]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'watchdog/master'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 6 May 2014 03:30:50 +0000 (13:30 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 6 May 2014 03:30:50 +0000 (13:30 +1000)
2350 files changed:
.gitignore
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-driver-hid-thingm [deleted file]
Documentation/DocBook/80211.tmpl
Documentation/DocBook/drm.tmpl
Documentation/arm/Marvell/README
Documentation/arm/memory.txt
Documentation/cpu-freq/cpu-drivers.txt
Documentation/cpu-freq/index.txt
Documentation/devicetree/bindings/arm/arch_timer.txt
Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
Documentation/devicetree/bindings/arm/armada-cpu-reset.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/coherency-fabric.txt
Documentation/devicetree/bindings/arm/cpus.txt
Documentation/devicetree/bindings/arm/marvell,berlin.txt
Documentation/devicetree/bindings/arm/pmu.txt
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/ata/apm-xgene.txt
Documentation/devicetree/bindings/clock/at91-clock.txt
Documentation/devicetree/bindings/clock/imx25-clock.txt
Documentation/devicetree/bindings/clock/imx27-clock.txt
Documentation/devicetree/bindings/clock/imx6q-clock.txt
Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/mmp-dma.txt
Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
Documentation/devicetree/bindings/input/st-keyscan.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt
Documentation/devicetree/bindings/mfd/mc13xxx.txt
Documentation/devicetree/bindings/mfd/s2mps11.txt
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
Documentation/devicetree/bindings/mtd/fsl-quadspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/arc_emac.txt
Documentation/devicetree/bindings/net/broadcom-systemport.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/socfpga-dwmac.txt
Documentation/devicetree/bindings/net/stmmac.txt
Documentation/devicetree/bindings/net/via-rhine.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
Documentation/devicetree/bindings/powerpc/4xx/akebono.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/hsta.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/tps65090.txt
Documentation/devicetree/bindings/sound/ak4104.txt
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
Documentation/devicetree/bindings/sound/fsl-sai.txt
Documentation/devicetree/bindings/sound/max98095.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nokia,rx51.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5640.txt
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/snow.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/st,sta350.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/driver-model/devres.txt
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
Documentation/hwmon/lm77
Documentation/kernel-parameters.txt
Documentation/lto-build [new file with mode: 0644]
Documentation/mtd/spi-nor.txt [new file with mode: 0644]
Documentation/networking/bonding.txt
Documentation/networking/filter.txt
Documentation/networking/scaling.txt
Documentation/s390/zfcpdump.txt
MAINTAINERS
Makefile
arch/arc/include/asm/irq.h
arch/arc/include/asm/processor.h
arch/arc/kernel/entry.S
arch/arc/kernel/irq.c
arch/arc/kernel/process.c
arch/arc/mm/cache_arc700.c
arch/arc/plat-arcfpga/Makefile
arch/arc/plat-arcfpga/platform.c
arch/arc/plat-arcfpga/smp.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/arm-soc-for-next-contents.txt [new file with mode: 0644]
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am3517.dtsi
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am437x-gp-evm.dts
arch/arm/boot/dts/armada-370-db.dts
arch/arm/boot/dts/armada-370-mirabox.dts
arch/arm/boot/dts/armada-370-netgear-rn102.dts
arch/arm/boot/dts/armada-370-netgear-rn104.dts
arch/arm/boot/dts/armada-370-rd.dts
arch/arm/boot/dts/armada-370-xp.dtsi
arch/arm/boot/dts/armada-370.dtsi
arch/arm/boot/dts/armada-375-db.dts
arch/arm/boot/dts/armada-375.dtsi
arch/arm/boot/dts/armada-380.dtsi
arch/arm/boot/dts/armada-385-db.dts
arch/arm/boot/dts/armada-385-rd.dts
arch/arm/boot/dts/armada-385.dtsi
arch/arm/boot/dts/armada-38x.dtsi
arch/arm/boot/dts/armada-xp-axpwifiap.dts
arch/arm/boot/dts/armada-xp-db.dts
arch/arm/boot/dts/armada-xp-gp.dts
arch/arm/boot/dts/armada-xp-matrix.dts
arch/arm/boot/dts/armada-xp-mv78230.dtsi
arch/arm/boot/dts/armada-xp-mv78260.dtsi
arch/arm/boot/dts/armada-xp-mv78460.dtsi
arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
arch/arm/boot/dts/armada-xp.dtsi
arch/arm/boot/dts/at91-sama5d3_xplained.dts
arch/arm/boot/dts/at91sam9261.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9rl.dtsi
arch/arm/boot/dts/at91sam9rlek.dts
arch/arm/boot/dts/berlin2.dtsi
arch/arm/boot/dts/berlin2cd.dtsi
arch/arm/boot/dts/berlin2q-marvell-dmp.dts [new file with mode: 0644]
arch/arm/boot/dts/berlin2q.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts
arch/arm/boot/dts/imx25-pdk.dts
arch/arm/boot/dts/imx25.dtsi
arch/arm/boot/dts/imx27-pdk.dts
arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts
arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx28-duckbill.dts
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts
arch/arm/boot/dts/imx35-pdk.dts [new file with mode: 0644]
arch/arm/boot/dts/imx35.dtsi
arch/arm/boot/dts/imx50.dtsi
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx51-digi-connectcore-jsk.dts [new file with mode: 0644]
arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53-qsb-common.dtsi
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6dl-phytec-pbab01.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6q-gk802.dts
arch/arm/boot/dts/imx6q-gw5400-a.dts
arch/arm/boot/dts/imx6q-phytec-pbab01.dts
arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi
arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6qdl-wandboard.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6sl.dtsi
arch/arm/boot/dts/kirkwood-6192.dtsi
arch/arm/boot/dts/kirkwood-6281.dtsi
arch/arm/boot/dts/kirkwood-6282.dtsi
arch/arm/boot/dts/kirkwood-98dx4122.dtsi
arch/arm/boot/dts/kirkwood-b3.dts
arch/arm/boot/dts/kirkwood-cloudbox.dts
arch/arm/boot/dts/kirkwood-db.dtsi
arch/arm/boot/dts/kirkwood-dns320.dts
arch/arm/boot/dts/kirkwood-dns325.dts
arch/arm/boot/dts/kirkwood-dnskw.dtsi
arch/arm/boot/dts/kirkwood-dockstar.dts
arch/arm/boot/dts/kirkwood-dreamplug.dts
arch/arm/boot/dts/kirkwood-ds109.dts
arch/arm/boot/dts/kirkwood-ds110jv10.dts
arch/arm/boot/dts/kirkwood-ds111.dts
arch/arm/boot/dts/kirkwood-ds112.dts
arch/arm/boot/dts/kirkwood-ds209.dts
arch/arm/boot/dts/kirkwood-ds210.dts
arch/arm/boot/dts/kirkwood-ds212.dts
arch/arm/boot/dts/kirkwood-ds212j.dts
arch/arm/boot/dts/kirkwood-ds409.dts
arch/arm/boot/dts/kirkwood-ds409slim.dts
arch/arm/boot/dts/kirkwood-ds411.dts
arch/arm/boot/dts/kirkwood-ds411j.dts
arch/arm/boot/dts/kirkwood-ds411slim.dts
arch/arm/boot/dts/kirkwood-goflexnet.dts
arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts
arch/arm/boot/dts/kirkwood-ib62x0.dts
arch/arm/boot/dts/kirkwood-iconnect.dts
arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
arch/arm/boot/dts/kirkwood-km_kirkwood.dts
arch/arm/boot/dts/kirkwood-laplug.dts
arch/arm/boot/dts/kirkwood-lsxl.dtsi
arch/arm/boot/dts/kirkwood-mplcec4.dts
arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
arch/arm/boot/dts/kirkwood-netgear_readynas_duo_v2.dts
arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts
arch/arm/boot/dts/kirkwood-ns2-common.dtsi
arch/arm/boot/dts/kirkwood-nsa310.dts
arch/arm/boot/dts/kirkwood-nsa310a.dts
arch/arm/boot/dts/kirkwood-nsa320.dts [new file with mode: 0644]
arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi [moved from arch/arm/boot/dts/kirkwood-nsa310-common.dtsi with 58% similarity]
arch/arm/boot/dts/kirkwood-openblocks_a6.dts
arch/arm/boot/dts/kirkwood-openblocks_a7.dts
arch/arm/boot/dts/kirkwood-rd88f6192.dts
arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
arch/arm/boot/dts/kirkwood-rs212.dts
arch/arm/boot/dts/kirkwood-rs409.dts
arch/arm/boot/dts/kirkwood-rs411.dts
arch/arm/boot/dts/kirkwood-sheevaplug-common.dtsi
arch/arm/boot/dts/kirkwood-synology.dtsi
arch/arm/boot/dts/kirkwood-t5325.dts
arch/arm/boot/dts/kirkwood-topkick.dts
arch/arm/boot/dts/kirkwood-ts219-6281.dts
arch/arm/boot/dts/kirkwood-ts219-6282.dts
arch/arm/boot/dts/kirkwood-ts219.dtsi
arch/arm/boot/dts/kirkwood-ts419.dtsi
arch/arm/boot/dts/kirkwood.dtsi
arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
arch/arm/boot/dts/omap2.dtsi
arch/arm/boot/dts/omap2420.dtsi
arch/arm/boot/dts/omap2430.dtsi
arch/arm/boot/dts/omap3-cm-t3x30.dtsi
arch/arm/boot/dts/omap3-igep.dtsi
arch/arm/boot/dts/omap3-igep0020.dts
arch/arm/boot/dts/omap3-sb-t35.dtsi
arch/arm/boot/dts/omap3-sbc-t3517.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/orion5x-lacie-d2-network.dts [new file with mode: 0644]
arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts
arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts [new file with mode: 0644]
arch/arm/boot/dts/orion5x-mv88f5182.dtsi [new file with mode: 0644]
arch/arm/boot/dts/orion5x-rd88f5182-nas.dts [new file with mode: 0644]
arch/arm/boot/dts/orion5x.dtsi
arch/arm/boot/dts/r8a7740-armadillo800eva-reference.dts
arch/arm/boot/dts/r8a7740.dtsi
arch/arm/boot/dts/r8a7778-bockw-reference.dts
arch/arm/boot/dts/r8a7778.dtsi
arch/arm/boot/dts/r8a7779.dtsi
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/r8a7790.dtsi
arch/arm/boot/dts/r8a7791-henninger.dts [new file with mode: 0644]
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/boot/dts/r8a7791.dtsi
arch/arm/boot/dts/s3c2416-smdk2416.dts
arch/arm/boot/dts/s3c2416.dtsi
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sama5d3_mci2.dtsi
arch/arm/boot/dts/sama5d3_tcb1.dtsi
arch/arm/boot/dts/sama5d3_uart.dtsi
arch/arm/boot/dts/sama5d3xmb.dtsi
arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
arch/arm/boot/dts/stih415-pinctrl.dtsi
arch/arm/boot/dts/stih416-pinctrl.dtsi
arch/arm/boot/dts/tegra114-dalmore.dts
arch/arm/boot/dts/tegra114-tn7.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra124-jetson-tk1.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra124-venice2.dts
arch/arm/boot/dts/tegra124.dtsi
arch/arm/boot/dts/tegra20-harmony.dts
arch/arm/boot/dts/tegra30-beaver.dts
arch/arm/boot/dts/vf610-colibri.dts [new file with mode: 0644]
arch/arm/boot/dts/vf610-twr.dts
arch/arm/boot/dts/vf610.dtsi
arch/arm/boot/dts/vt8500.dtsi
arch/arm/boot/dts/wm8650.dtsi
arch/arm/boot/dts/wm8850.dtsi
arch/arm/common/edma.c
arch/arm/configs/dove_defconfig
arch/arm/configs/imx_v4_v5_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/kirkwood_defconfig
arch/arm/configs/multi_v5_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/mvebu_v5_defconfig
arch/arm/configs/mvebu_v7_defconfig
arch/arm/configs/mxs_defconfig
arch/arm/configs/realview-smp_defconfig
arch/arm/configs/realview_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/configs/versatile_defconfig
arch/arm/include/asm/assembler.h
arch/arm/include/asm/fixmap.h
arch/arm/include/asm/highmem.h
arch/arm/include/asm/memory.h
arch/arm/include/debug/vf.S
arch/arm/kernel/Makefile
arch/arm/kernel/entry-armv.S
arch/arm/kernel/ftrace.c
arch/arm/kernel/hibernate.c [new file with mode: 0644]
arch/arm/kernel/iwmmxt.S
arch/arm/kernel/perf_event_cpu.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/sleep.S
arch/arm/kernel/topology.c
arch/arm/kvm/Kconfig
arch/arm/kvm/mmu.c
arch/arm/mach-bcm/Kconfig
arch/arm/mach-berlin/Kconfig
arch/arm/mach-davinci/da850.c
arch/arm/mach-dove/irq.c
arch/arm/mach-ep93xx/crunch-bits.S
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/clk-gate2.c
arch/arm/mach-imx/clk-imx25.c
arch/arm/mach-imx/clk-imx27.c
arch/arm/mach-imx/clk-imx31.c
arch/arm/mach-imx/clk-imx51-imx53.c
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/clk-imx6sl.c
arch/arm/mach-imx/clk.h
arch/arm/mach-imx/common.h
arch/arm/mach-imx/devices/platform-mx2-emma.c
arch/arm/mach-imx/mach-mx21ads.c
arch/arm/mach-imx/mach-mx51_babbage.c [deleted file]
arch/arm/mach-imx/time.c
arch/arm/mach-kirkwood/board-dt.c
arch/arm/mach-kirkwood/irq.c
arch/arm/mach-mvebu/Kconfig
arch/arm/mach-mvebu/Makefile
arch/arm/mach-mvebu/armada-370-xp.h
arch/arm/mach-mvebu/board-t5325.c [deleted file]
arch/arm/mach-mvebu/board-v7.c
arch/arm/mach-mvebu/board.h
arch/arm/mach-mvebu/coherency.c
arch/arm/mach-mvebu/coherency.h
arch/arm/mach-mvebu/coherency_ll.S
arch/arm/mach-mvebu/common.h
arch/arm/mach-mvebu/cpu-reset.c [new file with mode: 0644]
arch/arm/mach-mvebu/dove.c
arch/arm/mach-mvebu/headsmp-a9.S [new file with mode: 0644]
arch/arm/mach-mvebu/headsmp.S
arch/arm/mach-mvebu/kirkwood.c
arch/arm/mach-mvebu/mvebu-soc-id.c
arch/arm/mach-mvebu/mvebu-soc-id.h
arch/arm/mach-mvebu/platsmp-a9.c [new file with mode: 0644]
arch/arm/mach-mvebu/platsmp.c
arch/arm/mach-mvebu/pmsu.c
arch/arm/mach-mvebu/system-controller.c
arch/arm/mach-omap2/omap-headsmp.S
arch/arm/mach-omap2/omap_twl.c
arch/arm/mach-orion5x/Kconfig
arch/arm/mach-orion5x/Makefile
arch/arm/mach-orion5x/board-d2net.c [new file with mode: 0644]
arch/arm/mach-orion5x/board-dt.c
arch/arm/mach-orion5x/board-mss2.c [new file with mode: 0644]
arch/arm/mach-orion5x/board-rd88f5182.c [new file with mode: 0644]
arch/arm/mach-orion5x/common.h
arch/arm/mach-orion5x/d2net-setup.c [deleted file]
arch/arm/mach-orion5x/edmini_v2-setup.c [deleted file]
arch/arm/mach-orion5x/irq.c
arch/arm/mach-orion5x/mss2-setup.c [deleted file]
arch/arm/mach-qcom/Kconfig
arch/arm/mach-realview/core.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pba8.c
arch/arm/mach-realview/realview_pbx.c
arch/arm/mach-s3c24xx/Kconfig
arch/arm/mach-s3c24xx/Makefile
arch/arm/mach-s3c24xx/clock-s3c2412.c [deleted file]
arch/arm/mach-s3c24xx/clock-s3c2416.c [deleted file]
arch/arm/mach-s3c24xx/clock-s3c2443.c [deleted file]
arch/arm/mach-s3c24xx/common-s3c2443.c [deleted file]
arch/arm/mach-s3c24xx/common.c
arch/arm/mach-s3c24xx/common.h
arch/arm/mach-s3c24xx/mach-jive.c
arch/arm/mach-s3c24xx/mach-s3c2416-dt.c
arch/arm/mach-s3c24xx/mach-smdk2413.c
arch/arm/mach-s3c24xx/mach-smdk2416.c
arch/arm/mach-s3c24xx/mach-smdk2443.c
arch/arm/mach-s3c24xx/mach-vstms.c
arch/arm/mach-s3c24xx/pm.c
arch/arm/mach-s3c24xx/s3c2412.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-bockw.c
arch/arm/mach-shmobile/board-koelsch-reference.c
arch/arm/mach-shmobile/board-koelsch.c
arch/arm/mach-shmobile/board-lager-reference.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-shmobile/clock-emev2.c [deleted file]
arch/arm/mach-shmobile/clock-r8a7778.c
arch/arm/mach-shmobile/clock-r8a7790.c
arch/arm/mach-shmobile/clock-r8a7791.c
arch/arm/mach-shmobile/clock.c
arch/arm/mach-shmobile/include/mach/clock.h
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/emev2.h [deleted file]
arch/arm/mach-shmobile/pm-rmobile.c
arch/arm/mach-shmobile/setup-emev2.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-r8a7790.c
arch/arm/mach-shmobile/setup-r8a7791.c
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/smp-emev2.c
arch/arm/mach-shmobile/smp-r8a7791.c
arch/arm/mach-shmobile/timer.c
arch/arm/mach-versatile/core.c
arch/arm/mm/highmem.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-3level.S
arch/arm/mm/proc-v7.S
arch/arm/plat-orion/gpio.c
arch/arm/plat-orion/include/plat/irq.h
arch/arm/plat-orion/include/plat/orion-gpio.h
arch/arm/plat-orion/irq.c
arch/arm/plat-versatile/Kconfig
arch/arm/plat-versatile/Makefile
arch/arm/vfp/entry.S
arch/arm64/boot/dts/apm-storm.dtsi
arch/arm64/kernel/early_printk.c
arch/arm64/kernel/setup.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/mmu.c
arch/hexagon/include/asm/barrier.h [deleted file]
arch/m68k/kernel/setup_no.c
arch/m68k/platform/68000/m68EZ328.c
arch/m68k/platform/68000/m68VZ328.c
arch/mips/Kbuild
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/dec/ecc-berr.c
arch/mips/dec/kn02xa-berr.c
arch/mips/dec/prom/Makefile
arch/mips/dec/prom/call_o32.S [deleted file]
arch/mips/fw/lib/call_o32.S
arch/mips/fw/sni/sniprom.c
arch/mips/include/asm/branch.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/dec/prom.h
arch/mips/include/asm/fpu.h
arch/mips/include/asm/fpu_emulator.h
arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h
arch/mips/include/asm/mach-jz4740/dma.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/rm9k-ocd.h [deleted file]
arch/mips/include/uapi/asm/Kbuild
arch/mips/include/uapi/asm/bitfield.h [new file with mode: 0644]
arch/mips/include/uapi/asm/inst.h
arch/mips/jz4740/board-qi_lb60.c
arch/mips/kernel/branch.c
arch/mips/kernel/proc.c
arch/mips/kernel/unaligned.c
arch/mips/lib/csum_partial.S
arch/mips/lib/delay.c
arch/mips/lib/strncpy_user.S
arch/mips/loongson/Kconfig
arch/mips/loongson/lemote-2f/clock.c
arch/mips/loongson1/Kconfig
arch/mips/math-emu/Makefile
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/dp_add.c
arch/mips/math-emu/dp_cmp.c
arch/mips/math-emu/dp_div.c
arch/mips/math-emu/dp_fint.c
arch/mips/math-emu/dp_flong.c
arch/mips/math-emu/dp_frexp.c [deleted file]
arch/mips/math-emu/dp_fsp.c
arch/mips/math-emu/dp_logb.c [deleted file]
arch/mips/math-emu/dp_modf.c [deleted file]
arch/mips/math-emu/dp_mul.c
arch/mips/math-emu/dp_scalb.c [deleted file]
arch/mips/math-emu/dp_simple.c
arch/mips/math-emu/dp_sqrt.c
arch/mips/math-emu/dp_sub.c
arch/mips/math-emu/dp_tint.c
arch/mips/math-emu/dp_tlong.c
arch/mips/math-emu/dsemul.c
arch/mips/math-emu/ieee754.c
arch/mips/math-emu/ieee754.h
arch/mips/math-emu/ieee754d.c
arch/mips/math-emu/ieee754dp.c
arch/mips/math-emu/ieee754dp.h
arch/mips/math-emu/ieee754int.h
arch/mips/math-emu/ieee754m.c [deleted file]
arch/mips/math-emu/ieee754sp.c
arch/mips/math-emu/ieee754sp.h
arch/mips/math-emu/ieee754xcpt.c [deleted file]
arch/mips/math-emu/kernel_linkage.c [deleted file]
arch/mips/math-emu/me-debugfs.c [new file with mode: 0644]
arch/mips/math-emu/me-micromips.c [new file with mode: 0644]
arch/mips/math-emu/sp_add.c
arch/mips/math-emu/sp_cmp.c
arch/mips/math-emu/sp_div.c
arch/mips/math-emu/sp_fdp.c
arch/mips/math-emu/sp_fint.c
arch/mips/math-emu/sp_flong.c
arch/mips/math-emu/sp_frexp.c [deleted file]
arch/mips/math-emu/sp_logb.c [deleted file]
arch/mips/math-emu/sp_modf.c [deleted file]
arch/mips/math-emu/sp_mul.c
arch/mips/math-emu/sp_scalb.c [deleted file]
arch/mips/math-emu/sp_simple.c
arch/mips/math-emu/sp_sqrt.c
arch/mips/math-emu/sp_sub.c
arch/mips/math-emu/sp_tint.c
arch/mips/math-emu/sp_tlong.c
arch/parisc/include/uapi/asm/Kbuild
arch/parisc/include/uapi/asm/resource.h [deleted file]
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/addnote.c
arch/powerpc/boot/crt0.S
arch/powerpc/boot/dcr.h
arch/powerpc/boot/dts/akebono.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8308_p1m.dts
arch/powerpc/boot/dts/mpc8308rdb.dts
arch/powerpc/boot/elf_util.c
arch/powerpc/boot/main.c
arch/powerpc/boot/of.c
arch/powerpc/boot/of.h
arch/powerpc/boot/ofconsole.c
arch/powerpc/boot/oflib.c
arch/powerpc/boot/ops.h
arch/powerpc/boot/ppc_asm.h
arch/powerpc/boot/ps3.c
arch/powerpc/boot/pseries-head.S [new file with mode: 0644]
arch/powerpc/boot/stdio.c
arch/powerpc/boot/swab.h [new file with mode: 0644]
arch/powerpc/boot/treeboot-akebono.c [new file with mode: 0644]
arch/powerpc/boot/util.S
arch/powerpc/boot/wrapper
arch/powerpc/boot/zImage.lds.S
arch/powerpc/configs/44x/akebono_defconfig [new file with mode: 0644]
arch/powerpc/include/asm/code-patching.h
arch/powerpc/include/asm/context_tracking.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/exception-64e.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/ftrace.h
arch/powerpc/include/asm/irqflags.h
arch/powerpc/include/asm/kprobes.h
arch/powerpc/include/asm/linkage.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/module.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/sections.h
arch/powerpc/include/asm/string.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/uapi/asm/elf.h
arch/powerpc/include/uapi/asm/setup.h
arch/powerpc/kernel/cpu_setup_fsl_booke.S
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64e.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/fadump.c
arch/powerpc/kernel/ftrace.c
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/idle_book3e.S
arch/powerpc/kernel/idle_power4.S
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_init_check.sh
arch/powerpc/kernel/rtas_flash.c
arch/powerpc/kernel/rtas_pci.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/systbl.S
arch/powerpc/kernel/tm.S
arch/powerpc/kvm/book3s_hv_interrupts.S
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/lib/Makefile
arch/powerpc/lib/copypage_64.S
arch/powerpc/lib/copypage_power7.S
arch/powerpc/lib/copyuser_64.S
arch/powerpc/lib/copyuser_power7.S
arch/powerpc/lib/hweight_64.S
arch/powerpc/lib/mem_64.S
arch/powerpc/lib/memcpy_64.S
arch/powerpc/lib/memcpy_power7.S
arch/powerpc/mm/hash_low_64.S
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/slb_low.S
arch/powerpc/perf/hv-24x7.c
arch/powerpc/perf/hv-gpci.c
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/Makefile
arch/powerpc/platforms/44x/ppc476.c [moved from arch/powerpc/platforms/44x/currituck.c with 72% similarity]
arch/powerpc/platforms/44x/ppc476_modules.lds [new file with mode: 0644]
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/smp.c
arch/powerpc/platforms/embedded6xx/Kconfig
arch/powerpc/platforms/pasemi/powersave.S
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/opal-dump.c
arch/powerpc/platforms/powernv/opal-elog.c
arch/powerpc/platforms/powernv/opal-flash.c
arch/powerpc/platforms/powernv/opal-sysparam.c
arch/powerpc/platforms/powernv/opal-takeover.S
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/opal.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/pseries/eeh_pseries.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/hvCall.S
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/platforms/wsp/scom_smp.c
arch/powerpc/sysdev/Kconfig
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/ppc4xx_hsta_msi.c [new file with mode: 0644]
arch/powerpc/sysdev/ppc4xx_pci.c
arch/s390/Kconfig
arch/s390/appldata/appldata_mem.c
arch/s390/include/asm/ccwgroup.h
arch/s390/include/asm/futex.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/pci_clp.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/smp.h
arch/s390/include/asm/spinlock.h
arch/s390/include/asm/spinlock_types.h
arch/s390/include/asm/switch_to.h
arch/s390/include/asm/syscall.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/crash_dump.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/head31.S
arch/s390/kernel/nmi.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/topology.c
arch/s390/kvm/kvm-s390.c
arch/s390/lib/spinlock.c
arch/s390/lib/uaccess.c
arch/s390/mm/fault.c
arch/s390/mm/mem_detect.c
arch/s390/mm/page-states.c
arch/s390/mm/pgtable.c
arch/s390/mm/vmem.c
arch/s390/net/bpf_jit_comp.c
arch/s390/pci/pci.c
arch/s390/pci/pci_clp.c
arch/s390/pci/pci_event.c
arch/s390/pci/pci_sysfs.c
arch/sparc/include/asm/auxio.h
arch/sparc/include/asm/auxio_64.h
arch/sparc/include/asm/bug.h
arch/sparc/include/asm/checksum_32.h
arch/sparc/include/asm/checksum_64.h
arch/sparc/include/asm/cpudata.h
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/floppy_32.h
arch/sparc/include/asm/io_32.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/irq_32.h
arch/sparc/include/asm/page.h
arch/sparc/include/asm/pgalloc_32.h
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/setup.h
arch/sparc/include/asm/timer_32.h
arch/sparc/kernel/auxio_32.c
arch/sparc/kernel/cpu.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.h
arch/sparc/kernel/irq_32.c
arch/sparc/kernel/kernel.h
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/leon_pci.c
arch/sparc/kernel/leon_pci_grpci1.c
arch/sparc/kernel/leon_pci_grpci2.c
arch/sparc/kernel/leon_pmc.c
arch/sparc/kernel/leon_smp.c
arch/sparc/kernel/nmi.c
arch/sparc/kernel/of_device_common.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/process_32.c
arch/sparc/kernel/ptrace_32.c
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/signal_32.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sys32.S
arch/sparc/kernel/tadpole.c
arch/sparc/kernel/time_32.c
arch/sparc/kernel/traps_32.c
arch/sparc/kernel/unaligned_32.c
arch/sparc/kernel/windows.c
arch/sparc/lib/Makefile
arch/sparc/mm/fault_32.c
arch/sparc/mm/init_32.c
arch/sparc/mm/iommu.c
arch/sparc/mm/leon_mm.c
arch/sparc/mm/mm_32.h [new file with mode: 0644]
arch/sparc/mm/srmmu.c
arch/sparc/mm/srmmu.h [deleted file]
arch/tile/kernel/setup.c
arch/um/include/shared/os.h
arch/um/include/shared/skas/proc_mm.h [deleted file]
arch/um/include/shared/skas/skas.h
arch/um/include/shared/skas_ptrace.h [deleted file]
arch/um/kernel/ptrace.c
arch/um/kernel/reboot.c
arch/um/kernel/skas/mmu.c
arch/um/kernel/skas/process.c
arch/um/kernel/trap.c
arch/um/kernel/um_arch.c
arch/um/os-Linux/process.c
arch/um/os-Linux/skas/mem.c
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/start_up.c
arch/um/sys-ia64/sysdep/skas_ptrace.h [deleted file]
arch/um/sys-ppc/shared/sysdep/skas_ptrace.h [deleted file]
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/crypto/ghash-clmulni-intel_asm.S
arch/x86/crypto/ghash-clmulni-intel_glue.c
arch/x86/include/asm/checksum_64.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/perf_event_intel_rapl.c
arch/x86/kernel/vsmp_64.c
arch/x86/kvm/vmx.c
arch/x86/um/ldt.c
arch/x86/um/shared/sysdep/faultinfo_32.h
arch/x86/um/shared/sysdep/faultinfo_64.h
arch/x86/um/shared/sysdep/skas_ptrace.h [deleted file]
arch/xtensa/Kconfig
arch/xtensa/boot/dts/kc705.dts [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi
arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi
arch/xtensa/boot/dts/xtfpga.dtsi
arch/xtensa/include/asm/bootparam.h
arch/xtensa/include/asm/fixmap.h [new file with mode: 0644]
arch/xtensa/include/asm/highmem.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/sysmem.h [new file with mode: 0644]
arch/xtensa/include/asm/tlbflush.h
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/smp.c
arch/xtensa/kernel/xtensa_ksyms.c
arch/xtensa/mm/Makefile
arch/xtensa/mm/cache.c
arch/xtensa/mm/highmem.c [new file with mode: 0644]
arch/xtensa/mm/init.c
arch/xtensa/mm/mmu.c
arch/xtensa/mm/tlb.c
arch/xtensa/platforms/iss/Makefile
arch/xtensa/platforms/xt2000/setup.c
block/blk-core.c
block/blk-flush.c
block/blk-iopoll.c
block/blk-map.c
block/blk-mq-cpumap.c
block/blk-mq-sysfs.c
block/blk-mq-tag.c
block/blk-mq-tag.h
block/blk-mq.c
block/blk-mq.h
block/blk-throttle.c
block/blk-timeout.c
block/blk.h
block/bsg.c
block/cfq-iosched.c
crypto/crypto_user.c
crypto/tcrypt.c
crypto/testmgr.h
drivers/acpi/acpi_pad.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acapps.h [new file with mode: 0644]
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evsci.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/tbdata.c [new file with mode: 0644]
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/tbxfload.c
drivers/acpi/acpica/utdecode.c
drivers/acpi/acpica/utstring.c
drivers/acpi/ec.c
drivers/acpi/osl.c
drivers/acpi/scan.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_imx.c
drivers/ata/ahci_mvebu.c [new file with mode: 0644]
drivers/ata/libahci.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/pata_octeon_cf.c
drivers/base/dd.c
drivers/base/platform.c
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_nla.c
drivers/block/drbd/drbd_proc.c
drivers/block/drbd/drbd_protocol.h
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h
drivers/block/drbd/drbd_state.c
drivers/block/drbd/drbd_worker.c
drivers/block/drbd/drbd_wrappers.h [deleted file]
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/mg_disk.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/null_blk.c
drivers/block/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/skd_main.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/block/virtio_blk.c
drivers/block/xen-blkfront.c
drivers/block/xsysace.c
drivers/block/z2ram.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btmrvl_drv.h
drivers/bluetooth/btmrvl_main.c
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btmrvl_sdio.h
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_h4.c
drivers/bus/mvebu-mbus.c
drivers/cdrom/cdrom.c
drivers/cdrom/gdrom.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/picoxcell-rng.c [deleted file]
drivers/char/random.c
drivers/char/raw.c
drivers/clk/mvebu/Kconfig
drivers/clk/mvebu/Makefile
drivers/clk/mvebu/orion.c [new file with mode: 0644]
drivers/clk/samsung/Makefile
drivers/clk/samsung/clk-pll.c
drivers/clk/samsung/clk-pll.h
drivers/clk/samsung/clk-s3c2412.c [new file with mode: 0644]
drivers/clk/samsung/clk-s3c2443.c [new file with mode: 0644]
drivers/clk/ti/clk-43xx.c
drivers/clk/versatile/clk-vexpress-osc.c
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/zevio-timer.c
drivers/connector/cn_proc.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/arm_big_little.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/dbx500-cpufreq.c
drivers/cpufreq/elanfreq.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/exynos-cpufreq.h
drivers/cpufreq/exynos5440-cpufreq.c
drivers/cpufreq/freq_table.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpufreq/pasemi-cpufreq.c
drivers/cpufreq/powernow-k6.c
drivers/cpufreq/powernow-k7.c
drivers/cpufreq/ppc-corenet-cpufreq.c
drivers/cpufreq/ppc_cbe_cpufreq.c
drivers/cpufreq/s3c2416-cpufreq.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/cpufreq/speedstep-centrino.c
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-armada-370-xp.c [new file with mode: 0644]
drivers/crypto/atmel-aes.c
drivers/crypto/bfin_crc.c
drivers/crypto/bfin_crc.h [new file with mode: 0644]
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/error.c
drivers/crypto/ccp/ccp-pci.c
drivers/crypto/nx/nx-842.c
drivers/crypto/omap-des.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/dmaengine.c
drivers/dma/edma.c
drivers/dma/fsldma.c
drivers/dma/ioat/dca.c
drivers/dma/ioat/dma.c
drivers/dma/ioat/dma_v3.c
drivers/dma/mmp_pdma.c
drivers/dma/mpc512x_dma.c
drivers/dma/mv_xor.c
drivers/dma/sh/shdma-base.c
drivers/dma/xilinx/Makefile [new file with mode: 0644]
drivers/dma/xilinx/xilinx_vdma.c [new file with mode: 0644]
drivers/extcon/Kconfig
drivers/extcon/extcon-max14577.c
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/ast/ast_drv.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/cirrus/cirrus_main.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_platform.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_usb.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_ns2501.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/i915_cmd_parser.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_context.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_gtt.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.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_dsi.c
drivers/gpu/drm/i915/intel_dsi.h
drivers/gpu/drm/i915/intel_dsi_cmd.c
drivers/gpu/drm/i915/intel_dsi_cmd.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.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_sideband.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/mga/mga_state.c
drivers/gpu/drm/mgag200/mgag200_main.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/nouveau/nouveau_vga.c
drivers/gpu/drm/panel/panel-ld9040.c
drivers/gpu/drm/panel/panel-s6e8aa0.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_drv.c
drivers/gpu/drm/qxl/qxl_irq.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/r128/r128_state.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/shmobile/shmob_drm_drv.c
drivers/gpu/drm/tegra/bus.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/dsi.h
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/hdmi.h
drivers/gpu/drm/tegra/rgb.c
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/tegra/sor.h
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/via/via_mm.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-input.c
drivers/hid/hid-rmi.c [new file with mode: 0644]
drivers/hid/hid-sony.c
drivers/hid/hid-thingm.c
drivers/hwmon/coretemp.c
drivers/hwmon/f71805f.c
drivers/hwmon/ibmpex.c
drivers/hwmon/lm70.c
drivers/hwmon/lm75.c
drivers/hwmon/lm77.c
drivers/hwmon/lm92.c
drivers/hwmon/lm93.c
drivers/hwmon/max1111.c
drivers/hwmon/max197.c
drivers/hwmon/pc87427.c
drivers/hwmon/s3c-hwmon.c
drivers/hwmon/tmp102.c
drivers/hwmon/tmp421.c
drivers/hwmon/vt1211.c
drivers/ide/Kconfig
drivers/ide/ide-disk.c
drivers/ide/ide-probe.c
drivers/iio/adc/Kconfig
drivers/iio/adc/exynos_adc.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/infiniband/hw/cxgb4/Kconfig
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
drivers/input/evdev.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/st-keyscan.c [new file with mode: 0644]
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/bma150.c
drivers/input/misc/gpio-beeper.c
drivers/input/misc/twl6040-vibra.c
drivers/input/mouse/synaptics.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/tsc2005.c
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-crossbar.c
drivers/irqchip/irq-orion.c
drivers/isdn/hisax/icc.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-versatile.c [moved from arch/arm/plat-versatile/leds.c with 68% similarity]
drivers/md/dm-cache-target.c
drivers/md/dm-thin.c
drivers/md/dm-verity.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/i2c/s5c73m3/s5c73m3-core.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos4-is/fimc-core.c
drivers/media/usb/dvb-usb-v2/Makefile
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/gspca/sonixb.c
drivers/memory/mvebu-devbus.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/arizona-core.c
drivers/mfd/bcm590xx.c
drivers/mfd/cros_ec.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/ipaq-micro.c [new file with mode: 0644]
drivers/mfd/kempld-core.c
drivers/mfd/lpc_ich.c
drivers/mfd/max14577.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/rtsx_usb.c
drivers/mfd/sec-core.c
drivers/mfd/sec-irq.c
drivers/mfd/tps65090.c
drivers/mfd/twl-core.c
drivers/mfd/wm5110-tables.c
drivers/misc/genwqe/card_utils.c
drivers/mmc/core/core.c
drivers/mmc/core/debugfs.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/mmci.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/rtsx_usb_sdmmc.c [new file with mode: 0644]
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sh_mmcif.c
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/devices/Kconfig
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/serial_flash_cmds.h
drivers/mtd/devices/st_spi_fsm.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ecc.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/omap2.c
drivers/mtd/spi-nor/Kconfig [new file with mode: 0644]
drivers/mtd/spi-nor/Makefile [new file with mode: 0644]
drivers/mtd/spi-nor/fsl-quadspi.c [new file with mode: 0644]
drivers/mtd/spi-nor/spi-nor.c [new file with mode: 0644]
drivers/mtd/tests/oobtest.c
drivers/mtd/ubi/block.c
drivers/mtd/ubi/wl.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_alb.h
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bond_options.h
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/c_can/Kconfig
drivers/net/can/c_can/c_can.c
drivers/net/can/c_can/c_can.h
drivers/net/can/c_can/c_can_pci.c
drivers/net/can/c_can/c_can_platform.c
drivers/net/can/dev.c
drivers/net/can/sja1000/sja1000_isa.c
drivers/net/can/slcan.c
drivers/net/can/softing/softing_main.c
drivers/net/can/spi/Kconfig [new file with mode: 0644]
drivers/net/can/spi/Makefile [new file with mode: 0644]
drivers/net/can/spi/mcp251x.c [moved from drivers/net/can/mcp251x.c with 96% similarity]
drivers/net/can/usb/Kconfig
drivers/net/can/usb/kvaser_usb.c
drivers/net/dsa/mv88e6123_61_65.c
drivers/net/dsa/mv88e6131.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/ethernet/altera/Kconfig
drivers/net/ethernet/altera/altera_msgdma.c
drivers/net/ethernet/altera/altera_msgdma.h
drivers/net/ethernet/altera/altera_sgdma.c
drivers/net/ethernet/altera/altera_sgdma.h
drivers/net/ethernet/altera/altera_tse.h
drivers/net/ethernet/altera/altera_tse_ethtool.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/arc/emac.h
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/Makefile
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bcmsysport.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/bcmsysport.h [new file with mode: 0644]
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/cadence/Kconfig
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/chelsio/Kconfig
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.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_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/ethoc.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/intel/e1000e/e1000.h
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/e1000e/nvm.c
drivers/net/ethernet/intel/e1000e/param.c
drivers/net/ethernet/intel/e1000e/phy.c
drivers/net/ethernet/intel/e1000e/phy.h
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_adminq.h
drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/i40evf/i40e_adminq.c
drivers/net/ethernet/intel/i40evf/i40e_adminq.h
drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
drivers/net/ethernet/intel/i40evf/i40e_type.h
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/e1000_defines.h
drivers/net/ethernet/intel/igb/e1000_hw.h
drivers/net/ethernet/intel/igb/e1000_i210.c
drivers/net/ethernet/intel/igb/e1000_i210.h
drivers/net/ethernet/intel/igb/e1000_mac.c
drivers/net/ethernet/intel/igb/e1000_mac.h
drivers/net/ethernet/intel/igb/e1000_mbx.c
drivers/net/ethernet/intel/igb/e1000_mbx.h
drivers/net/ethernet/intel/igb/e1000_nvm.c
drivers/net/ethernet/intel/igb/e1000_nvm.h
drivers/net/ethernet/intel/igb/e1000_phy.c
drivers/net/ethernet/intel/igb/e1000_phy.h
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_hwmon.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/marvell/mvmdio.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/qlogic/Kconfig
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.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_main.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/ti/cpmac.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpts.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/via/Kconfig
drivers/net/ethernet/via/via-rhine.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/at86rf230.c
drivers/net/irda/sh_sir.c
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/phy/at803x.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/smsc.c
drivers/net/phy/vitesse.c
drivers/net/slip/slip.c
drivers/net/team/team.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ath10k/bmi.c
drivers/net/wireless/ath/ath10k/bmi.h
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.h
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/txrx.h
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath6kl/Kconfig
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/core.c
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/htc_mbox.c
drivers/net/wireless/ath/ath6kl/htc_pipe.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/usb.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h
drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9340_initvals.h
drivers/net/wireless/ath/ath9k/ar953x_initvals.h
drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug_sta.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/wil6210/interrupt.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/pcie_bus.c
drivers/net/wireless/ath/wil6210/rx_reorder.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/ath/wil6210/wmi.h
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/radio_2056.c
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/b43/wa.c
drivers/net/wireless/brcm80211/brcmfmac/chip.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/cw1200/sta.h
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sf.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11ac.c
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/README
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rsi/rsi_91x_mgmt.c
drivers/net/wireless/rsi/rsi_mgmt.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180/Makefile
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl818x.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723be/sw.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/sdio.c
drivers/net/wireless/ti/wlcore/spi.c
drivers/of/irq.c
drivers/of/platform.c
drivers/of/selftest.c
drivers/of/testcase-data/tests-interrupts.dtsi
drivers/pci/bus.c
drivers/pci/host-bridge.c
drivers/pci/host/pci-mvebu.c
drivers/pci/hotplug-pci.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpci_hotplug_pci.c
drivers/pci/hotplug/cpqphp_nvram.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pcihp_slot.c
drivers/pci/hotplug/rpaphp_core.c
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/hotplug/shpchp_pci.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/portdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/search.c
drivers/pci/setup-bus.c
drivers/pci/setup-irq.c
drivers/pci/setup-res.c
drivers/pinctrl/pinctrl-as3722.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-tb10x.c
drivers/pinctrl/sh-pfc/pfc-r8a7790.c
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pnp/pnpacpi/core.c
drivers/pnp/quirks.c
drivers/power/tps65090-charger.c
drivers/powercap/intel_rapl.c
drivers/ptp/ptp_clock.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/arizona-ldo1.c
drivers/regulator/arizona-micsupp.c
drivers/regulator/axp20x-regulator.c [new file with mode: 0644]
drivers/regulator/core.c
drivers/regulator/max14577.c
drivers/regulator/of_regulator.c
drivers/regulator/pbias-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/s5m8767.c
drivers/regulator/tps65090-regulator.c
drivers/regulator/tps65217-regulator.c
drivers/reset/Makefile
drivers/reset/reset-socfpga.c [new file with mode: 0644]
drivers/rtc/rtc-s5m.c
drivers/s390/char/Makefile
drivers/s390/char/zcore.c
drivers/s390/cio/chsc.c
drivers/s390/kvm/virtio_ccw.c
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_sys.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/sbus/char/jsflash.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_netlink.c
drivers/scsi/sd.c
drivers/scsi/virtio_scsi.c
drivers/sh/clk/core.c
drivers/staging/iio/resolver/ad2s1200.c
drivers/staging/lustre/lustre/include/lclient.h
drivers/staging/lustre/lustre/lclient/lcommon_cl.c
drivers/staging/lustre/lustre/llite/file.c
drivers/staging/lustre/lustre/llite/llite_internal.h
drivers/staging/lustre/lustre/llite/rw.c
drivers/staging/lustre/lustre/llite/rw26.c
drivers/staging/lustre/lustre/llite/vvp_io.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/media/sn9c102/sn9c102_devtable.h
drivers/staging/rtl8821ae/core.c
drivers/thermal/cpu_cooling.c
drivers/tty/hvc/hvc_console.c
drivers/tty/n_tty.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/tty_buffer.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/storage_common.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci.h
drivers/usb/phy/phy-fsm-usb.c
drivers/usb/serial/qcserial.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/unusual_devs.h
drivers/video/fbdev/Kconfig
drivers/video/fbdev/core/fbmon.c
drivers/video/fbdev/da8xx-fb.c
drivers/video/fbdev/gbefb.c
drivers/video/fbdev/mmp/Kconfig
drivers/video/fbdev/mmp/fb/mmpfb.c
drivers/video/fbdev/mmp/hw/Kconfig
drivers/video/fbdev/mmp/hw/mmp_ctrl.h
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/fbdev/wm8505fb.c
drivers/virtio/virtio_ring.c
fs/9p/vfs_addr.c
fs/9p/vfs_file.c
fs/adfs/file.c
fs/affs/file.c
fs/afs/file.c
fs/afs/flock.c
fs/afs/internal.h
fs/afs/write.c
fs/aio.c
fs/bfs/file.c
fs/bio-integrity.c
fs/bio.c
fs/block_dev.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/locks.c
fs/ceph/super.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/file.c
fs/cifs/inode.c
fs/direct-io.c
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/exofs/file.c
fs/exofs/inode.c
fs/ext2/file.c
fs/ext2/inode.c
fs/ext3/file.c
fs/ext3/inode.c
fs/ext4/ext4.h
fs/ext4/ext4_extents.h
fs/ext4/extents.c
fs/ext4/extents_status.c
fs/ext4/file.c
fs/ext4/indirect.c
fs/ext4/inode.c
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/super.c
fs/f2fs/acl.c
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/f2fs/xattr.c
fs/f2fs/xattr.h
fs/fat/file.c
fs/fat/inode.c
fs/file.c
fs/file_table.c
fs/fuse/control.c
fs/fuse/cuse.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/aops.c
fs/gfs2/file.c
fs/gfs2/lops.c
fs/gfs2/quota.c
fs/hfs/inode.c
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/jffs2/file.c
fs/jfs/file.c
fs/jfs/inode.c
fs/jfs/jfs_inode.c
fs/locks.c
fs/logfs/dev_mtd.c
fs/logfs/file.c
fs/logfs/super.c
fs/minix/file.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4file.c
fs/nfs/write.c
fs/nilfs2/file.c
fs/nilfs2/inode.c
fs/ntfs/file.c
fs/ocfs2/aops.c
fs/ocfs2/file.c
fs/omfs/file.c
fs/open.c
fs/pipe.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/read_write.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
fs/romfs/mmap-nommu.c
fs/splice.c
fs/sysv/file.c
fs/ubifs/file.c
fs/ubifs/super.c
fs/udf/file.c
fs/udf/inode.c
fs/ufs/file.c
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc_btree.c
fs/xfs/xfs_aops.c
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_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_da_btree.c
fs/xfs/xfs_da_btree.h
fs/xfs/xfs_da_format.h
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_leaf.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_dir2_priv.h
fs/xfs/xfs_dir2_readdir.c
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_dquot_buf.c
fs/xfs/xfs_file.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_filestream.h
fs/xfs/xfs_format.h
fs/xfs/xfs_fs.h
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_ialloc_btree.c
fs/xfs/xfs_ialloc_btree.h
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_fork.c
fs/xfs/xfs_inode_fork.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mru_cache.c
fs/xfs/xfs_mru_cache.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quota_defs.h
fs/xfs/xfs_sb.h
fs/xfs/xfs_shared.h
fs/xfs/xfs_stats.c
fs/xfs/xfs_stats.h
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_symlink_remote.c
fs/xfs/xfs_trace.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_trans_resv.c
fs/xfs/xfs_trans_space.h
fs/xfs/xfs_types.h
include/acpi/acpixf.h
include/acpi/actbl.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-generic/fixmap.h
include/asm-generic/word-at-a-time.h
include/drm/drmP.h
include/drm/drm_crtc_helper.h
include/drm/drm_modes.h
include/drm/i915_pciids.h
include/dt-bindings/clock/at91.h [moved from include/dt-bindings/clk/at91.h with 100% similarity]
include/dt-bindings/clock/r8a7790-clock.h
include/dt-bindings/clock/r8a7791-clock.h
include/dt-bindings/clock/s3c2412.h [new file with mode: 0644]
include/dt-bindings/clock/s3c2443.h [new file with mode: 0644]
include/linux/amba/xilinx_dma.h [new file with mode: 0644]
include/linux/bio.h
include/linux/blk-mq.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/ceph/libceph.h
include/linux/cpufreq.h
include/linux/dmaengine.h
include/linux/ethtool.h
include/linux/f2fs_fs.h
include/linux/fb.h
include/linux/filter.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/gpio_keys.h
include/linux/hid.h
include/linux/interrupt.h
include/linux/irq.h
include/linux/key.h
include/linux/mbus.h
include/linux/memblock.h
include/linux/mfd/arizona/core.h
include/linux/mfd/ipaq-micro.h [new file with mode: 0644]
include/linux/mfd/kempld.h
include/linux/mfd/max14577-private.h
include/linux/mfd/max14577.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/samsung/core.h
include/linux/mfd/samsung/s2mps14.h
include/linux/mfd/tps65090.h
include/linux/mfd/tps65217.h
include/linux/mfd/tps65218.h
include/linux/mm.h
include/linux/mmc/card.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/moduleparam.h
include/linux/mtd/spi-nor.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/netlink.h
include/linux/nfs_fs.h
include/linux/of_irq.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/phy.h
include/linux/platform_data/edma.h
include/linux/security.h
include/linux/shdma-base.h
include/linux/skbuff.h
include/linux/sock_diag.h
include/linux/spi/at86rf230.h
include/linux/splice.h
include/linux/suspend.h
include/linux/tcp.h
include/linux/tty.h
include/linux/uio.h
include/linux/virtio.h
include/net/6lowpan.h
include/net/addrconf.h
include/net/af_vsock.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/cfg80211.h
include/net/checksum.h
include/net/dsa.h
include/net/ip.h
include/net/ip6_checksum.h
include/net/ipv6.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/pkt_cls.h
include/net/regulatory.h
include/net/sch_generic.h
include/net/sock.h
include/net/tcp.h
include/net/vxlan.h
include/net/xfrm.h
include/sound/atmel-ac97c.h
include/sound/rt5640.h
include/sound/rt5651.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/sta350.h [new file with mode: 0644]
include/trace/events/asoc.h
include/trace/events/ext4.h
include/trace/events/filelock.h [new file with mode: 0644]
include/trace/events/module.h
include/uapi/drm/i915_drm.h
include/uapi/linux/audit.h
include/uapi/linux/capability.h
include/uapi/linux/ethtool.h
include/uapi/linux/filter.h
include/uapi/linux/fuse.h
include/uapi/linux/if_fddi.h
include/uapi/linux/input.h
include/uapi/linux/nl80211.h
include/uapi/linux/tipc.h
include/uapi/linux/tipc_config.h
init/Kconfig
init/main.c
kernel/audit.c
kernel/gcov/Kconfig
kernel/hrtimer.c
kernel/irq/irqdesc.c
kernel/module.c
kernel/params.c
kernel/power/hibernate.c
kernel/softirq.c
kernel/timer.c
kernel/trace/ftrace.c
kernel/trace/trace_events_trigger.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/interval_tree.c
lib/interval_tree_test.c [moved from lib/interval_tree_test_main.c with 100% similarity]
mm/Kconfig
mm/filemap.c
mm/iov_iter.c
mm/memblock.c
mm/page_io.c
mm/process_vm_access.c
mm/shmem.c
mm/vmacache.c
mm/vmscan.c
net/8021q/vlan_dev.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bridge/br_netlink.c
net/can/gw.c
net/ceph/osdmap.c
net/ceph/pagevec.c
net/core/dev.c
net/core/ethtool.c
net/core/filter.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/sock.c
net/core/sock_diag.c
net/dcb/dcbnl.c
net/decnet/dn_dev.c
net/decnet/dn_fib.c
net/decnet/netfilter/dn_rtmsg.c
net/ieee802154/reassembly.c
net/ipv4/inetpeer.c
net/ipv4/ip_gre.c
net/ipv4/ip_options.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_vti.c
net/ipv4/tcp.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_lp.c
net/ipv4/tcp_output.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_veno.c
net/ipv4/tcp_yeah.c
net/ipv4/udp.c
net/ipv4/xfrm4_output.c
net/ipv6/addrconf.c
net/ipv6/icmp.c
net/ipv6/ip6_checksum.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6mr.c
net/ipv6/netfilter/ip6t_rpfilter.c
net/ipv6/ping.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_output.c
net/key/af_key.c
net/l2tp/l2tp_ip6.c
net/mac80211/aes_ccm.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/debugfs.h
net/mac80211/debugfs_netdev.h
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh_hwmp.c
net/mac80211/michael.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/util.c
net/mac80211/wpa.c
net/netfilter/nfnetlink.c
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/netlink/genetlink.c
net/openvswitch/vport-vxlan.c
net/packet/diag.c
net/phonet/pn_netlink.c
net/sched/act_api.c
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_bpf.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_fw.c
net/sched/cls_route.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/sched/sch_api.c
net/sched/sch_hhf.c
net/sctp/protocol.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/ulpqueue.c
net/tipc/Makefile
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/discover.c
net/tipc/discover.h
net/tipc/handler.c [deleted file]
net/tipc/link.c
net/tipc/link.h
net/tipc/name_distr.c
net/tipc/name_distr.h
net/tipc/name_table.c
net/tipc/net.c
net/tipc/net.h
net/tipc/netlink.c
net/tipc/node.c
net/tipc/node.h
net/tipc/node_subscr.c
net/tipc/node_subscr.h
net/tipc/socket.c
net/vmw_vsock/af_vsock.c
net/wireless/Kconfig
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ethtool.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/scan.c
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c
net/wireless/wext-compat.c
net/wireless/wext-compat.h
net/wireless/wext-sme.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/Makefile.build
scripts/Makefile.extrawarn [new file with mode: 0644]
scripts/Makefile.fwinst
scripts/Makefile.host
scripts/Makefile.lib
scripts/Makefile.lto [new file with mode: 0644]
scripts/Makefile.modpost
scripts/conmakehash.c
scripts/kconfig/streamline_config.pl
scripts/link-vmlinux.sh
scripts/mkcompile_h
scripts/mkmakefile
scripts/mod/modpost.c
scripts/package/builddeb
scripts/patch-kernel
scripts/sortextable.c
scripts/tags.sh
security/apparmor/include/apparmor.h
security/apparmor/lib.c
security/capability.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/permission.c
security/keys/persistent.c
security/keys/proc.c
security/keys/sysctl.c
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
security/selinux/include/classmap.h
security/smack/smack_lsm.c
sound/atmel/ac97c.c
sound/core/pcm_lib.c
sound/core/seq/seq_midi.c
sound/pci/fm801.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_priv.h
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/lx6464es/lx_core.c
sound/soc/atmel/Kconfig
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l51-i2c.c [new file with mode: 0644]
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l51.h
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/hdmi.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/max9768.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98095.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.h
sound/soc/codecs/rt5651.c [new file with mode: 0644]
sound/soc/codecs/rt5651.h [new file with mode: 0644]
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/si476x.c
sound/soc/codecs/sirf-audio-codec.c
sound/soc/codecs/sirf-audio-codec.h
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta350.c [new file with mode: 0644]
sound/soc/codecs/sta350.h [new file with mode: 0644]
sound/soc/codecs/tas5086.c
sound/soc/codecs/tlv320aic23-i2c.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/davinci/davinci-vcif.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_spdif.h
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/generic/simple-card.c
sound/soc/intel/sst-acpi.c
sound/soc/intel/sst-baytrail-ipc.c
sound/soc/intel/sst-dsp-priv.h
sound/soc/intel/sst-dsp.c
sound/soc/intel/sst-dsp.h
sound/soc/intel/sst-firmware.c
sound/soc/intel/sst-haswell-dsp.c
sound/soc/intel/sst-haswell-ipc.c
sound/soc/intel/sst-haswell-ipc.h
sound/soc/intel/sst-haswell-pcm.c
sound/soc/jz4740/Kconfig
sound/soc/jz4740/Makefile
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/qi_lb60.c
sound/soc/nuc900/Kconfig
sound/soc/nuc900/nuc900-ac97.c
sound/soc/omap/Kconfig
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/n810.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-hdmi-card.c
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h [new file with mode: 0644]
sound/soc/omap/omap-twl4030.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/osk5912.c
sound/soc/omap/rx51.c
sound/soc/pxa/Kconfig
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/i2s.c
sound/soc/samsung/idma.c
sound/soc/samsung/snow.c [new file with mode: 0644]
sound/soc/sh/Kconfig
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sirf/sirf-audio-port.c
sound/soc/sirf/sirf-audio-port.h [deleted file]
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-devres.c
sound/soc/soc-io.c
sound/soc/soc-pcm.c
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/bcd2000/Makefile [new file with mode: 0644]
sound/usb/bcd2000/bcd2000.c [new file with mode: 0644]
sound/usb/card.c
sound/usb/card.h
sound/usb/endpoint.c
sound/usb/mixer.c
sound/usb/pcm.c
sound/usb/usbaudio.h
tools/lib/api/fs/debugfs.c
tools/lib/traceevent/event-parse.c
tools/lib/traceevent/event-parse.h
tools/net/bpf_dbg.c
tools/net/bpf_exp.l
tools/net/bpf_exp.y
tools/perf/Makefile.perf
tools/perf/arch/x86/tests/dwarf-unwind.c
tools/perf/arch/x86/tests/regs_load.S
tools/perf/config/Makefile
tools/perf/tests/make
tools/perf/util/machine.c
tools/power/acpi/Makefile
tools/power/acpi/common/cmfsize.c [new file with mode: 0644]
tools/power/acpi/common/getopt.c [new file with mode: 0644]
tools/power/acpi/man/acpidump.8
tools/power/acpi/os_specific/service_layers/oslinuxtbl.c [new file with mode: 0644]
tools/power/acpi/os_specific/service_layers/osunixdir.c [new file with mode: 0644]
tools/power/acpi/os_specific/service_layers/osunixmap.c [new file with mode: 0644]
tools/power/acpi/tools/acpidump/acpidump.c [deleted file]
tools/power/acpi/tools/acpidump/acpidump.h [new file with mode: 0644]
tools/power/acpi/tools/acpidump/apdump.c [new file with mode: 0644]
tools/power/acpi/tools/acpidump/apfiles.c [new file with mode: 0644]
tools/power/acpi/tools/acpidump/apmain.c [new file with mode: 0644]
tools/power/acpi/tools/ec/Makefile [new file with mode: 0644]
tools/power/acpi/tools/ec/ec_access.c [new file with mode: 0644]
tools/power/cpupower/Makefile
tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
virt/kvm/arm/vgic.c
virt/kvm/assigned-dev.c
virt/kvm/async_pf.c

index 42fa0d5626a9560d74d16b2df5250b300543b67e..f4c0b091dcf4e6413cbe70f0ec345a5894e0885e 100644 (file)
@@ -22,7 +22,6 @@
 *.lst
 *.symtypes
 *.order
-modules.builtin
 *.elf
 *.bin
 *.gz
@@ -33,6 +32,8 @@ modules.builtin
 *.lzo
 *.patch
 *.gcno
+modules.builtin
+Module.symvers
 
 #
 # Top-level generic files
@@ -44,7 +45,6 @@ modules.builtin
 /vmlinuz
 /System.map
 /Module.markers
-/Module.symvers
 
 #
 # Debian directory (make deb-pkg)
index a3c5a6685036103e7ec677272acdc4620d0302f6..ab8d76dfaa8096bbdf42bacf31336b856c07959b 100644 (file)
@@ -117,7 +117,7 @@ Description:
 
 What:          /sys/bus/pci/devices/.../vpd
 Date:          February 2008
-Contact:       Ben Hutchings <bhutchings@solarflare.com>
+Contact:       Ben Hutchings <bwh@kernel.org>
 Description:
                A file named vpd in a device directory will be a
                binary file containing the Vital Product Data for the
index d5a0d33c571f336a7756fc642acf61309facd6e6..acb9bfc89b4879c7f1f7c6815959baa4c819154b 100644 (file)
@@ -128,7 +128,7 @@ Description:        Discover cpuidle policy and mechanism
 
 What:          /sys/devices/system/cpu/cpu#/cpufreq/*
 Date:          pre-git history
-Contact:       cpufreq@vger.kernel.org
+Contact:       linux-pm@vger.kernel.org
 Description:   Discover and change clock speed of CPUs
 
                Clock scaling allows you to change the clock speed of the
@@ -146,7 +146,7 @@ Description:        Discover and change clock speed of CPUs
 
 What:          /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus
 Date:          June 2013
-Contact:       cpufreq@vger.kernel.org
+Contact:       linux-pm@vger.kernel.org
 Description:   Discover CPUs in the same CPU frequency coordination domain
 
                freqdomain_cpus is the list of CPUs (online+offline) that share
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-thingm b/Documentation/ABI/testing/sysfs-driver-hid-thingm
deleted file mode 100644 (file)
index abcffee..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-What:          /sys/class/leds/blink1::<serial>/rgb
-Date:          January 2013
-Contact:       Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-Description:   The ThingM blink1 is an USB RGB LED. The color notation is
-               3-byte hexadecimal. Read this attribute to get the last set
-               color. Write the 24-bit hexadecimal color to change the current
-               LED color. The default color is full white (0xFFFFFF).
-               For instance, set the color to green with: echo 00FF00 > rgb
-
-What:          /sys/class/leds/blink1::<serial>/fade
-Date:          January 2013
-Contact:       Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-Description:   This attribute allows to set a fade time in milliseconds for
-               the next color change. Read the attribute to know the current
-               fade time. The default value is set to 0 (no fade time). For
-               instance, set a fade time of 2 seconds with: echo 2000 > fade
-
-What:          /sys/class/leds/blink1::<serial>/play
-Date:          January 2013
-Contact:       Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-Description:   This attribute is used to play/pause the light patterns. Write 1
-               to start playing, 0 to stop. Reading this attribute returns the
-               current playing status.
index 044b76436e8373ae601f9c60bd274754f3df6033..d9b9416c989fd81f0a9a338b59fc9093d96479a4 100644 (file)
 !Finclude/net/cfg80211.h wdev_priv
 !Finclude/net/cfg80211.h ieee80211_iface_limit
 !Finclude/net/cfg80211.h ieee80211_iface_combination
+!Finclude/net/cfg80211.h cfg80211_check_combinations
       </chapter>
       <chapter>
       <title>Actions and configuration</title>
index 677a02553ec0cd772c1a86c73b7d314f48376190..1c51d43f2548bf5451054431cd9caf6f05e76962 100644 (file)
@@ -341,14 +341,6 @@ char *date;</synopsis>
         </para>
         <sect4>
           <title>Managed IRQ Registration</title>
-          <para>
-            Both the <function>drm_irq_install</function> and
-           <function>drm_irq_uninstall</function> functions get the device IRQ by
-           calling <function>drm_dev_to_irq</function>. This inline function will
-           call a bus-specific operation to retrieve the IRQ number. For platform
-           devices, <function>platform_get_irq</function>(..., 0) is used to
-           retrieve the IRQ number.
-          </para>
           <para>
             <function>drm_irq_install</function> starts by calling the
             <methodname>irq_preinstall</methodname> driver operation. The operation
@@ -356,7 +348,7 @@ char *date;</synopsis>
             clearing all pending interrupt flags or disabling the interrupt.
           </para>
           <para>
-            The IRQ will then be requested by a call to
+            The passed-in IRQ will then be requested by a call to
             <function>request_irq</function>. If the DRIVER_IRQ_SHARED driver
             feature flag is set, a shared (IRQF_SHARED) IRQ handler will be
             requested.
@@ -2950,6 +2942,11 @@ int num_ioctls;</synopsis>
        This sections covers all things related to the GEM implementation in the
        i915 driver.
       </para>
+      <sect2>
+        <title>Batchbuffer Parsing</title>
+!Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser
+!Idrivers/gpu/drm/i915/i915_cmd_parser.c
+      </sect2>
     </sect1>
   </chapter>
 </part>
index 963ec445e15a3a1a84571b15c3e2362bdd5e19b9..2cce5401e323ff0bc88ed98557babbd2a963234e 100644 (file)
@@ -234,6 +234,11 @@ Berlin family (Digital Entertainment)
                Core:           Marvell PJ4B (ARMv7), Tauros3 L2CC
                Homepage:       http://www.marvell.com/digital-entertainment/armada-1500/
                Product Brief:  http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf
+       88DE3114, Armada 1500 Pro
+               Design name:    BG2-Q
+               Core:           Quad Core ARM Cortex-A9, PL310 L2CC
+               Homepage:       http://www.marvell.com/digital-entertainment/armada-1500-pro/
+               Product Brief:  http://www.marvell.com/digital-entertainment/armada-1500-pro/assets/Marvell_ARMADA_1500_PRO-01_product_brief.pdf
        88DE????
                Design name:    BG3
                Core:           ARM Cortex-A15, CA15 integrated L2CC
index 4bfb9ffbdbc1d2b389025c9c0e5d9c5402a36a29..256c5e067fb1e7eda0254bfe6cd6540b5b329712 100644 (file)
@@ -41,16 +41,9 @@ fffe8000     fffeffff        DTCM mapping area for platforms with
 fffe0000       fffe7fff        ITCM mapping area for platforms with
                                ITCM mounted inside the CPU.
 
-fff00000       fffdffff        Fixmap mapping region.  Addresses provided
+fffc0000       ffdfffff        Fixmap mapping region.  Addresses provided
                                by fix_to_virt() will be located here.
 
-ffc00000       ffefffff        DMA memory mapping region.  Memory returned
-                               by the dma_alloc_xxx functions will be
-                               dynamically mapped here.
-
-ff000000       ffbfffff        Reserved for future expansion of DMA
-                               mapping region.
-
 fee00000       feffffff        Mapping of PCI I/O space. This is a static
                                mapping within the vmalloc space.
 
index 48da5fdcb9f11b5671859a63e61ce2c9f40bab03..b045fe54986a077792c80e4ad2563b2e38118a86 100644 (file)
@@ -228,3 +228,22 @@ is the corresponding frequency table helper for the ->target
 stage. Just pass the values to this function, and the unsigned int
 index returns the number of the frequency table entry which contains
 the frequency the CPU shall be set to.
+
+The following macros can be used as iterators over cpufreq_frequency_table:
+
+cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency
+table.
+
+cpufreq-for_each_valid_entry(pos, table) - iterates over all entries,
+excluding CPUFREQ_ENTRY_INVALID frequencies.
+Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
+"table" - the cpufreq_frequency_table * you want to iterate over.
+
+For example:
+
+       struct cpufreq_frequency_table *pos, *driver_freq_table;
+
+       cpufreq_for_each_entry(pos, driver_freq_table) {
+               /* Do something with pos */
+               pos->frequency = ...
+       }
index 3d0b915035b9f28fbcff7d83a91ef016d4d7b2ad..dc024ab4054fc9d3728f0cda79cc9891e4178544 100644 (file)
@@ -35,8 +35,8 @@ Mailing List
 ------------
 There is a CPU frequency changing CVS commit and general list where
 you can report bugs, problems or submit patches. To post a message,
-send an email to cpufreq@vger.kernel.org, to subscribe go to
-http://vger.kernel.org/vger-lists.html#cpufreq and follow the
+send an email to linux-pm@vger.kernel.org, to subscribe go to
+http://vger.kernel.org/vger-lists.html#linux-pm and follow the
 instructions there.
 
 Links
index 06fc7602593a9d38a4cec97538948b03b5ce2676..37b2cafa4e52703b516d8c163653ae58106ad990 100644 (file)
@@ -19,6 +19,9 @@ to deliver its interrupts via SPIs.
 
 - clock-frequency : The frequency of the main counter, in Hz. Optional.
 
+- always-on : a boolean property. If present, the timer is powered through an
+  always-on power domain, therefore it never loses context.
+
 Example:
 
        timer {
index 926b4d6aae7e0e3e8cb3eb8031e8d95abec39e05..26799ef562df1a00451df7426b3df70ef9e84363 100644 (file)
@@ -1,20 +1,21 @@
 Power Management Service Unit(PMSU)
 -----------------------------------
-Available on Marvell SOCs: Armada 370 and Armada XP
+Available on Marvell SOCs: Armada 370, Armada 38x and Armada XP
 
 Required properties:
 
-- compatible: "marvell,armada-370-xp-pmsu"
+- compatible: should be one of:
+  - "marvell,armada-370-pmsu" for Armada 370 or Armada XP
+  - "marvell,armada-380-pmsu" for Armada 38x
+  - "marvell,armada-370-xp-pmsu" was used for Armada 370/XP but is now
+    deprecated and will be removed
 
-- reg: Should contain PMSU registers location and length. First pair
-  for the per-CPU SW Reset Control registers, second pair for the
-  Power Management Service Unit.
+- reg: Should contain PMSU registers location and length.
 
 Example:
 
-armada-370-xp-pmsu@d0022000 {
-       compatible = "marvell,armada-370-xp-pmsu";
-       reg = <0xd0022100 0x430>,
-             <0xd0020800 0x20>;
+armada-370-xp-pmsu@22000 {
+       compatible = "marvell,armada-370-pmsu";
+       reg = <0x22000 0x1000>;
 };
 
diff --git a/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt b/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt
new file mode 100644 (file)
index 0000000..b63a7b6
--- /dev/null
@@ -0,0 +1,14 @@
+Marvell Armada CPU reset controller
+===================================
+
+Required properties:
+
+- compatible: Should be "marvell,armada-370-cpu-reset".
+
+- reg: should be register base and length as documented in the
+  datasheet for the CPU reset registers
+
+cpurst: cpurst@20800 {
+       compatible = "marvell,armada-370-cpu-reset";
+       reg = <0x20800 0x20>;
+};
index 17d8cd107559981a5a6de1ba7f80f45874c62105..8dd46617c889afa3f05f1e578ddc34bc76d94cc8 100644 (file)
@@ -1,16 +1,33 @@
 Coherency fabric
 ----------------
-Available on Marvell SOCs: Armada 370 and Armada XP
+Available on Marvell SOCs: Armada 370, Armada 375, Armada 38x and Armada XP
 
 Required properties:
 
-- compatible: "marvell,coherency-fabric"
+- compatible: the possible values are:
+
+ * "marvell,coherency-fabric", to be used for the coherency fabric of
+   the Armada 370 and Armada XP.
+
+ * "marvell,armada-375-coherency-fabric", for the Armada 375 coherency
+   fabric.
+
+ * "marvell,armada-380-coherency-fabric", for the Armada 38x coherency
+   fabric.
 
 - reg: Should contain coherency fabric registers location and
-  length. First pair for the coherency fabric registers, second pair
-  for the per-CPU fabric registers registers.
+  length.
+
+ * For "marvell,coherency-fabric", the first pair for the coherency
+   fabric registers, second pair for the per-CPU fabric registers.
 
-Example:
+ * For "marvell,armada-375-coherency-fabric", only one pair is needed
+   for the per-CPU fabric registers.
+
+ * For "marvell,armada-380-coherency-fabric", only one pair is needed
+   for the per-CPU fabric registers.
+
+Examples:
 
 coherency-fabric@d0020200 {
        compatible = "marvell,coherency-fabric";
@@ -19,3 +36,8 @@ coherency-fabric@d0020200 {
 
 };
 
+coherency-fabric@21810 {
+       compatible = "marvell,armada-375-coherency-fabric";
+       reg = <0x21810 0x1c>;
+};
+
index 333f4aea30291e7a2882c8f2f67d1ec417307ef5..4bbcf4fb7583ab42f917275f068a037c347bd989 100644 (file)
@@ -185,6 +185,9 @@ nodes to be present and contain the properties described below.
                            "qcom,gcc-msm8660"
                            "qcom,kpss-acc-v1"
                            "qcom,kpss-acc-v2"
+                           "marvell,armada-375-smp"
+                           "marvell,armada-380-smp"
+                           "marvell,armada-xp-smp"
 
        - cpu-release-addr
                Usage: required for systems that have an "enable-method"
index 737afa5f8148b92b469f5430271713f5cb81114e..0677003e1476611a8252cbf1d964ea9414225db9 100644 (file)
@@ -12,6 +12,7 @@ SoC and board used. Currently known SoC compatibles are:
     "marvell,berlin2"      for Marvell Armada 1500 (BG2, 88DE3100),
     "marvell,berlin2cd"    for Marvell Armada 1500-mini (BG2CD, 88DE3005)
     "marvell,berlin2ct"    for Marvell Armada ? (BG2CT, 88DE????)
+    "marvell,berlin2q"     for Marvell Armada 1500-pro (BG2Q, 88DE3114)
     "marvell,berlin3"      for Marvell Armada ? (BG3, 88DE????)
 
 * Example:
index fe5cef8976cb0724833b292ab17d25fa779423c5..75ef91d08f3bd2cbc402326598ead0e34663e790 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
 
 - compatible : should be one of
        "arm,armv8-pmuv3"
+       "arm,cortex-a17-pmu"
        "arm,cortex-a15-pmu"
        "arm,cortex-a12-pmu"
        "arm,cortex-a9-pmu"
index 48b285ffa3a650e7d0adb028e7f577617b2dff9c..d6b07e87aa936e5f7a974c28bcf911e645c81f88 100644 (file)
@@ -4,10 +4,15 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
 Each SATA controller should have its own node.
 
 Required properties:
-- compatible        : compatible list, one of "snps,spear-ahci",
-                      "snps,exynos5440-ahci", "ibm,476gtr-ahci",
-                      "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci"
-                      "fsl,imx6q-ahci" or "snps,dwc-ahci"
+- compatible        : compatible string, one of:
+  - "allwinner,sun4i-a10-ahci"
+  - "fsl,imx53-ahci"
+  - "fsl,imx6q-ahci"
+  - "ibm,476gtr-ahci"
+  - "marvell,armada-380-ahci"
+  - "snps,dwc-ahci"
+  - "snps,exynos5440-ahci"
+  - "snps,spear-ahci"
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
index 7bcfbf59810e5a5c105740c7dca63844d7791ef2..a668f0e7d0018b76841127db20845a7fd45affd6 100644 (file)
@@ -24,6 +24,7 @@ Required properties:
   * "sata-phy" for the SATA 6.0Gbps PHY
 
 Optional properties:
+- dma-coherent         : Present if dma operations are coherent
 - status               : Shall be "ok" if enabled or "disabled" if disabled.
                          Default is "ok".
 
@@ -55,6 +56,7 @@ Example:
                              <0x0 0x1f22e000 0x0 0x1000>,
                              <0x0 0x1f227000 0x0 0x1000>;
                        interrupts = <0x0 0x87 0x4>;
+                       dma-coherent;
                        status = "ok";
                        clocks = <&sataclk 0>;
                        phys = <&phy2 0>;
@@ -69,6 +71,7 @@ Example:
                              <0x0 0x1f23e000 0x0 0x1000>,
                              <0x0 0x1f237000 0x0 0x1000>;
                        interrupts = <0x0 0x88 0x4>;
+                       dma-coherent;
                        status = "ok";
                        clocks = <&sataclk 0>;
                        phys = <&phy3 0>;
index cd5e23912888cf4350750fe0adc908fb895e3d08..6794cdc96d8fdf44513a4ad2310fe67a2a93712d 100644 (file)
@@ -62,7 +62,7 @@ Required properties for PMC node:
 - interrupt-controller : tell that the PMC is an interrupt controller.
 - #interrupt-cells : must be set to 1. The first cell encodes the interrupt id,
        and reflect the bit position in the PMC_ER/DR/SR registers.
-       You can use the dt macros defined in dt-bindings/clk/at91.h.
+       You can use the dt macros defined in dt-bindings/clock/at91.h.
        0 (AT91_PMC_MOSCS) -> main oscillator ready
        1 (AT91_PMC_LOCKA) -> PLL A ready
        2 (AT91_PMC_LOCKB) -> PLL B ready
index db4f2f05c4d0f15b32f354a7629e7a0c5a0556b4..ceaf31346d5c0d0591271b95ea1fd8a4e21706ef 100644 (file)
@@ -139,6 +139,9 @@ clocks and IDs.
        uart5_ipg               124
        reserved                125
        wdt_ipg                 126
+       cko_div                 127
+       cko_sel                 128
+       clo                     129
 
 Examples:
 
index 7a2070393732aa84fc40d7a41220b4531a325248..6bc9fd2c6631435f74267f7c8b97e54d55eeeda1 100644 (file)
@@ -98,7 +98,12 @@ clocks and IDs.
        fpm                  83
        mpll_osc_sel         84
        mpll_sel             85
-       spll_gate            86
+       spll_gate            86
+       mshc_div             87
+       rtic_ipg_gate        88
+       mshc_ipg_gate        89
+       rtic_ahb_gate        90
+       mshc_baud_gate       91
 
 Examples:
 
index 6aab72bf67ea96280796eda3251e4a9e634f0a92..90ec91fe5ce03a317437f49eb7b376c5f2140bba 100644 (file)
@@ -220,6 +220,7 @@ clocks and IDs.
        lvds2_sel               205
        lvds1_gate              206
        lvds2_gate              207
+       esai_ahb                208
 
 Examples:
 
index 307a503c5db882cc600710aae58381ea131977ae..dc5ea5b22da90dbf43f0d5e15b28141d3c7e0e4d 100644 (file)
@@ -29,6 +29,11 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove:
  2 = l2clk  (L2 Cache clock derived from CPU0 clock)
  3 = ddrclk (DDR controller clock derived from CPU0 clock)
 
+The following is a list of provided IDs and clock names on Orion5x:
+ 0 = tclk   (Internal Bus clock)
+ 1 = cpuclk (CPU0 clock)
+ 2 = ddrclk (DDR controller clock derived from CPU0 clock)
+
 Required properties:
 - compatible : shall be one of the following:
        "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
@@ -38,6 +43,9 @@ Required properties:
        "marvell,dove-core-clock" - for Dove SoC core clocks
        "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
        "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
+       "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC
+       "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC
+       "marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC
 - reg : shall be the register address of the Sample-At-Reset (SAR) register
 - #clock-cells : from common clock binding; shall be set to 1
 
diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt
new file mode 100644 (file)
index 0000000..2b43096
--- /dev/null
@@ -0,0 +1,50 @@
+* Samsung S3C2412 Clock Controller
+
+The S3C2412 clock controller generates and supplies clock to various controllers
+within the SoC. The clock binding described here is applicable to the s3c2412
+and s3c2413 SoCs in the s3c24x family.
+
+Required Properties:
+
+- compatible: should be "samsung,s3c2412-clock"
+- 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 SoC.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/s3c2412.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:
+ - "xti" - crystal input - required,
+ - "ext" - external clock source - optional,
+
+Example: Clock controller node:
+
+       clocks: clock-controller@4c000000 {
+               compatible = "samsung,s3c2412-clock";
+               reg = <0x4c000000 0x20>;
+               #clock-cells = <1>;
+       };
+
+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):
+
+       serial@50004000 {
+               compatible = "samsung,s3c2412-uart";
+               reg = <0x50004000 0x4000>;
+               interrupts = <1 23 3 4>, <1 23 4 4>;
+               clock-names = "uart", "clk_uart_baud2", "clk_uart_baud3";
+               clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>,
+                        <&clocks SCLK_UART>;
+               status = "disabled";
+       };
diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt
new file mode 100644 (file)
index 0000000..e67bb05
--- /dev/null
@@ -0,0 +1,56 @@
+* Samsung S3C2443 Clock Controller
+
+The S3C2443 clock controller generates and supplies clock to various controllers
+within the SoC. The clock binding described here is applicable to all SoCs in
+the s3c24x family starting with the s3c2443.
+
+Required Properties:
+
+- compatible: should be one of the following.
+  - "samsung,s3c2416-clock" - controller compatible with S3C2416 SoC.
+  - "samsung,s3c2443-clock" - controller compatible with S3C2443 SoC.
+  - "samsung,s3c2450-clock" - controller compatible with S3C2450 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 SoC.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/s3c2443.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:
+ - "xti" - crystal input - required,
+ - "ext" - external clock source - optional,
+ - "ext_i2s" - external I2S clock - optional,
+ - "ext_uart" - external uart clock - optional,
+
+Example: Clock controller node:
+
+       clocks: clock-controller@4c000000 {
+               compatible = "samsung,s3c2416-clock";
+               reg = <0x4c000000 0x40>;
+               #clock-cells = <1>;
+       };
+
+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):
+
+       serial@50004000 {
+               compatible = "samsung,s3c2440-uart";
+               reg = <0x50004000 0x4000>;
+               interrupts = <1 23 3 4>, <1 23 4 4>;
+               clock-names = "uart", "clk_uart_baud2",
+                               "clk_uart_baud3";
+               clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>,
+                               <&clocks SCLK_UART>;
+               status = "disabled";
+       };
index a4fa4efa1d83a3aa7fa3a4c0e9ca99d914e7f463..7a802f64e5bd8f89e08b0bd4b34a388eeb926254 100644 (file)
@@ -1,17 +1,20 @@
 * MARVELL MMP DMA controller
 
 Marvell Peripheral DMA Controller
-Used platfroms: pxa688, pxa910, pxa3xx, etc
+Used platforms: pxa688, pxa910, pxa3xx, etc
 
 Required properties:
 - compatible: Should be "marvell,pdma-1.0"
 - reg: Should contain DMA registers location and length.
 - interrupts: Either contain all of the per-channel DMA interrupts
                or one irq for pdma device
-- #dma-channels: Number of DMA channels supported by the controller.
+
+Optional properties:
+- #dma-channels: Number of DMA channels supported by the controller (defaults
+  to 32 when not specified)
 
 "marvell,pdma-1.0"
-Used platfroms: pxa25x, pxa27x, pxa3xx, pxa93x, pxa168, pxa910, pxa688.
+Used platforms: pxa25x, pxa27x, pxa3xx, pxa93x, pxa168, pxa910, pxa688.
 
 Examples:
 
@@ -45,7 +48,7 @@ pdma: dma-controller@d4000000 {
 
 
 Marvell Two Channel DMA Controller used specifically for audio
-Used platfroms: pxa688, pxa910
+Used platforms: pxa688, pxa910
 
 Required properties:
 - compatible: Should be "marvell,adma-1.0" or "marvell,pxa910-squ"
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
new file mode 100644 (file)
index 0000000..1405ed0
--- /dev/null
@@ -0,0 +1,75 @@
+Xilinx AXI VDMA engine, it does transfers between memory and video devices.
+It can be configured to have one channel or two channels. If configured
+as two channels, one is to transmit to the video device and another is
+to receive from the video device.
+
+Required properties:
+- compatible: Should be "xlnx,axi-vdma-1.00.a"
+- #dma-cells: Should be <1>, see "dmas" property below
+- reg: Should contain VDMA registers location and length.
+- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
+- dma-channel child node: Should have at least one channel and can have up to
+       two channels per device. This node specifies the properties of each
+       DMA channel (see child node properties below).
+
+Optional properties:
+- xlnx,include-sg: Tells configured for Scatter-mode in
+       the hardware.
+- xlnx,flush-fsync: Tells which channel to Flush on Frame sync.
+       It takes following values:
+       {1}, flush both channels
+       {2}, flush mm2s channel
+       {3}, flush s2mm channel
+
+Required child node properties:
+- compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or
+       "xlnx,axi-vdma-s2mm-channel".
+- interrupts: Should contain per channel VDMA interrupts.
+- xlnx,data-width: Should contain the stream data width, take values
+       {32,64...1024}.
+
+Optional child node properties:
+- xlnx,include-dre: Tells hardware is configured for Data
+       Realignment Engine.
+- xlnx,genlock-mode: Tells Genlock synchronization is
+       enabled/disabled in hardware.
+
+Example:
+++++++++
+
+axi_vdma_0: axivdma@40030000 {
+       compatible = "xlnx,axi-vdma-1.00.a";
+       #dma_cells = <1>;
+       reg = < 0x40030000 0x10000 >;
+       xlnx,num-fstores = <0x8>;
+       xlnx,flush-fsync = <0x1>;
+       dma-channel@40030000 {
+               compatible = "xlnx,axi-vdma-mm2s-channel";
+               interrupts = < 0 54 4 >;
+               xlnx,datawidth = <0x40>;
+       } ;
+       dma-channel@40030030 {
+               compatible = "xlnx,axi-vdma-s2mm-channel";
+               interrupts = < 0 53 4 >;
+               xlnx,datawidth = <0x40>;
+       } ;
+} ;
+
+
+* DMA client
+
+Required properties:
+- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs,
+       where Channel ID is '0' for write/tx and '1' for read/rx
+       channel.
+- dma-names: a list of DMA channel names, one per "dmas" entry
+
+Example:
+++++++++
+
+vdmatest_0: vdmatest@0 {
+       compatible ="xlnx,axi-vdma-test-1.00.a";
+       dmas = <&axi_vdma_0 0
+               &axi_vdma_0 1>;
+       dma-names = "vdma0", "vdma1";
+} ;
index efa8b8451f93be2600cbb41fa5c8275c7ea5ddaf..b48f4ef31d937ff8c4944e379d55357045653f02 100644 (file)
@@ -136,6 +136,7 @@ of the following host1x client modules:
   - compatible: "nvidia,tegra<chip>-hdmi"
   - reg: Physical base address and length of the controller's registers.
   - interrupts: The interrupt outputs from the controller.
+  - hdmi-supply: supply for the +5V HDMI connector pin
   - vdd-supply: regulator for supply voltage
   - pll-supply: regulator for PLL
   - clocks: Must contain an entry for each entry in clock-names.
@@ -180,6 +181,7 @@ of the following host1x client modules:
     See ../reset/reset.txt for details.
   - reset-names: Must include the following entries:
     - dsi
+  - avdd-dsi-supply: phandle of a supply that powers the DSI controller
   - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying
     which pads are used by this DSI output and need to be calibrated. See also
     ../mipi/nvidia,tegra114-mipi.txt.
diff --git a/Documentation/devicetree/bindings/input/st-keyscan.txt b/Documentation/devicetree/bindings/input/st-keyscan.txt
new file mode 100644 (file)
index 0000000..51eb428
--- /dev/null
@@ -0,0 +1,60 @@
+* ST Keyscan controller Device Tree bindings
+
+The ST keyscan controller Device Tree binding is based on the
+matrix-keymap.
+
+Required properties:
+- compatible: "st,sti-keyscan"
+
+- reg: Register base address and size of st-keyscan controller.
+
+- interrupts: Interrupt number for the st-keyscan controller.
+
+- clocks: Must contain one entry, for the module clock.
+  See ../clocks/clock-bindings.txt for details.
+
+- pinctrl: Should specify pin control groups used for this controller.
+  See ../pinctrl/pinctrl-bindings.txt for details.
+
+- linux,keymap: The keymap for keys as described in the binding document
+  devicetree/bindings/input/matrix-keymap.txt.
+
+- keypad,num-rows: Number of row lines connected to the keypad controller.
+
+- keypad,num-columns: Number of column lines connected to the keypad
+  controller.
+
+Optional property:
+- st,debounce_us: Debouncing interval time in microseconds
+
+Example:
+
+keyscan: keyscan@fe4b0000 {
+       compatible = "st,sti-keyscan";
+       reg = <0xfe4b0000 0x2000>;
+       interrupts = <GIC_SPI 212 IRQ_TYPE_NONE>;
+       clocks  = <&CLK_SYSIN>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_keyscan>;
+
+       keypad,num-rows = <4>;
+       keypad,num-columns = <4>;
+       st,debounce_us = <5000>;
+
+       linux,keymap = < MATRIX_KEY(0x00, 0x00, KEY_F13)
+                        MATRIX_KEY(0x00, 0x01, KEY_F9)
+                        MATRIX_KEY(0x00, 0x02, KEY_F5)
+                        MATRIX_KEY(0x00, 0x03, KEY_F1)
+                        MATRIX_KEY(0x01, 0x00, KEY_F14)
+                        MATRIX_KEY(0x01, 0x01, KEY_F10)
+                        MATRIX_KEY(0x01, 0x02, KEY_F6)
+                        MATRIX_KEY(0x01, 0x03, KEY_F2)
+                        MATRIX_KEY(0x02, 0x00, KEY_F15)
+                        MATRIX_KEY(0x02, 0x01, KEY_F11)
+                        MATRIX_KEY(0x02, 0x02, KEY_F7)
+                        MATRIX_KEY(0x02, 0x03, KEY_F3)
+                        MATRIX_KEY(0x03, 0x00, KEY_F16)
+                        MATRIX_KEY(0x03, 0x01, KEY_F12)
+                        MATRIX_KEY(0x03, 0x02, KEY_F8)
+                        MATRIX_KEY(0x03, 0x03, KEY_F4) >;
+       };
index 653c90c34a71bdeae7f6029a4c4e0106300a98c8..1ee3bc09f31982d3bf554e22972e4a6768920501 100644 (file)
@@ -6,10 +6,11 @@ The actual devices are instantiated from the child nodes of a Device Bus node.
 
 Required properties:
 
- - compatible:          Currently only Armada 370/XP SoC are supported,
-                        with this compatible string:
+ - compatible:          Armada 370/XP SoC are supported using the
+                        "marvell,mvebu-devbus" compatible string.
 
-                        marvell,mvebu-devbus
+                        Orion5x SoC are supported using the
+                        "marvell,orion-devbus" compatible string.
 
  - reg:                 A resource specifier for the register space.
                         This is the base address of a chip select within
@@ -22,7 +23,14 @@ Required properties:
                         integer values for each chip-select line in use:
                         0 <physical address of mapping> <size>
 
-Mandatory timing properties for child nodes:
+Optional properties:
+
+ - devbus,keep-config   This property can optionally be used to keep
+                        using the timing parameters set by the
+                        bootloader. It makes all the timing properties
+                        described below unused.
+
+Timing properties for child nodes:
 
 Read parameters:
 
@@ -30,21 +38,26 @@ Read parameters:
                         drive the AD bus after the completion of a device read.
                         This prevents contentions on the Device Bus after a read
                         cycle from a slow device.
+                        Mandatory, except if devbus,keep-config is used.
 
- - devbus,bus-width:    Defines the bus width (e.g. <16>)
+ - devbus,bus-width:    Defines the bus width, in bits (e.g. <16>).
+                        Mandatory, except if devbus,keep-config is used.
 
  - devbus,badr-skew-ps: Defines the time delay from from A[2:0] toggle,
                         to read data sample. This parameter is useful for
                         synchronous pipelined devices, where the address
                         precedes the read data by one or two cycles.
+                        Mandatory, except if devbus,keep-config is used.
 
  - devbus,acc-first-ps: Defines the time delay from the negation of
                         ALE[0] to the cycle that the first read data is sampled
                         by the controller.
+                        Mandatory, except if devbus,keep-config is used.
 
  - devbus,acc-next-ps:  Defines the time delay between the cycle that
                         samples data N and the cycle that samples data N+1
                         (in burst accesses).
+                        Mandatory, except if devbus,keep-config is used.
 
  - devbus,rd-setup-ps:  Defines the time delay between DEV_CSn assertion to
                        DEV_OEn assertion. If set to 0 (default),
@@ -52,6 +65,8 @@ Read parameters:
                         This parameter has no affect on <acc-first-ps> parameter
                         (no affect on first data sample). Set <rd-setup-ps>
                         to a value smaller than <acc-first-ps>.
+                        Mandatory for "marvell,mvebu-devbus" compatible string,
+                        except if devbus,keep-config is used.
 
  - devbus,rd-hold-ps:   Defines the time between the last data sample to the
                        de-assertion of DEV_CSn. If set to 0 (default),
@@ -62,16 +77,20 @@ Read parameters:
                         last data sampled. Also this parameter has no
                         affect on <turn-off-ps> parameter.
                         Set <rd-hold-ps> to a value smaller than <turn-off-ps>.
+                        Mandatory for "marvell,mvebu-devbus" compatible string,
+                        except if devbus,keep-config is used.
 
 Write parameters:
 
  - devbus,ale-wr-ps:    Defines the time delay from the ALE[0] negation cycle
                        to the DEV_WEn assertion.
+                        Mandatory.
 
  - devbus,wr-low-ps:    Defines the time during which DEV_WEn is active.
                         A[2:0] and Data are kept valid as long as DEV_WEn
                         is active. This parameter defines the setup time of
                         address and data to DEV_WEn rise.
+                        Mandatory.
 
  - devbus,wr-high-ps:   Defines the time during which DEV_WEn is kept
                         inactive (high) between data beats of a burst write.
@@ -79,10 +98,13 @@ Write parameters:
                         <wr-high-ps> - <tick> ps.
                        This parameter defines the hold time of address and
                        data after DEV_WEn rise.
+                        Mandatory.
 
  - devbus,sync-enable: Synchronous device enable.
                        1: True
                        0: False
+                       Mandatory for "marvell,mvebu-devbus" compatible string,
+                       except if devbus,keep-config is used.
 
 An example for an Armada XP GP board, with a 16 MiB NOR device as child
 is showed below. Note that the Device Bus driver is in charge of allocating
index 1413f39912d3acc3fbb8b5557909557e7500a1c0..8aba48821a85a3284ac92a31c2c401922fad3744 100644 (file)
@@ -10,6 +10,9 @@ Optional properties:
 - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
 
 Sub-nodes:
+- codec: Contain the Audio Codec node.
+  - adc-port: Contain PMIC SSI port number used for ADC.
+  - dac-port: Contain PMIC SSI port number used for DAC.
 - leds : Contain the led nodes and initial register values in property
   "led-control". Number of register depends of used IC, for MC13783 is 6,
   for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of
index 802e839b08294f6ef5f54c561b03c1981e395f0c..d81ba30c0d8bd628bad8f11e3471f0b9146386b3 100644 (file)
@@ -56,6 +56,20 @@ 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]
 
+On S2MPS14 the LDO10, LDO11 and LDO12 can be configured to external control
+over GPIO. To turn this feature on this property must be added to the regulator
+sub-node:
+       - samsung,ext-control-gpios: GPIO specifier for one GPIO
+               controlling this regulator (enable/disable);
+Example:
+       LDO12 {
+               regulator-name = "V_EMMC_2.8V";
+               regulator-min-microvolt = <2800000>;
+               regulator-max-microvolt = <2800000>;
+               samsung,ext-control-gpios = <&gpk0 2 0>;
+       };
+
+
 The regulator constraints inside the regulator nodes use the standard regulator
 bindings which are documented elsewhere.
 
index 8f3f13315358028f20a5a79720e6a27266caf2be..2d4a7258a10db9d2c30dc808bb7b5ad5e74fa994 100644 (file)
@@ -69,10 +69,6 @@ Optional properties:
 
 * supports-highspeed: Enables support for high speed cards (up to 50MHz)
 
-* caps2-mmc-hs200-1_8v: Supports mmc HS200 SDR 1.8V mode
-
-* caps2-mmc-hs200-1_2v: Supports mmc HS200 SDR 1.2V mode
-
 * broken-cd: as documented in mmc core bindings.
 
 * vmmc-supply: The phandle to the regulator to use for vmmc.  If this is
@@ -103,7 +99,6 @@ board specific portions as listed below.
                clock-freq-min-max = <400000 200000000>;
                num-slots = <1>;
                supports-highspeed;
-               caps2-mmc-hs200-1_8v;
                broken-cd;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
new file mode 100644 (file)
index 0000000..823d134
--- /dev/null
@@ -0,0 +1,35 @@
+* Freescale Quad Serial Peripheral Interface(QuadSPI)
+
+Required properties:
+  - compatible : Should be "fsl,vf610-qspi"
+  - reg : the first contains the register location and length,
+          the second contains the memory mapping address and length
+  - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
+  - interrupts : Should contain the interrupt for the device
+  - clocks : The clocks needed by the QuadSPI controller
+  - clock-names : the name of the clocks
+
+Optional properties:
+  - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B.
+                              Each bus can be connected with two NOR flashes.
+                             Most of the time, each bus only has one NOR flash
+                             connected, this is the default case.
+                             But if there are two NOR flashes connected to the
+                             bus, you should enable this property.
+                             (Please check the board's schematic.)
+
+Example:
+
+qspi0: quadspi@40044000 {
+       compatible = "fsl,vf610-qspi";
+       reg = <0x40044000 0x1000>, <0x20000000 0x10000000>;
+       reg-names = "QuadSPI", "QuadSPI-memory";
+       interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&clks VF610_CLK_QSPI0_EN>,
+               <&clks VF610_CLK_QSPI0>;
+       clock-names = "qspi_en", "qspi";
+
+       flash0: s25fl128s@0 {
+               ....
+       };
+};
index 7fbb027218a126002312a829c6cd273ac715b030..a1d71eb43b209485ac7bec4832119f25fe68a49e 100644 (file)
@@ -4,11 +4,15 @@ Required properties:
 - compatible: Should be "snps,arc-emac"
 - reg: Address and length of the register set for the device
 - interrupts: Should contain the EMAC interrupts
-- clock-frequency: CPU frequency. It is needed to calculate and set polling
-period of EMAC.
 - max-speed: see ethernet.txt file in the same directory.
 - phy: see ethernet.txt file in the same directory.
 
+Clock handling:
+The clock frequency is needed to calculate and set polling period of EMAC.
+It must be provided by one of:
+- clock-frequency: CPU frequency.
+- clocks: reference to the clock supplying the EMAC.
+
 Child nodes of the driver are the individual PHY devices connected to the
 MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus.
 
@@ -19,7 +23,11 @@ Examples:
                reg = <0xc0fc2000 0x3c>;
                interrupts = <6>;
                mac-address = [ 00 11 22 33 44 55 ];
+
                clock-frequency = <80000000>;
+               /* or */
+               clocks = <&emac_clock>;
+
                max-speed = <100>;
                phy = <&phy0>;
 
diff --git a/Documentation/devicetree/bindings/net/broadcom-systemport.txt b/Documentation/devicetree/bindings/net/broadcom-systemport.txt
new file mode 100644 (file)
index 0000000..1b7600e
--- /dev/null
@@ -0,0 +1,29 @@
+* Broadcom BCM7xxx Ethernet Systemport Controller (SYSTEMPORT)
+
+Required properties:
+- compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport"
+- reg: address and length of the register set for the device.
+- interrupts: interrupts for the device, first cell must be for the the rx
+  interrupts, and the second cell should be for the transmit queues
+- local-mac-address: Ethernet MAC address (48 bits) of this adapter
+- phy-mode: Should be a string describing the PHY interface to the
+  Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt
+- fixed-link: see Documentation/devicetree/bindings/net/fsl-tsec-phy.txt for
+  the property specific details
+
+Optional properties:
+- systemport,num-tier2-arb: number of tier 2 arbiters, an integer
+- systemport,num-tier1-arb: number of tier 1 arbiters, an integer
+- systemport,num-txq: number of HW transmit queues, an integer
+- systemport,num-rxq: number of HW receive queues, an integer
+
+Example:
+ethernet@f04a0000 {
+       compatible = "brcm,systemport-v1.00";
+       reg = <0xf04a0000 0x4650>;
+       local-mac-address = [ 00 11 22 33 44 55 ];
+       fixed-link = <0 1 1000 0 0>;
+       phy-mode = "gmii";
+       interrupts = <0x0 0x16 0x0>,
+               <0x0 0x17 0x0>;
+};
diff --git a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt
new file mode 100644 (file)
index 0000000..d3bbdde
--- /dev/null
@@ -0,0 +1,23 @@
+* AT86RF230 IEEE 802.15.4 *
+
+Required properties:
+  - compatible:                should be "atmel,at86rf230", "atmel,at86rf231",
+                       "atmel,at86rf233" or "atmel,at86rf212"
+  - spi-max-frequency: maximal bus speed, should be set to 7500000 depends
+                       sync or async operation mode
+  - reg:               the chipselect index
+  - interrupts:                the interrupt generated by the device
+
+Optional properties:
+  - reset-gpio:                GPIO spec for the rstn pin
+  - sleep-gpio:                GPIO spec for the slp_tr pin
+
+Example:
+
+       at86rf231@0 {
+               compatible = "atmel,at86rf231";
+               spi-max-frequency = <7500000>;
+               reg = <0>;
+               interrupts = <19 1>;
+               interrupt-parent = <&gpio3>;
+       };
index 636f0ac4e22388b4c8934681f7a7fc3712d30a0f..2a60cd3e8d5ddb7bdf3b2caad2bc414a3d8566e0 100644 (file)
@@ -23,5 +23,5 @@ gmac0: ethernet@ff700000 {
        interrupt-names = "macirq";
        mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */
        clocks = <&emac_0_clk>;
-       clocks-names = "stmmaceth";
+       clock-names = "stmmaceth";
 };
index 80c1fb8bfbb8bd778a6682fa75d863ce51d3c0e4..a2acd2b26baf78c8aafc3948d7dc7cb012c09db5 100644 (file)
@@ -33,7 +33,7 @@ Optional properties:
 - max-frame-size: See ethernet.txt file in the same directory
 - clocks: If present, the first clock should be the GMAC main clock,
   further clocks may be specified in derived bindings.
-- clocks-names: One name for each entry in the clocks property, the
+- clock-names: One name for each entry in the clocks property, the
   first one should be "stmmaceth".
 
 Examples:
diff --git a/Documentation/devicetree/bindings/net/via-rhine.txt b/Documentation/devicetree/bindings/net/via-rhine.txt
new file mode 100644 (file)
index 0000000..334eca2
--- /dev/null
@@ -0,0 +1,17 @@
+* VIA Rhine 10/100 Network Controller
+
+Required properties:
+- compatible : Should be "via,vt8500-rhine" for integrated
+       Rhine controllers found in VIA VT8500, WonderMedia WM8950
+       and similar. These are listed as 1106:3106 rev. 0x84 on the
+       virtual PCI bus under vendor-provided kernels
+- reg : Address and length of the io space
+- interrupts : Should contain the controller interrupt line
+
+Examples:
+
+ethernet@d8004000 {
+       compatible = "via,vt8500-rhine";
+       reg = <0xd8004000 0x100>;
+       interrupts = <10>;
+};
index 4bd5be0e5e7dd51eaf7cf23a92a2bf884dd264f1..26bcb18f4e609288d006eeae5bbf496730e2921f 100644 (file)
@@ -83,7 +83,7 @@ Example:
                reg             = <0xfe61f080 0x4>;
                reg-names       = "irqmux";
                interrupts      = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
-               interrupts-names = "irqmux";
+               interrupt-names = "irqmux";
                ranges          = <0 0xfe610000 0x5000>;
 
                PIO0: gpio@fe610000 {
@@ -165,7 +165,7 @@ sdhci0:sdhci@fe810000{
        interrupt-parent = <&PIO3>;
        #interrupt-cells = <2>;
        interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; /* Interrupt line via PIO3-3 */
-       interrupts-names = "card-detect";
+       interrupt-names = "card-detect";
        pinctrl-names = "default";
        pinctrl-0       = <&pinctrl_mmc>;
 };
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt b/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt
new file mode 100644 (file)
index 0000000..db93921
--- /dev/null
@@ -0,0 +1,54 @@
+
+IBM Akebono board device tree
+=============================
+
+The IBM Akebono board is a development board for the PPC476GTR SoC.
+
+0) The root node
+
+   Required properties:
+
+   - model : "ibm,akebono".
+   - compatible : "ibm,akebono" , "ibm,476gtr".
+
+1.a) The Secure Digital Host Controller Interface (SDHCI) node
+
+  Represent the Secure Digital Host Controller Interfaces.
+
+  Required properties:
+
+   - compatible : should be "ibm,476gtr-sdhci","generic-sdhci".
+   - reg : should contain the SDHCI registers location and length.
+   - interrupt-parent : a phandle for the interrupt controller.
+   - interrupts : should contain the SDHCI interrupt.
+
+1.b) The Advanced Host Controller Interface (AHCI) SATA node
+
+  Represents the advanced host controller SATA interface.
+
+  Required properties:
+
+   - compatible : should be "ibm,476gtr-ahci".
+   - reg : should contain the AHCI registers location and length.
+   - interrupt-parent : a phandle for the interrupt controller.
+   - interrupts : should contain the AHCI interrupt.
+
+1.c) The FPGA node
+
+  The Akebono board stores some board information such as the revision
+  number in an FPGA which is represented by this node.
+
+  Required properties:
+
+   - compatible : should be "ibm,akebono-fpga".
+   - reg : should contain the FPGA registers location and length.
+
+1.d) The AVR node
+
+  The Akebono board has an Atmel AVR microprocessor attached to the I2C
+  bus as a power controller for the board.
+
+  Required properties:
+
+   - compatible : should be "ibm,akebono-avr".
+   - reg : should contain the I2C bus address for the AVR.
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt b/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt
new file mode 100644 (file)
index 0000000..c737c83
--- /dev/null
@@ -0,0 +1,19 @@
+
+ppc476gtr High Speed Serial Assist (HSTA) node
+==============================================
+
+The 476gtr SoC contains a high speed serial assist module attached
+between the plb4 and plb6 system buses to provide high speed data
+transfer between memory and system peripherals as well as support for
+PCI message signalled interrupts.
+
+Currently only the MSI support is used by Linux using the following
+device tree entries:
+
+Require properties:
+- compatible           : "ibm,476gtr-hsta-msi", "ibm,hsta-msi"
+- reg                  : register mapping for the HSTA MSI space
+- interrupt-parent     : parent controller for mapping interrupts
+- interrupts           : ordered interrupt mapping for each MSI in the register
+                         space. The first interrupt should be associated with a
+                         register offset of 0x00, the second to 0x10, etc.
index 313a60ba61d8e61667bad2f627d738433f7854c8..340980239ea9f7e1fb35f59da3ebcc0bf5b96ef8 100644 (file)
@@ -21,6 +21,10 @@ Optional properties:
   number should be provided. If it is externally controlled and no GPIO
   entry then driver will just configure this rails as external control
   and will not provide any enable/disable APIs.
+- ti,overcurrent-wait: This is applicable to FET registers, which have a
+  poorly defined "overcurrent wait" field.  If this property is present it
+  should be between 0 - 3.  If this property isn't present we won't touch the
+  "overcurrent wait" field and we'll leave it to the BIOS/EC to deal with.
 
 Each regulator is defined using the standard binding for regulators.
 
index b902ee39cf8973bae24217f329c5c24ab8d012bb..deca5e18f304bd2a45723acd4579959a6fe8ce61 100644 (file)
@@ -8,6 +8,8 @@ Required properties:
 
   - reg : The chip select number on the SPI bus
 
+  - vdd-supply : A regulator node, providing 2.7V - 3.6V
+
 Optional properties:
 
   - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
@@ -19,4 +21,5 @@ spdif: ak4104@0 {
        compatible = "asahi-kasei,ak4104";
        reg = <0>;
        spi-max-frequency = <5000000>;
+       vdd-supply = <&vdd_3v3_reg>;
 };
index 569b26c4a81ee25e1f141329f90903dcb28ab4e4..60ca07996458576e2fcc6f85a334e13fcec5a2c7 100644 (file)
@@ -47,7 +47,7 @@ mcasp0: mcasp0@1d00000 {
        reg = <0x100000 0x3000>;
        reg-names "mpu";
        interrupts = <82>, <83>;
-       interrupts-names = "tx", "rx";
+       interrupt-names = "tx", "rx";
        op-mode = <0>;          /* MCASP_IIS_MODE */
        tdm-slots = <2>;
        serial-dir = <
index 98611a6761c0ad0a5f8dc9e354442918238cb762..0f4e23828190f7bda8d9b829ab7410276b2ead5f 100644 (file)
@@ -7,10 +7,11 @@ codec/DSP interfaces.
 
 
 Required properties:
-- compatible: Compatible list, contains "fsl,vf610-sai".
+- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai".
 - reg: Offset and length of the register set for the device.
 - clocks: Must contain an entry for each entry in clock-names.
-- clock-names : Must include the "sai" entry.
+- clock-names : Must include the "bus" for register access and "mclk1" "mclk2"
+  "mclk3" for bit clock and frame clock providing.
 - dmas : Generic dma devicetree binding as described in
   Documentation/devicetree/bindings/dma/dma.txt.
 - dma-names : Two dmas have to be defined, "tx" and "rx".
@@ -30,8 +31,10 @@ sai2: sai@40031000 {
              reg = <0x40031000 0x1000>;
              pinctrl-names = "default";
              pinctrl-0 = <&pinctrl_sai2_1>;
-             clocks = <&clks VF610_CLK_SAI2>;
-             clock-names = "sai";
+             clocks = <&clks VF610_CLK_PLATFORM_BUS>,
+                    <&clks VF610_CLK_SAI2>,
+                    <&clks 0>, <&clks 0>;
+             clock-names = "bus", "mclk1", "mclk2", "mclk3";
              dma-names = "tx", "rx";
              dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
                   <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
diff --git a/Documentation/devicetree/bindings/sound/max98095.txt b/Documentation/devicetree/bindings/sound/max98095.txt
new file mode 100644 (file)
index 0000000..bacbeaa
--- /dev/null
@@ -0,0 +1,16 @@
+MAX98095 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "maxim,max98095".
+
+- reg : The I2C address of the device.
+
+Example:
+
+max98095: codec@11 {
+       compatible = "maxim,max98095";
+       reg = <0x11>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nokia,rx51.txt b/Documentation/devicetree/bindings/sound/nokia,rx51.txt
new file mode 100644 (file)
index 0000000..72f93d9
--- /dev/null
@@ -0,0 +1,27 @@
+* Nokia N900 audio setup
+
+Required properties:
+- compatible: Should contain "nokia,n900-audio"
+- nokia,cpu-dai: phandle for the McBSP node
+- nokia,audio-codec: phandles for the main TLV320AIC3X node and the
+                     auxiliary TLV320AIC3X node (in this order)
+- nokia,headphone-amplifier: phandle for the TPA6130A2 node
+- tvout-selection-gpios: GPIO for tvout selection
+- jack-detection-gpios: GPIO for jack detection
+- eci-switch-gpios: GPIO for ECI (Enhancement Control Interface) switch
+- speaker-amplifier-gpios: GPIO for speaker amplifier
+
+Example:
+
+sound {
+       compatible = "nokia,n900-audio";
+
+       nokia,cpu-dai = <&mcbsp2>;
+       nokia,audio-codec = <&tlv320aic3x>, <&tlv320aic3x_aux>;
+       nokia,headphone-amplifier = <&tpa6130a2>;
+
+       tvout-selection-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>; /* 40 */
+       jack-detection-gpios = <&gpio6 17 GPIO_ACTIVE_HIGH>; /* 177 */
+       eci-switch-gpios = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* 182 */
+       speaker-amplifier-gpios = <&twl_gpio 7 GPIO_ACTIVE_HIGH>;
+};
index 068a1141b06f19de0f5206e97de40f0af6793812..bac4d9ac1edc8c45df26134e59c9537b1ce6b3af 100644 (file)
@@ -1,10 +1,10 @@
-RT5640 audio CODEC
+RT5640/RT5639 audio CODEC
 
 This device supports I2C only.
 
 Required properties:
 
-- compatible : "realtek,rt5640".
+- compatible : One of "realtek,rt5640" or "realtek,rt5639".
 
 - reg : The I2C address of the device.
 
@@ -18,7 +18,7 @@ Optional properties:
 
 - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
 
-Pins on the device (for linking into audio routes):
+Pins on the device (for linking into audio routes) for RT5639/RT5640:
 
   * DMIC1
   * DMIC2
@@ -31,13 +31,16 @@ Pins on the device (for linking into audio routes):
   * HPOR
   * LOUTL
   * LOUTR
-  * MONOP
-  * MONON
   * SPOLP
   * SPOLN
   * SPORP
   * SPORN
 
+Additional pins on the device for RT5640:
+
+  * MONOP
+  * MONON
+
 Example:
 
 rt5640 {
index 131aa2ad7f1a3120d6ebeef6492c466f87ab461b..9b9df146fd1a5299799bb90c60270fb42cea1e46 100644 (file)
@@ -1,6 +1,6 @@
 Simple-Card:
 
-Simple-Card specifies audio DAI connection of SoC <-> codec.
+Simple-Card specifies audio DAI connections of SoC <-> codec.
 
 Required properties:
 
@@ -10,26 +10,51 @@ Optional properties:
 
 - simple-audio-card,name               : User specified audio sound card name, one string
                                          property.
-- simple-audio-card,format             : CPU/CODEC common audio format.
-                                         "i2s", "right_j", "left_j" , "dsp_a"
-                                         "dsp_b", "ac97", "pdm", "msb", "lsb"
 - simple-audio-card,widgets            : Please refer to widgets.txt.
 - simple-audio-card,routing            : A list of the connections between audio components.
                                          Each entry is a pair of strings, the first being the
                                          connection's sink, the second being the connection's
                                          source.
-- dai-tdm-slot-num                     : Please refer to tdm-slot.txt.
-- dai-tdm-slot-width                   : Please refer to tdm-slot.txt.
+Optional subnodes:
+
+- simple-audio-card,dai-link           : Container for dai-link level
+                                         properties and the CPU and CODEC
+                                         sub-nodes. This container may be
+                                         omitted when the card has only one
+                                         DAI link. See the examples and the
+                                         section bellow.
+
+Dai-link subnode properties and subnodes:
+
+If dai-link subnode is omitted and the subnode properties are directly
+under "sound"-node the subnode property and subnode names have to be
+prefixed with "simple-audio-card,"-prefix.
 
-Required subnodes:
+Required dai-link subnodes:
 
-- simple-audio-card,dai-link           : container for the CPU and CODEC sub-nodes
-                                         This container may be omitted when the
-                                         card has only one DAI link.
-                                         See the examples.
+- cpu                                  : CPU   sub-node
+- codec                                        : CODEC sub-node
 
-- simple-audio-card,cpu                        : CPU   sub-node
-- simple-audio-card,codec              : CODEC sub-node
+Optional dai-link subnode properties:
+
+- format                               : CPU/CODEC common audio format.
+                                         "i2s", "right_j", "left_j" , "dsp_a"
+                                         "dsp_b", "ac97", "pdm", "msb", "lsb"
+- frame-master                         : Indicates dai-link frame master.
+                                         phandle to a cpu or codec subnode.
+- bitclock-master                      : Indicates dai-link bit clock master.
+                                         phandle to a cpu or codec subnode.
+- bitclock-inversion                   : bool property. Add this if the
+                                         dai-link uses bit clock inversion.
+- frame-inversion                      : bool property. Add this if the
+                                         dai-link uses frame clock inversion.
+
+For backward compatibility the frame-master and bitclock-master
+properties can be used as booleans in codec subnode to indicate if the
+codec is the dai-link frame or bit clock master. In this case there
+should be no dai-link node, the same properties should not be present
+at sound-node level, and the bitclock-inversion and frame-inversion
+properties should also be placed in the codec node if needed.
 
 Required CPU/CODEC subnodes properties:
 
@@ -37,29 +62,21 @@ Required CPU/CODEC subnodes properties:
 
 Optional CPU/CODEC subnodes properties:
 
-- format                               : CPU/CODEC specific audio format if needed.
-                                         see simple-audio-card,format
-- frame-master                         : bool property. add this if subnode is frame master
-- bitclock-master                      : bool property. add this if subnode is bitclock master
-- bitclock-inversion                   : bool property. add this if subnode has clock inversion
-- frame-inversion                      : bool property. add this if subnode has frame inversion
+- dai-tdm-slot-num                     : Please refer to tdm-slot.txt.
+- dai-tdm-slot-width                   : Please refer to tdm-slot.txt.
 - clocks / system-clock-frequency      : specify subnode's clock if needed.
                                          it can be specified via "clocks" if system has
                                          clock node (= common clock), or "system-clock-frequency"
                                          (if system doens't support common clock)
 
-Note:
- * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
-   'frame-inversion', the simple card will use the settings of CODEC for both
-   CPU and CODEC sides as we need to keep the settings identical for both ends
-   of the link.
-
 Example 1 - single DAI link:
 
 sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "VF610-Tower-Sound-Card";
        simple-audio-card,format = "left_j";
+       simple-audio-card,bitclock-master = <&dailink0_master>;
+       simple-audio-card,frame-master = <&dailink0_master>;
        simple-audio-card,widgets =
                "Microphone", "Microphone Jack",
                "Headphone", "Headphone Jack",
@@ -69,17 +86,12 @@ sound {
                "Headphone Jack", "HP_OUT",
                "External Speaker", "LINE_OUT";
 
-       dai-tdm-slot-num = <2>;
-       dai-tdm-slot-width = <8>;
-
        simple-audio-card,cpu {
                sound-dai = <&sh_fsi2 0>;
        };
 
-       simple-audio-card,codec {
+       dailink0_master: simple-audio-card,codec {
                sound-dai = <&ak4648>;
-               bitclock-master;
-               frame-master;
                clocks = <&osc>;
        };
 };
@@ -105,31 +117,31 @@ Example 2 - many DAI links:
 sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "Cubox Audio";
-       simple-audio-card,format = "i2s";
 
        simple-audio-card,dai-link@0 {          /* I2S - HDMI */
-               simple-audio-card,cpu {
+               format = "i2s";
+               cpu {
                        sound-dai = <&audio1 0>;
                };
-               simple-audio-card,codec {
+               codec {
                        sound-dai = <&tda998x 0>;
                };
        };
 
        simple-audio-card,dai-link@1 {          /* S/PDIF - HDMI */
-               simple-audio-card,cpu {
+               cpu {
                        sound-dai = <&audio1 1>;
                };
-               simple-audio-card,codec {
+               codec {
                        sound-dai = <&tda998x 1>;
                };
        };
 
        simple-audio-card,dai-link@2 {          /* S/PDIF - S/PDIF */
-               simple-audio-card,cpu {
+               cpu {
                        sound-dai = <&audio1 1>;
                };
-               simple-audio-card,codec {
+               codec {
                        sound-dai = <&spdif_codec>;
                };
        };
diff --git a/Documentation/devicetree/bindings/sound/snow.txt b/Documentation/devicetree/bindings/sound/snow.txt
new file mode 100644 (file)
index 0000000..678b191
--- /dev/null
@@ -0,0 +1,17 @@
+Audio Binding for Snow boards
+
+Required properties:
+- compatible : Can be one of the following,
+                       "google,snow-audio-max98090" or
+                       "google,snow-audio-max98095"
+- samsung,i2s-controller: The phandle of the Samsung I2S controller
+- samsung,audio-codec: The phandle of the audio codec
+
+Example:
+
+sound {
+               compatible = "google,snow-audio-max98095";
+
+               samsung,i2s-controller = <&i2s0>;
+               samsung,audio-codec = <&max98095>;
+};
diff --git a/Documentation/devicetree/bindings/sound/st,sta350.txt b/Documentation/devicetree/bindings/sound/st,sta350.txt
new file mode 100644 (file)
index 0000000..9501888
--- /dev/null
@@ -0,0 +1,107 @@
+STA350 audio CODEC
+
+The driver for this device only supports I2C.
+
+Required properties:
+
+  - compatible: "st,sta350"
+  - reg: the I2C address of the device for I2C
+  - reset-gpios: a GPIO spec for the reset pin. If specified, it will be
+                deasserted before communication to the codec starts.
+
+  - power-down-gpios: a GPIO spec for the power down pin. If specified,
+                     it will be deasserted before communication to the codec
+                     starts.
+
+  - vdd-dig-supply: regulator spec, providing 3.3V
+  - vdd-pll-supply: regulator spec, providing 3.3V
+  - vcc-supply: regulator spec, providing 5V - 26V
+
+Optional properties:
+
+  -  st,output-conf: number, Selects the output configuration:
+       0: 2-channel (full-bridge) power, 2-channel data-out
+       1: 2 (half-bridge). 1 (full-bridge) on-board power
+       2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
+       3: 1 Channel Mono-Parallel
+       If parameter is missing, mode 0 will be enabled.
+
+  -  st,ch1-output-mapping: Channel 1 output mapping
+  -  st,ch2-output-mapping: Channel 2 output mapping
+  -  st,ch3-output-mapping: Channel 3 output mapping
+       0: Channel 1
+       1: Channel 2
+       2: Channel 3
+       If parameter is missing, channel 1 is choosen.
+
+  -  st,thermal-warning-recover:
+       If present, thermal warning recovery is enabled.
+
+  -  st,thermal-warning-adjustment:
+       If present, thermal warning adjustment is enabled.
+
+  -  st,fault-detect-recovery:
+       If present, then fault recovery will be enabled.
+
+  -  st,ffx-power-output-mode: string
+       The FFX power output mode selects how the FFX output timing is
+       configured. Must be one of these values:
+         -  "drop-compensation"
+         -  "tapered-compensation"
+         -  "full-power-mode"
+         -  "variable-drop-compensation" (default)
+
+  -  st,drop-compensation-ns: number
+       Only required for "st,ffx-power-output-mode" ==
+       "variable-drop-compensation".
+       Specifies the drop compensation in nanoseconds.
+       The value must be in the range of 0..300, and only
+       multiples of 20 are allowed. Default is 140ns.
+
+  -  st,overcurrent-warning-adjustment:
+       If present, overcurrent warning adjustment is enabled.
+
+  -  st,max-power-use-mpcc:
+       If present, then MPCC bits are used for MPC coefficients,
+       otherwise standard MPC coefficients are used.
+
+  -  st,max-power-corr:
+       If present, power bridge correction for THD reduction near maximum
+       power output is enabled.
+
+  -  st,am-reduction-mode:
+       If present, FFX mode runs in AM reduction mode, otherwise normal
+       FFX mode is used.
+
+  -  st,odd-pwm-speed-mode:
+       If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
+       channels. If not present, normal PWM spped mode (384 kHz) will be used.
+
+  -  st,distortion-compensation:
+       If present, distortion compensation variable uses DCC coefficient.
+       If not present, preset DC coefficient is used.
+
+  -  st,invalid-input-detect-mute:
+       If not present, automatic invalid input detect mute is enabled.
+
+
+
+Example:
+
+codec: sta350@38 {
+       compatible = "st,sta350";
+       reg = <0x1c>;
+       reset-gpios = <&gpio1 19 0>;
+       power-down-gpios = <&gpio1 16 0>;
+       st,output-conf = <0x3>;                 // set output to 2-channel
+                                               // (full-bridge) power,
+                                               // 2-channel data-out
+       st,ch1-output-mapping = <0>;            // set channel 1 output ch 1
+       st,ch2-output-mapping = <0>;            // set channel 2 output ch 1
+       st,ch3-output-mapping = <0>;            // set channel 3 output ch 1
+       st,max-power-correction;                // enables power bridge
+                                               // correction for THD reduction
+                                               // near maximum power output
+       st,invalid-input-detect-mute;           // mute if no valid digital
+                                               // audio signal is provided.
+};
index 74c66dee3e146445b5b1593670dc52473f527165..eff12be5e789cf91bb4a5d4a21bab7f7d1b7d32c 100644 (file)
@@ -13,6 +13,9 @@ Required properties:
     "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
 
 - reg - <int> -  I2C slave address
+- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
+  DVDD-supply : power supplies for the device as covered in
+  Documentation/devicetree/bindings/regulator/regulator.txt
 
 
 Optional properties:
@@ -24,9 +27,6 @@ Optional properties:
         3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
        If this node is not mentioned or if the value is unknown, then
        micbias is set to 2.0V.
-- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
-  DVDD-supply : power supplies for the device as covered in
-  Documentation/devicetree/bindings/regulator/regulator.txt
 
 CODEC output pins:
   * HPL
index abc308083acb204c7625c5d53ed58d546c65f755..285500407a437ffa1d319176255599b70428ed1f 100644 (file)
@@ -123,6 +123,7 @@ stericsson  ST-Ericsson
 synology       Synology, Inc.
 ti     Texas Instruments
 tlm    Trusted Logic Mobility
+toradex        Toradex AG
 toshiba        Toshiba Corporation
 toumaz Toumaz
 usi    Universal Scientifc Industrial Co., Ltd.
index 4f7897e99cba8a8fc7b5a33343825cfb94ce2d68..c74e04494ade32bd60b0cef1aafe725352afb0ca 100644 (file)
@@ -308,3 +308,8 @@ SLAVE DMA ENGINE
 
 SPI
   devm_spi_register_master()
+
+MDIO
+  devm_mdiobus_alloc()
+  devm_mdiobus_alloc_size()
+  devm_mdiobus_free()
index eba7901342531d2dc089c9a39d990aa924b86526..9b0d5a33c8bf70435826e261d3bc402aab7f0272 100644 (file)
@@ -196,8 +196,7 @@ prototypes:
        void (*invalidatepage) (struct page *, unsigned int, unsigned int);
        int (*releasepage) (struct page *, int);
        void (*freepage)(struct page *);
-       int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
-                       loff_t offset, unsigned long nr_segs);
+       int (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset);
        int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **,
                                unsigned long *);
        int (*migratepage)(struct address_space *, struct page *, struct page *);
index 617f6d70c0778ce37716d25fde6f0c158f492707..1846374a5add54a611da1be291aad96573baa444 100644 (file)
@@ -589,8 +589,7 @@ struct address_space_operations {
        void (*invalidatepage) (struct page *, unsigned int, unsigned int);
        int (*releasepage) (struct page *, int);
        void (*freepage)(struct page *);
-       ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
-                       loff_t offset, unsigned long nr_segs);
+       ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset);
        struct page* (*get_xip_page)(struct address_space *, sector_t,
                        int);
        /* migrate the contents of a page to the specified target */
index 57c3a46d637096c485e31556dba357c2415d1866..bfc915fe3639e83183e283ce8d22cf979747ceb5 100644 (file)
@@ -18,5 +18,21 @@ sensor incorporates a band-gap type temperature sensor,
 10-bit ADC, and a digital comparator with user-programmable upper
 and lower limit values.
 
-Limits can be set through the Overtemperature Shutdown register and
-Hysteresis register.
+The LM77 implements 3 limits: low (temp1_min), high (temp1_max) and
+critical (temp1_crit.) It also implements an hysteresis mechanism which
+applies to all 3 limits. The relative difference is stored in a single
+register on the chip, which means that the relative difference between
+the limit and its hysteresis is always the same for all 3 limits.
+
+This implementation detail implies the following:
+* When setting a limit, its hysteresis will automatically follow, the
+  difference staying unchanged. For example, if the old critical limit
+  was 80 degrees C, and the hysteresis was 75 degrees C, and you change
+  the critical limit to 90 degrees C, then the hysteresis will
+  automatically change to 85 degrees C.
+* All 3 hysteresis can't be set independently. We decided to make
+  temp1_crit_hyst writable, while temp1_min_hyst and temp1_max_hyst are
+  read-only. Setting temp1_crit_hyst writes the difference between
+  temp1_crit_hyst and temp1_crit into the chip, and the same relative
+  hysteresis applies automatically to the low and high limits.
+* The limits should be set before the hysteresis.
index 43842177b771d72e67e90361f79b28966435787f..60a278948652fc019750b9b7c473fd1c0318a729 100644 (file)
@@ -237,7 +237,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        This feature is enabled by default.
                        This option allows to turn off the feature.
 
-       acpi_no_auto_ssdt       [HW,ACPI] Disable automatic loading of SSDT
+       acpi_no_static_ssdt     [HW,ACPI]
+                       Disable installation of static SSDTs at early boot time
+                       By default, SSDTs contained in the RSDT/XSDT will be
+                       installed automatically and they will appear under
+                       /sys/firmware/acpi/tables.
+                       This option turns off this feature.
+                       Note that specifying this option does not affect
+                       dynamic table installation which will install SSDT
+                       tables to /sys/firmware/acpi/tables/dynamic.
 
        acpica_no_return_repair [HW, ACPI]
                        Disable AML predefined validation mechanism
diff --git a/Documentation/lto-build b/Documentation/lto-build
new file mode 100644 (file)
index 0000000..5dcce1e
--- /dev/null
@@ -0,0 +1,173 @@
+Link time optimization (LTO) for the Linux kernel
+
+This is an experimental feature.
+
+Link Time Optimization allows the compiler to optimize the complete program
+instead of just each file.  LTO requires at least gcc 4.8 (but
+works more efficiently with 4.9+) LTO requires Linux binutils (the normal FSF
+releases used in many distributions do not work at the moment)
+
+The compiler can inline functions between files and do various other global
+optimizations, like specializing functions for common parameters,
+determing when global variables are clobbered, making functions pure/const,
+propagating constants globally, removing unneeded data and others.
+
+It will also drop unused functions which can make the kernel
+image smaller in some circumstances, in particular for small kernel
+configurations.
+
+For small monolithic kernels it can throw away unused code very effectively
+(especially when modules are disabled) and usually shrinks
+the code size.
+
+Build time and memory consumption at build time will increase, depending
+on the size of the largest binary. Modular kernels are less affected.
+With LTO incremental builds are less incremental, as always the whole
+binary needs to be re-optimized (but not re-parsed)
+
+Oops can be somewhat more difficult to read, due to the more aggressive
+inlining.
+
+Normal "reasonable" builds work with less than 4GB of RAM, but very large
+configurations like allyesconfig may need more memory. The actual
+memory needed depends on the available memory (gcc sizes its garbage
+collector pools based on that or on the ulimit -m limits) and
+the compiler version.
+
+gcc 4.9+ has much better build performance and less memory consumption
+
+- A few kernel features are currently incompatible with LTO, in particular
+function tracing, because they require special compiler flags for
+specific files, which is not supported in LTO right now.
+- Jobserver control for -j does not work correctly for the final
+LTO phase due to some problems with the kernel's pipe code.
+The makefiles hard codes -j<number of online cpus> for the final
+LTO phase to work around for this
+
+Configuration:
+- Enable CONFIG_LTO_MENU and then disable CONFIG_LTO_DISABLE.
+This is mainly to not have allyesconfig default to LTO.
+- FUNCTION_TRACER, STACK_TRACER, FUNCTION_GRAPH_TRACER, KALLSYMS_ALL, GCOV
+have to disabled because they are currently incompatible with LTO.
+- MODVERSIONS have to be disabled (may work with 4.9+)
+
+Requirements:
+- Enough memory: 4GB for a standard build, more for allyesconfig
+The peak memory usage happens single threaded (when lto-wpa merges types),
+so dialing back -j options will not help much.
+
+A 32bit compiler is unlikely to work due to the memory requirements.
+You can however build a kernel targeted at 32bit on a 64bit host.
+
+Example build procedure:
+
+Simplified procedure for distributions that have gcc 4.8, but not
+the Linux binutils (for example openSUSE 13.1 or FC20):
+
+The LTO builds requires gcc-nm/gcc-ar. Some distributions ship
+those in separate packages, which may need to be explicitely installed.
+
+- Get the latest Linux binutils from
+http://www.kernel.org/pub/linux/devel/binutils/
+and unpack it.
+
+We install it in a separate directory to not overwrite the system binutils.
+
+# replace VERSION with respective version numbers
+
+cd binutils*
+# don't forget the --enable-plugins!
+./configure --prefix=/opt/binutils-VERSION --enable-plugins
+make -j $(getconf _NPROCESSORS_ONLN) && sudo make install
+
+Fix up the kernel configuration to allow LTO:
+
+<start with a suitable kernel configuration>
+./source/scripts/config --disable function_tracer \
+                       --disable function_graph_tracer \
+                       --disable stack_tracer --enable lto_menu \
+                        --disable lto_disable \
+                       --disable gcov \
+                       --disable kallsyms_all \
+                       --disable modversions
+make oldconfig
+
+Then you can build with
+
+# The COMPILER_PATH is needed to let gcc use the new binutils
+# as the LTO plugin linker
+# if you installed gcc in a separate directory like below also
+# add it to the PATH line below before the regular $PATH
+# The COMPILER_PATH setting is only needed if the gcc was not built
+# with --with-plugin-ld pointing to the Linux binutils ld
+# The AR/NM setting works around a Makefile bug
+COMPILER_PATH=/opt/binutils-VERSION/bin PATH=$COMPILER_PATH:$PATH \
+make -j$(getconf _NPROCESSORS_ONLN) AR=gcc-ar NM=gcc-nm
+
+If you don't have gcc 4.8+ as system compiler you would also need
+to install that compiler. In this case I recommend getting
+a gcc 4.9+ snapshot from http://gcc.gnu.org (or release when available),
+as it builds much faster for LTO than 4.8.
+
+Here's an example build procedure:
+
+Assuming gcc is unpacked in gcc-VERSION
+
+cd gcc-VERSION
+./contrib/download_preqrequisites
+cd ..
+
+mkdir obj-gcc
+# please don't skip this cd. the build will not work correctly in the
+# source dir, you have to use the separate object dir
+cd obj-gcc
+../gcc-VERSION/configure --prefix=/opt/gcc-VERSION --enable-lto \
+--with-plugin-ld=/opt/binutils-VERSION/bin/ld
+--disable-nls --enable-languages=c,c++ \
+--disable-libstdcxx-pch
+make -j$(getconf _NPROCESSORS_ONLN)
+sudo make install-no-fixedincludes
+
+FAQs:
+
+Q: I get a section type attribute conflict
+A: Usually because of someone doing
+const __initdata (should be const __initconst) or const __read_mostly
+(should be just const). Check both symbols reported by gcc.
+
+Q: I see lots of undefined symbols for memcmp etc.
+A: Usually because NM=gcc-nm AR=gcc-ar are missing.
+The Makefile tries to set those automatically, but it doesn't always
+work. Better to set it manually on the make command line.
+
+Q: It's quite slow / uses too much memory.
+A: Consider a gcc 4.9 snapshot/release (not released yet)
+The main problem in 4.8 is the type merging in the single threaded WPA pass,
+which has been improved considerably in 4.9 by running it distributed.
+
+Q: It's still slow
+A: It'll always be somewhat slower than non LTO sorry.
+
+Q: What's up with .XXXXX numeric post fixes
+A: This is due LTO turning (near) all symbols to static
+Use gcc 4.9, it avoids them in most cases. They are also filtered out
+in kallsyms.
+
+References:
+
+Presentation on Kernel LTO
+(note, performance numbers/details outdated.  In particular gcc 4.9 fixed
+most of the build time problems):
+http://halobates.de/kernel-lto.pdf
+
+Generic gcc LTO:
+http://www.ucw.cz/~hubicka/slides/labs2013.pdf
+http://www.hipeac.net/system/files/barcelona.pdf
+
+Somewhat outdated too:
+http://gcc.gnu.org/projects/lto/lto.pdf
+http://gcc.gnu.org/projects/lto/whopr.pdf
+
+Happy Link-Time-Optimizing!
+
+Andi Kleen
diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt
new file mode 100644 (file)
index 0000000..548d630
--- /dev/null
@@ -0,0 +1,62 @@
+                          SPI NOR framework
+               ============================================
+
+Part I - Why do we need this framework?
+---------------------------------------
+
+SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus
+controller operates agnostic of the specific device attached. However, some
+controllers (such as Freescale's QuadSPI controller) cannot easily handle
+arbitrary streams of bytes, but rather are designed specifically for SPI NOR.
+
+In particular, Freescale's QuadSPI controller must know the NOR commands to
+find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of
+opcodes, addresses, or data payloads; a SPI controller simply knows to send or
+receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under
+which the controller driver is aware of the opcodes, addressing, and other
+details of the SPI NOR protocol.
+
+Part II - How does the framework work?
+--------------------------------------
+
+This framework just adds a new layer between the MTD and the SPI bus driver.
+With this new layer, the SPI NOR controller driver does not depend on the
+m25p80 code anymore.
+
+   Before this framework, the layer is like:
+
+                   MTD
+         ------------------------
+                  m25p80
+         ------------------------
+              SPI bus driver
+         ------------------------
+               SPI NOR chip
+
+   After this framework, the layer is like:
+                   MTD
+         ------------------------
+              SPI NOR framework
+         ------------------------
+                  m25p80
+         ------------------------
+              SPI bus driver
+         ------------------------
+              SPI NOR chip
+
+  With the SPI NOR controller driver (Freescale QuadSPI), it looks like:
+                   MTD
+         ------------------------
+              SPI NOR framework
+         ------------------------
+                fsl-quadSPI
+         ------------------------
+              SPI NOR chip
+
+Part III - How can drivers use the framework?
+---------------------------------------------
+
+The main API is spi_nor_scan(). Before you call the hook, a driver should
+initialize the necessary fields for spi_nor{}. Please see
+drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
+when you want to write a new driver for a SPI NOR controller.
index a383c00392d03f2e316f7fe7dd954c7d8b71f274..9c723ecd00251534a0b011c4e0ffbd053242454e 100644 (file)
@@ -585,13 +585,19 @@ mode
        balance-tlb or 5
 
                Adaptive transmit load balancing: channel bonding that
-               does not require any special switch support.  The
-               outgoing traffic is distributed according to the
-               current load (computed relative to the speed) on each
-               slave.  Incoming traffic is received by the current
-               slave.  If the receiving slave fails, another slave
-               takes over the MAC address of the failed receiving
-               slave.
+               does not require any special switch support.
+
+               In tlb_dynamic_lb=1 mode; the outgoing traffic is
+               distributed according to the current load (computed
+               relative to the speed) on each slave.
+
+               In tlb_dynamic_lb=0 mode; the load balancing based on
+               current load is disabled and the load is distributed
+               only using the hash distribution.
+
+               Incoming traffic is received by the current slave.
+               If the receiving slave fails, another slave takes over
+               the MAC address of the failed receiving slave.
 
                Prerequisite:
 
@@ -736,6 +742,28 @@ primary_reselect
 
        This option was added for bonding version 3.6.0.
 
+tlb_dynamic_lb
+
+       Specifies if dynamic shuffling of flows is enabled in tlb
+       mode. The value has no effect on any other modes.
+
+       The default behavior of tlb mode is to shuffle active flows across
+       slaves based on the load in that interval. This gives nice lb
+       characteristics but can cause packet reordering. If re-ordering is
+       a concern use this variable to disable flow shuffling and rely on
+       load balancing provided solely by the hash distribution.
+       xmit-hash-policy can be used to select the appropriate hashing for
+       the setup.
+
+       The sysfs entry can be used to change the setting per bond device
+       and the initial value is derived from the module parameter. The
+       sysfs entry is allowed to be changed only if the bond device is
+       down.
+
+       The default value is "1" that enables flow shuffling while value "0"
+       disables it. This option was added in bonding driver 3.7.1
+
+
 updelay
 
        Specifies the time, in milliseconds, to wait before enabling a
@@ -769,7 +797,7 @@ use_carrier
 xmit_hash_policy
 
        Selects the transmit hash policy to use for slave selection in
-       balance-xor and 802.3ad modes.  Possible values are:
+       balance-xor, 802.3ad, and tlb modes.  Possible values are:
 
        layer2
 
index 81f940f4e88480d48c35fd7707d679d646ef0af8..748fd385535d38ee905f48403b5244ccc41d037a 100644 (file)
@@ -281,6 +281,7 @@ Possible BPF extensions are shown in the following table:
   cpu                                   raw_smp_processor_id()
   vlan_tci                              vlan_tx_tag_get(skb)
   vlan_pr                               vlan_tx_tag_present(skb)
+  rand                                  prandom_u32()
 
 These extensions can also be prefixed with '#'.
 Examples for low-level BPF:
@@ -308,6 +309,18 @@ Examples for low-level BPF:
   ret #-1
   drop: ret #0
 
+** icmp random packet sampling, 1 in 4
+  ldh [12]
+  jne #0x800, drop
+  ldb [23]
+  jneq #1, drop
+  # get a random uint32 number
+  ld rand
+  mod #4
+  jneq #1, drop
+  ret #-1
+  drop: ret #0
+
 ** SECCOMP filter example:
 
   ld [4]                  /* offsetof(struct seccomp_data, arch) */
@@ -600,7 +613,7 @@ Some core changes of the new internal format:
 
   Therefore, BPF calling convention is defined as:
 
-    * R0       - return value from in-kernel function
+    * R0       - return value from in-kernel function, and exit value for BPF program
     * R1 - R5  - arguments from BPF program to in-kernel function
     * R6 - R9  - callee saved registers that in-kernel function will preserve
     * R10      - read-only frame pointer to access stack
@@ -646,9 +659,140 @@ Some core changes of the new internal format:
 - Introduces bpf_call insn and register passing convention for zero overhead
   calls from/to other kernel functions:
 
-  After a kernel function call, R1 - R5 are reset to unreadable and R0 has a
-  return type of the function. Since R6 - R9 are callee saved, their state is
-  preserved across the call.
+  Before an in-kernel function call, the internal BPF program needs to
+  place function arguments into R1 to R5 registers to satisfy calling
+  convention, then the interpreter will take them from registers and pass
+  to in-kernel function. If R1 - R5 registers are mapped to CPU registers
+  that are used for argument passing on given architecture, the JIT compiler
+  doesn't need to emit extra moves. Function arguments will be in the correct
+  registers and BPF_CALL instruction will be JITed as single 'call' HW
+  instruction. This calling convention was picked to cover common call
+  situations without performance penalty.
+
+  After an in-kernel function call, R1 - R5 are reset to unreadable and R0 has
+  a return value of the function. Since R6 - R9 are callee saved, their state
+  is preserved across the call.
+
+  For example, consider three C functions:
+
+  u64 f1() { return (*_f2)(1); }
+  u64 f2(u64 a) { return f3(a + 1, a); }
+  u64 f3(u64 a, u64 b) { return a - b; }
+
+  GCC can compile f1, f3 into x86_64:
+
+  f1:
+    movl $1, %edi
+    movq _f2(%rip), %rax
+    jmp  *%rax
+  f3:
+    movq %rdi, %rax
+    subq %rsi, %rax
+    ret
+
+  Function f2 in BPF may look like:
+
+  f2:
+    bpf_mov R2, R1
+    bpf_add R1, 1
+    bpf_call f3
+    bpf_exit
+
+  If f2 is JITed and the pointer stored to '_f2'. The calls f1 -> f2 -> f3 and
+  returns will be seamless. Without JIT, __sk_run_filter() interpreter needs to
+  be used to call into f2.
+
+  For practical reasons all BPF programs have only one argument 'ctx' which is
+  already placed into R1 (e.g. on __sk_run_filter() startup) and the programs
+  can call kernel functions with up to 5 arguments. Calls with 6 or more arguments
+  are currently not supported, but these restrictions can be lifted if necessary
+  in the future.
+
+  On 64-bit architectures all register map to HW registers one to one. For
+  example, x86_64 JIT compiler can map them as ...
+
+    R0 - rax
+    R1 - rdi
+    R2 - rsi
+    R3 - rdx
+    R4 - rcx
+    R5 - r8
+    R6 - rbx
+    R7 - r13
+    R8 - r14
+    R9 - r15
+    R10 - rbp
+
+  ... since x86_64 ABI mandates rdi, rsi, rdx, rcx, r8, r9 for argument passing
+  and rbx, r12 - r15 are callee saved.
+
+  Then the following internal BPF pseudo-program:
+
+    bpf_mov R6, R1 /* save ctx */
+    bpf_mov R2, 2
+    bpf_mov R3, 3
+    bpf_mov R4, 4
+    bpf_mov R5, 5
+    bpf_call foo
+    bpf_mov R7, R0 /* save foo() return value */
+    bpf_mov R1, R6 /* restore ctx for next call */
+    bpf_mov R2, 6
+    bpf_mov R3, 7
+    bpf_mov R4, 8
+    bpf_mov R5, 9
+    bpf_call bar
+    bpf_add R0, R7
+    bpf_exit
+
+  After JIT to x86_64 may look like:
+
+    push %rbp
+    mov %rsp,%rbp
+    sub $0x228,%rsp
+    mov %rbx,-0x228(%rbp)
+    mov %r13,-0x220(%rbp)
+    mov %rdi,%rbx
+    mov $0x2,%esi
+    mov $0x3,%edx
+    mov $0x4,%ecx
+    mov $0x5,%r8d
+    callq foo
+    mov %rax,%r13
+    mov %rbx,%rdi
+    mov $0x2,%esi
+    mov $0x3,%edx
+    mov $0x4,%ecx
+    mov $0x5,%r8d
+    callq bar
+    add %r13,%rax
+    mov -0x228(%rbp),%rbx
+    mov -0x220(%rbp),%r13
+    leaveq
+    retq
+
+  Which is in this example equivalent in C to:
+
+    u64 bpf_filter(u64 ctx)
+    {
+        return foo(ctx, 2, 3, 4, 5) + bar(ctx, 6, 7, 8, 9);
+    }
+
+  In-kernel functions foo() and bar() with prototype: u64 (*)(u64 arg1, u64
+  arg2, u64 arg3, u64 arg4, u64 arg5); will receive arguments in proper
+  registers and place their return value into '%rax' which is R0 in BPF.
+  Prologue and epilogue are emitted by JIT and are implicit in the
+  interpreter. R0-R5 are scratch registers, so BPF program needs to preserve
+  them across the calls as defined by calling convention.
+
+  For example the following program is invalid:
+
+    bpf_mov R1, 1
+    bpf_call foo
+    bpf_mov R0, R1
+    bpf_exit
+
+  After the call the registers R1-R5 contain junk values and cannot be read.
+  In the future a BPF verifier can be used to validate internal BPF programs.
 
 Also in the new design, BPF is limited to 4096 insns, which means that any
 program will terminate quickly and will only call a fixed number of kernel
@@ -663,6 +807,25 @@ A program, that is translated internally consists of the following elements:
 
   op:16, jt:8, jf:8, k:32    ==>    op:8, a_reg:4, x_reg:4, off:16, imm:32
 
+So far 87 internal BPF instructions were implemented. 8-bit 'op' opcode field
+has room for new instructions. Some of them may use 16/24/32 byte encoding. New
+instructions must be multiple of 8 bytes to preserve backward compatibility.
+
+Internal BPF is a general purpose RISC instruction set. Not every register and
+every instruction are used during translation from original BPF to new format.
+For example, socket filters are not using 'exclusive add' instruction, but
+tracing filters may do to maintain counters of events, for example. Register R9
+is not used by socket filters either, but more complex filters may be running
+out of registers and would have to resort to spill/fill to stack.
+
+Internal BPF can used as generic assembler for last step performance
+optimizations, socket filters and seccomp are using it as assembler. Tracing
+filters may use it as assembler to generate code from kernel. In kernel usage
+may not be bounded by security considerations, since generated internal BPF code
+may be optimizing internal code path and not being exposed to the user space.
+Safety of internal BPF can come from a verifier (TBD). In such use cases as
+described, it may be used as safe instruction set.
+
 Just like the original BPF, the new format runs within a controlled environment,
 is deterministic and the kernel can easily prove that. The safety of the program
 can be determined in two steps: first step does depth-first-search to disallow
index ca6977f5b2ed066f49823c0d7c0129a9a16b0820..99ca40e8e810888d30bbb9726eb2de2e537c3e79 100644 (file)
@@ -429,7 +429,7 @@ RPS and RFS were introduced in kernel 2.6.35. XPS was incorporated into
 (therbert@google.com)
 
 Accelerated RFS was introduced in 2.6.35. Original patches were
-submitted by Ben Hutchings (bhutchings@solarflare.com)
+submitted by Ben Hutchings (bwh@kernel.org)
 
 Authors:
 Tom Herbert (therbert@google.com)
index cf45d27c4608da8f566d4b888aa766a8e1e9bd4e..dc929be9601615f4e9e3e2393b6b4fbb83f50009 100644 (file)
@@ -1,15 +1,15 @@
-s390 SCSI dump tool (zfcpdump)
+The s390 SCSI dump tool (zfcpdump)
 
 System z machines (z900 or higher) provide hardware support for creating system
 dumps on SCSI disks. The dump process is initiated by booting a dump tool, which
 has to create a dump of the current (probably crashed) Linux image. In order to
 not overwrite memory of the crashed Linux with data of the dump tool, the
-hardware saves some memory plus the register sets of the boot cpu before the
+hardware saves some memory plus the register sets of the boot CPU before the
 dump tool is loaded. There exists an SCLP hardware interface to obtain the saved
 memory afterwards. Currently 32 MB are saved.
 
 This zfcpdump implementation consists of a Linux dump kernel together with
-a userspace dump tool, which are loaded together into the saved memory region
+a user space dump tool, which are loaded together into the saved memory region
 below 32 MB. zfcpdump is installed on a SCSI disk using zipl (as contained in
 the s390-tools package) to make the device bootable. The operator of a Linux
 system can then trigger a SCSI dump by booting the SCSI disk, where zfcpdump
@@ -19,68 +19,33 @@ The kernel part of zfcpdump is implemented as a debugfs file under "zcore/mem",
 which exports memory and registers of the crashed Linux in an s390
 standalone dump format. It can be used in the same way as e.g. /dev/mem. The
 dump format defines a 4K header followed by plain uncompressed memory. The
-register sets are stored in the prefix pages of the respective cpus. To build a
+register sets are stored in the prefix pages of the respective CPUs. To build a
 dump enabled kernel with the zcore driver, the kernel config option
-CONFIG_ZFCPDUMP has to be set. When reading from "zcore/mem", the part of
+CONFIG_CRASH_DUMP has to be set. When reading from "zcore/mem", the part of
 memory, which has been saved by hardware is read by the driver via the SCLP
 hardware interface. The second part is just copied from the non overwritten real
 memory.
 
-The userspace application of zfcpdump can reside e.g. in an intitramfs or an
-initrd. It reads from zcore/mem and writes the system dump to a file on a
-SCSI disk.
+Since kernel version 3.12 also the /proc/vmcore file can also be used to access
+the dump.
 
-To build a zfcpdump kernel use the following settings in your kernel
-configuration:
- * CONFIG_ZFCPDUMP=y
- * Enable ZFCP driver
- * Enable SCSI driver
- * Enable ext2 and ext3 filesystems
- * Disable as many features as possible to keep the kernel small.
-   E.g. network support is not needed at all.
+To get a valid zfcpdump kernel configuration use "make zfcpdump_defconfig".
 
-To use the zfcpdump userspace application in an initramfs you have to do the
-following:
+The s390 zipl tool looks for the zfcpdump kernel and optional initrd/initramfs
+under the following locations:
 
- * Copy the zfcpdump executable somewhere into your Linux tree.
-   E.g. to "arch/s390/boot/zfcpdump. If you do not want to include
-   shared libraries, compile the tool with the "-static" gcc option.
- * If you want to include e2fsck, add it to your source tree, too. The zfcpdump
-   application attempts to start /sbin/e2fsck from the ramdisk.
- * Use an initramfs config file like the following:
+* kernel:  <zfcpdump directory>/zfcpdump.image
+* ramdisk: <zfcpdump directory>/zfcpdump.rd
 
-   dir /dev 755 0 0
-   nod /dev/console 644 0 0 c 5 1
-   nod /dev/null 644 0 0 c 1 3
-   nod /dev/sda1 644 0 0 b 8 1
-   nod /dev/sda2 644 0 0 b 8 2
-   nod /dev/sda3 644 0 0 b 8 3
-   nod /dev/sda4 644 0 0 b 8 4
-   nod /dev/sda5 644 0 0 b 8 5
-   nod /dev/sda6 644 0 0 b 8 6
-   nod /dev/sda7 644 0 0 b 8 7
-   nod /dev/sda8 644 0 0 b 8 8
-   nod /dev/sda9 644 0 0 b 8 9
-   nod /dev/sda10 644 0 0 b 8 10
-   nod /dev/sda11 644 0 0 b 8 11
-   nod /dev/sda12 644 0 0 b 8 12
-   nod /dev/sda13 644 0 0 b 8 13
-   nod /dev/sda14 644 0 0 b 8 14
-   nod /dev/sda15 644 0 0 b 8 15
-   file /init arch/s390/boot/zfcpdump 755 0 0
-   file /sbin/e2fsck arch/s390/boot/e2fsck 755 0 0
-   dir /proc 755 0 0
-   dir /sys 755 0 0
-   dir /mnt 755 0 0
-   dir /sbin 755 0 0
+The zfcpdump directory is defined in the s390-tools package.
 
- * Issue "make image" to build the zfcpdump image with initramfs.
+The user space application of zfcpdump can reside in an intitramfs or an
+initrd. It can also be included in a built-in kernel initramfs. The application
+reads from /proc/vmcore or zcore/mem and writes the system dump to a SCSI disk.
 
-In a Linux distribution the zfcpdump enabled kernel image must be copied to
-/usr/share/zfcpdump/zfcpdump.image, where the s390 zipl tool is looking for the
-dump kernel when preparing a SCSI dump disk.
-
-If you use a ramdisk copy it to "/usr/share/zfcpdump/zfcpdump.rd".
+The s390-tools package version 1.24.0 and above builds an external zfcpdump
+initramfs with a user space application that writes the dump to a SCSI
+partition.
 
 For more information on how to use zfcpdump refer to the s390 'Using the Dump
 Tools book', which is available from
index e67ea244204163a5d0eb9e43239c5ccd4394bae1..434ae324ef3b12c12a4d49840f791b5975e27aa7 100644 (file)
@@ -1967,6 +1967,12 @@ S:       Maintained
 F:     drivers/bcma/
 F:     include/linux/bcma/
 
+BROADCOM SYSTEMPORT ETHERNET DRIVER
+M:     Florian Fainelli <f.fainelli@gmail.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/broadcom/bcmsysport.*
+
 BROCADE BFA FC SCSI DRIVER
 M:     Anil Gurumurthy <anil.gurumurthy@qlogic.com>
 M:     Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
@@ -2415,7 +2421,6 @@ F:        drivers/net/ethernet/ti/cpmac.c
 CPU FREQUENCY DRIVERS
 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
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
@@ -2426,7 +2431,6 @@ F:        include/linux/cpufreq.h
 CPU FREQUENCY DRIVERS - ARM BIG LITTLE
 M:     Viresh Kumar <viresh.kumar@linaro.org>
 M:     Sudeep Holla <sudeep.holla@arm.com>
-L:     cpufreq@vger.kernel.org
 L:     linux-pm@vger.kernel.org
 W:     http://www.arm.com/products/processors/technologies/biglittleprocessing.php
 S:     Maintained
@@ -3485,6 +3489,12 @@ S:       Maintained
 F:     drivers/extcon/
 F:     Documentation/extcon/
 
+EXYNOS DP DRIVER
+M:     Jingoo Han <jg1.han@samsung.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+F:     drivers/gpu/drm/exynos/exynos_dp*
+
 EXYNOS MIPI DISPLAY DRIVERS
 M:     Inki Dae <inki.dae@samsung.com>
 M:     Donghwa Lee <dh09.lee@samsung.com>
@@ -3550,7 +3560,7 @@ F:        include/scsi/libfcoe.h
 F:     include/uapi/scsi/fc/
 
 FILE LOCKING (flock() and fcntl()/lockf())
-M:     Jeff Layton <jlayton@redhat.com>
+M:     Jeff Layton <jlayton@poochiereds.net>
 M:     J. Bruce Fields <bfields@fieldses.org>
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
@@ -5108,14 +5118,19 @@ F:      drivers/s390/kvm/
 
 KERNEL VIRTUAL MACHINE (KVM) FOR ARM
 M:     Christoffer Dall <christoffer.dall@linaro.org>
+M:     Marc Zyngier <marc.zyngier@arm.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     kvmarm@lists.cs.columbia.edu
 W:     http://systems.cs.columbia.edu/projects/kvm-arm
 S:     Supported
 F:     arch/arm/include/uapi/asm/kvm*
 F:     arch/arm/include/asm/kvm*
 F:     arch/arm/kvm/
+F:     virt/kvm/arm/
+F:     include/kvm/arm_*
 
 KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
+M:     Christoffer Dall <christoffer.dall@linaro.org>
 M:     Marc Zyngier <marc.zyngier@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     kvmarm@lists.cs.columbia.edu
@@ -6693,6 +6708,7 @@ F:        Documentation/PCI/
 F:     drivers/pci/
 F:     include/linux/pci*
 F:     arch/x86/pci/
+F:     arch/x86/kernel/quirks.c
 
 PCI DRIVER FOR IMX6
 M:     Richard Zhu <r65037@freescale.com>
@@ -7277,7 +7293,6 @@ F:        drivers/video/aty/aty128fb.c
 RALINK RT2X00 WIRELESS LAN DRIVER
 P:     rt2x00 project
 M:     Ivo van Doorn <IvDoorn@gmail.com>
-M:     Gertjan van Wingerde <gwingerde@gmail.com>
 M:     Helmut Schaa <helmut.schaa@googlemail.com>
 L:     linux-wireless@vger.kernel.org
 L:     users@rt2x00.serialmonkey.com (moderated for non-subscribers)
@@ -7293,7 +7308,7 @@ F:        Documentation/blockdev/ramdisk.txt
 F:     drivers/block/brd.c
 
 RANDOM NUMBER DRIVER
-M:     Theodore Ts'o" <tytso@mit.edu>
+M:     "Theodore Ts'o" <tytso@mit.edu>
 S:     Maintained
 F:     drivers/char/random.c
 
@@ -7674,7 +7689,6 @@ F:        drivers/clk/samsung/
 SAMSUNG SXGBE DRIVERS
 M:     Byungho An <bh74.an@samsung.com>
 M:     Girish K S <ks.giri@samsung.com>
-M:     Siva Reddy Kallam <siva.kallam@samsung.com>
 M:     Vipul Pandya <vipul.pandya@samsung.com>
 S:     Supported
 L:     netdev@vger.kernel.org
@@ -9098,6 +9112,9 @@ F:        arch/um/os-Linux/drivers/
 
 TURBOCHANNEL SUBSYSTEM
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
+M:     Ralf Baechle <ralf@linux-mips.org>
+L:     linux-mips@linux-mips.org
+Q:     http://patchwork.linux-mips.org/project/linux-mips/list/
 S:     Maintained
 F:     drivers/tc/
 F:     include/linux/tc.h
index 041c685e11ea0d24a2946c4384a06e22a8de93d2..112a271f5573001b78d1f114c13499ae432b5cdc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 15
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc4
 NAME = Shuffling Zombie Juror
 
 # *DOCUMENTATION*
@@ -105,10 +105,6 @@ ifeq ("$(origin O)", "command line")
   KBUILD_OUTPUT := $(O)
 endif
 
-ifeq ("$(origin W)", "command line")
-  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
-endif
-
 # That's our default target when none is given on the command line
 PHONY := _all
 _all:
@@ -166,7 +162,7 @@ export srctree objtree VPATH
 # SUBARCH tells the usermode build what the underlying arch is.  That is set
 # first, and if a usermode build is happening, the "ARCH=um" on the command
 # line overrides the setting of ARCH below.  If a native build is happening,
-# then ARCH is assigned, getting whatever value it gets normally, and 
+# then ARCH is assigned, getting whatever value it gets normally, and
 # SUBARCH is subsequently ignored.
 
 SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
@@ -259,18 +255,18 @@ endif
 KBUILD_MODULES :=
 KBUILD_BUILTIN := 1
 
-#      If we have only "make modules", don't compile built-in objects.
-#      When we're building modules with modversions, we need to consider
-#      the built-in objects during the descend as well, in order to
-#      make sure the checksums are up to date before we record them.
+# If we have only "make modules", don't compile built-in objects.
+# When we're building modules with modversions, we need to consider
+# the built-in objects during the descend as well, in order to
+# make sure the checksums are up to date before we record them.
 
 ifeq ($(MAKECMDGOALS),modules)
   KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
 endif
 
-#      If we have "make <whatever> modules", compile modules
-#      in addition to whatever we do anyway.
-#      Just "make" or "make all" shall build modules as well
+# If we have "make <whatever> modules", compile modules
+# in addition to whatever we do anyway.
+# Just "make" or "make all" shall build modules as well
 
 ifneq ($(filter all _all modules,$(MAKECMDGOALS)),)
   KBUILD_MODULES := 1
@@ -294,7 +290,7 @@ export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
 #         cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
 #
 # If $(quiet) is empty, the whole command will be printed.
-# If it is set to "quiet_", only the short version will be printed. 
+# If it is set to "quiet_", only the short version will be printed.
 # If it is set to "silent_", nothing will be printed at all, since
 # the variable $(silent_cmd_cc_o_c) doesn't exist.
 #
@@ -346,12 +342,16 @@ $(srctree)/scripts/Kbuild.include: ;
 include $(srctree)/scripts/Kbuild.include
 
 # Make variables (CC, etc...)
-
 AS             = $(CROSS_COMPILE)as
 LD             = $(CROSS_COMPILE)ld
+LDFINAL        = $(LD)
 CC             = $(CROSS_COMPILE)gcc
 CPP            = $(CC) -E
+ifdef CONFIG_LTO
+AR             = $(CROSS_COMPILE)gcc-ar
+else
 AR             = $(CROSS_COMPILE)ar
+endif
 NM             = $(CROSS_COMPILE)nm
 STRIP          = $(CROSS_COMPILE)strip
 OBJCOPY                = $(CROSS_COMPILE)objcopy
@@ -410,7 +410,7 @@ KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(S
 
 export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
 export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
-export CPP AR NM STRIP OBJCOPY OBJDUMP
+export CPP AR NM STRIP OBJCOPY OBJDUMP LDFINAL
 export MAKE AWK GENKSYMS INSTALLKERNEL PERL UTS_MACHINE
 export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
 
@@ -421,6 +421,17 @@ export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
 export KBUILD_ARFLAGS
 
+ifdef CONFIG_LTO
+# LTO gcc creates a lot of files in TMPDIR, and with /tmp as tmpfs
+# it's easy to drive the machine OOM. Use the object directory
+# instead.
+ifndef TMPDIR
+TMPDIR ?= $(objtree)
+export TMPDIR
+$(info setting TMPDIR=$(objtree) for LTO build)
+endif
+endif
+
 # When compiling out-of-tree modules, put MODVERDIR in the module
 # tree rather than in the kernel tree. The kernel tree might
 # even be read-only.
@@ -504,8 +515,16 @@ ifeq ($(mixed-targets),1)
 # We're called with mixed targets (*config and build targets).
 # Handle them one by one.
 
-%:: FORCE
-       $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
+PHONY += $(MAKECMDGOALS) __build_one_by_one
+
+$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
+       @:
+
+__build_one_by_one:
+       $(Q)set -e; \
+       for i in $(MAKECMDGOALS); do \
+               $(MAKE) -f $(srctree)/Makefile $$i; \
+       done
 
 else
 ifeq ($(config-targets),1)
@@ -731,6 +750,9 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
        KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
 endif
 
+include $(srctree)/scripts/Makefile.extrawarn
+include ${srctree}/scripts/Makefile.lto
+
 # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
 KBUILD_CPPFLAGS += $(KCPPFLAGS)
 KBUILD_AFLAGS += $(KAFLAGS)
@@ -775,10 +797,10 @@ MODLIB    = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
 export MODLIB
 
 #
-#  INSTALL_MOD_STRIP, if defined, will cause modules to be
-#  stripped after they are installed.  If INSTALL_MOD_STRIP is '1', then
-#  the default option --strip-debug will be used.  Otherwise,
-#  INSTALL_MOD_STRIP value will be used as the options to the strip command.
+# INSTALL_MOD_STRIP, if defined, will cause modules to be
+# stripped after they are installed.  If INSTALL_MOD_STRIP is '1', then
+# the default option --strip-debug will be used.  Otherwise,
+# INSTALL_MOD_STRIP value will be used as the options to the strip command.
 
 ifdef INSTALL_MOD_STRIP
 ifeq ($(INSTALL_MOD_STRIP),1)
@@ -863,7 +885,7 @@ ifdef CONFIG_BUILD_DOCSRC
 endif
        +$(call if_changed,link-vmlinux)
 
-# The actual objects are generated when descending, 
+# The actual objects are generated when descending,
 # make sure no implicit rule kicks in
 $(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
 
@@ -1021,11 +1043,11 @@ ifdef CONFIG_MODULES
 
 all: modules
 
-#      Build modules
+# Build modules
 #
-#      A module can be listed more than once in obj-m resulting in
-#      duplicate lines in modules.order files.  Those are removed
-#      using awk while concatenating to the final file.
+# A module can be listed more than once in obj-m resulting in
+# duplicate lines in modules.order files.  Those are removed
+# using awk while concatenating to the final file.
 
 PHONY += modules
 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
@@ -1104,7 +1126,7 @@ CLEAN_DIRS  += $(MODVERDIR)
 
 # Directories & files removed with 'make mrproper'
 MRPROPER_DIRS  += include/config usr/include include/generated          \
-                  arch/*/include/generated .tmp_objdiff
+                 arch/*/include/generated .tmp_objdiff
 MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
                  signing_key.priv signing_key.x509 x509.genkey         \
@@ -1478,7 +1500,7 @@ endif
        $(build)=$(build-dir) $(@:.ko=.o)
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
 
-# FIXME Should go into a make.lib or something 
+# FIXME Should go into a make.lib or something
 # ===========================================================================
 
 quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN   $(wildcard $(rm-dirs)))
index 291a70db68b8b0fa0d262a79d80d7e9be9681c0e..781f57f25bd8d10ff0d85dfb6a18ca5d396117f9 100644 (file)
@@ -19,8 +19,6 @@
 #include <asm-generic/irq.h>
 
 extern void arc_init_IRQ(void);
-extern int get_hw_config_num_irq(void);
-
 void arc_local_timer_setup(unsigned int cpu);
 
 #endif
index 15334ab66b56e110ac67152bac96317c3f8368ff..d99f9b37cd1540a14004e56a46d0e7be0584891b 100644 (file)
@@ -18,7 +18,6 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm/arcregs.h>       /* for STATUS_E1_MASK et all */
 #include <asm/ptrace.h>
 
 /* Arch specific stuff which needs to be saved per task.
@@ -41,15 +40,13 @@ struct thread_struct {
 /* Forward declaration, a strange C thing */
 struct task_struct;
 
-/*
- * Return saved PC of a blocked thread.
- */
+/* Return saved PC of a blocked thread  */
 unsigned long thread_saved_pc(struct task_struct *t);
 
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
 
-/* Free all resources held by a thread. */
+/* Free all resources held by a thread */
 #define release_thread(thread) do { } while (0)
 
 /* Prepare to copy thread state - unlazy all lazy status */
@@ -82,26 +79,8 @@ unsigned long thread_saved_pc(struct task_struct *t);
 #define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
 #define KSTK_FP(tsk)    KSTK_REG(tsk, 0)
 
-/*
- * Do necessary setup to start up a newly executed thread.
- *
- * E1,E2 so that Interrupts are enabled in user mode
- * L set, so Loop inhibited to begin with
- * lp_start and lp_end seeded with bogus non-zero values so to easily catch
- * the ARC700 sr to lp_start hardware bug
- */
-#define start_thread(_regs, _pc, _usp)                         \
-do {                                                           \
-       set_fs(USER_DS); /* reads from user space */            \
-       (_regs)->ret = (_pc);                                   \
-       /* Interrupts enabled in User Mode */                   \
-       (_regs)->status32 = STATUS_U_MASK | STATUS_L_MASK       \
-               | STATUS_E1_MASK | STATUS_E2_MASK;              \
-       (_regs)->sp = (_usp);                                   \
-       /* bogus seed values for debugging */                   \
-       (_regs)->lp_start = 0x10;                               \
-       (_regs)->lp_end = 0x80;                                 \
-} while (0)
+extern void start_thread(struct pt_regs * regs, unsigned long pc,
+                        unsigned long usp);
 
 extern unsigned int get_wchan(struct task_struct *p);
 
index 819dd5f7eb055ec87f082188e3d7ebb4a8b683aa..83a046a7cd06c964d392380ac88f17fa0759d21a 100644 (file)
@@ -156,7 +156,7 @@ ARCFP_DATA int1_saved_reg
 int1_saved_reg:
        .zero 4
 
-/* Each Interrupt level needs it's own scratch */
+/* Each Interrupt level needs its own scratch */
 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
 
 ARCFP_DATA int2_saved_reg
@@ -473,7 +473,7 @@ trap_with_param:
        lr  r0, [efa]
        mov r1, sp
 
-       ; Now that we have read EFA, its safe to do "fake" rtie
+       ; Now that we have read EFA, it is safe to do "fake" rtie
        ;   and get out of CPU exception mode
        FAKE_RET_FROM_EXCPN r11
 
@@ -614,11 +614,13 @@ resume_user_mode_begin:
 
 resume_kernel_mode:
 
-#ifdef CONFIG_PREEMPT
-
-       ; This is a must for preempt_schedule_irq()
+       ; Disable Interrupts from this point on
+       ; CONFIG_PREEMPT: This is a must for preempt_schedule_irq()
+       ; !CONFIG_PREEMPT: To ensure restore_regs is intr safe
        IRQ_DISABLE     r9
 
+#ifdef CONFIG_PREEMPT
+
        ; Can't preempt if preemption disabled
        GET_CURR_THR_INFO_FROM_SP   r10
        ld  r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -676,9 +678,9 @@ not_exception:
        brne r9, event_IRQ2, 149f
 
        ;------------------------------------------------------------------
-       ; if L2 IRQ interrupted a L1 ISR,  we'd disbaled preemption earlier
-       ; so that sched doesnt move to new task, causing L1 to be delayed
-       ; undeterministically. Now that we've achieved that, lets reset
+       ; if L2 IRQ interrupted an L1 ISR,  we'd disabled preemption earlier
+       ; so that sched doesn't move to new task, causing L1 to be delayed
+       ; undeterministically. Now that we've achieved that, let's reset
        ; things to what they were, before returning from L2 context
        ;----------------------------------------------------------------
 
@@ -734,7 +736,7 @@ ENTRY(ret_from_fork)
        ; put last task in scheduler queue
        bl   @schedule_tail
 
-       ; If kernel thread, jump to it's entry-point
+       ; If kernel thread, jump to its entry-point
        ld   r9, [sp, PT_status32]
        brne r9, 0, 1f
 
index a4b141ee9a6a19c9e6e4001583fc7b6637b3f1f4..7d653c0d077390fa31bc70a6e6e67cbf78ad33a8 100644 (file)
@@ -150,24 +150,6 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
        set_irq_regs(old_regs);
 }
 
-int get_hw_config_num_irq(void)
-{
-       uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR);
-
-       switch (val & 0x03) {
-       case 0:
-               return 16;
-       case 1:
-               return 32;
-       case 2:
-               return 8;
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
 /*
  * arch_local_irq_enable - Enable interrupts.
  *
index 07a3a968fe49a113e94c2a894895db09362108ac..fdd89715d2d3783f8a1302513c10a15d138ded91 100644 (file)
@@ -150,6 +150,29 @@ int copy_thread(unsigned long clone_flags,
        return 0;
 }
 
+/*
+ * Do necessary setup to start up a new user task
+ */
+void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
+{
+       set_fs(USER_DS); /* user space */
+
+       regs->sp = usp;
+       regs->ret = pc;
+
+       /*
+        * [U]ser Mode bit set
+        * [L] ZOL loop inhibited to begin with - cleared by a LP insn
+        * Interrupts enabled
+        */
+       regs->status32 = STATUS_U_MASK | STATUS_L_MASK |
+                        STATUS_E1_MASK | STATUS_E2_MASK;
+
+       /* bogus seed values for debugging */
+       regs->lp_start = 0x10;
+       regs->lp_end = 0x80;
+}
+
 /*
  * Some archs flush debug and FPU info here
  */
index 89edf7961a2f743e74ee355f0b8a3f9c40ecd7ee..23c3832e6d9faf683900a9370f1405b1e382883a 100644 (file)
@@ -253,12 +253,16 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
 
        if (cacheop == OP_INV_IC) {
                aux_cmd = ARC_REG_IC_IVIL;
+#if (CONFIG_ARC_MMU_VER > 2)
                aux_tag = ARC_REG_IC_PTAG;
+#endif
        }
        else {
                /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
                aux_cmd = cacheop & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
+#if (CONFIG_ARC_MMU_VER > 2)
                aux_tag = ARC_REG_DC_PTAG;
+#endif
        }
 
        /* Ensure we properly floor/ceil the non-line aligned/sized requests
index a44e22ebc1b77786ae14a39d1f5794c110df0b6b..4d1bddc34b5b531076ef05ea89206a6b75c4ef86 100644 (file)
@@ -9,4 +9,4 @@
 KBUILD_CFLAGS  += -Iarch/arc/plat-arcfpga/include
 
 obj-y := platform.o irq.o
-obj-$(CONFIG_SMP)              += smp.o
+obj-$(CONFIG_ISS_SMP_EXTN)             += smp.o
index 19b76b61f44bfc2b1b560a240347aa435fcb87ff..213394a15cd234144f367e357e1a4d2e88080be3 100644 (file)
@@ -169,7 +169,7 @@ static void __init plat_fpga_early_init(void)
 
        arc_fpga_serial_init();
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_ISS_SMP_EXTN
        iss_model_init_early_smp();
 #endif
 }
@@ -211,7 +211,7 @@ MACHINE_START(ANGEL4, "angel4")
        .init_early     = plat_fpga_early_init,
        .init_machine   = plat_fpga_populate_dev,
        .init_irq       = plat_fpga_init_IRQ,
-#ifdef CONFIG_SMP
+#ifdef CONFIG_ISS_SMP_EXTN
        .init_smp       = iss_model_init_smp,
 #endif
 MACHINE_END
index 8a12741f5f7ab79668212259036fe0c2872bb037..92bad9122077dc00b22fc82c6e22be8f5219787b 100644 (file)
@@ -42,6 +42,24 @@ static void iss_model_smp_wakeup_cpu(int cpu, unsigned long pc)
 
 }
 
+static inline int get_hw_config_num_irq(void)
+{
+       uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR);
+
+       switch (val & 0x03) {
+       case 0:
+               return 16;
+       case 1:
+               return 32;
+       case 2:
+               return 8;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
 /*
  * Any SMP specific init any CPU does when it comes up.
  * Here we setup the CPU to enable Inter-Processor-Interrupts
index db3c5414223e7298346c6338665263d5f51c0e3c..696e993da7e390be2262dcab5dcc09890689b40e 100644 (file)
@@ -2295,6 +2295,11 @@ config ARCH_SUSPEND_POSSIBLE
 config ARM_CPU_SUSPEND
        def_bool PM_SLEEP
 
+config ARCH_HIBERNATION_POSSIBLE
+       bool
+       depends on MMU
+       default y if ARCH_SUSPEND_POSSIBLE
+
 endmenu
 
 source "net/Kconfig"
index eab8ecbe69c1d271369700a9f7aac14c628685b0..00c69503da22b59169c5a6e462203e9d15ab263b 100644 (file)
@@ -942,6 +942,15 @@ config DEBUG_IMX_UART_PORT
          Choose UART port on which kernel low-level debug messages
          should be output.
 
+config DEBUG_VF_UART_PORT
+       int "Vybrid Debug UART Port Selection" if DEBUG_VF_UART
+       default 1
+       range 0 3
+       depends on SOC_VF610
+       help
+         Choose UART port on which kernel low-level debug messages
+         should be output.
+
 config DEBUG_TEGRA_UART
        bool
        depends on ARCH_TEGRA
diff --git a/arch/arm/arm-soc-for-next-contents.txt b/arch/arm/arm-soc-for-next-contents.txt
new file mode 100644 (file)
index 0000000..5f3b929
--- /dev/null
@@ -0,0 +1,40 @@
+next/fixes-non-critical
+
+next/cleanup
+       versatile/leds
+               git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator tags/versatile-leds
+       cleanup/kconfig
+               git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux tags/kconfig-cleanups
+               contains randconfig-fixes
+       renesas/cleanup
+               git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-cleanup-for-v3.16
+
+next/soc
+       renesas/soc
+               git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-soc-for-v3.16
+       renesas/clock
+               git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-clock-for-v3.16
+
+next/boards
+       shmobile/defconfig
+               git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-defconfig-for-v3.16
+       patch
+               ARM: multi_v7: enable AT24C EEPROM driver
+               ARM: multi_v7_defconfig: select CONFIG_GPIO_DWAPB
+               ARM: multi_v7_defconfig: Select CONFIG_MACH_BERLIN_BG2Q
+       renesas/clock
+               Merge branch 'renesas/clock' into next/boards
+       renesas/boards
+               git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-boards-for-v3.16
+       patch
+               ARM: configs: add CONFIG_MMC_SDHCI_PXAV3 to the multi_v7_defconfig
+
+next/dt
+       at91/dt
+               git://github.com/at91linux/linux-at91 tags/at91-dt
+       renesas/dt
+               git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-dt-for-v3.16
+
+next/drivers
+       socfpga/reset-driver
+               git://git.rocketboards.org/linux-socfpga-next tags/socfpga-driver-update-for-3.16
index 377b7c3640337ed994107814836d16909ddbd447..fb662207a504a8e3d801fe15f66df5df77cf1168 100644 (file)
@@ -56,7 +56,8 @@ dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
        bcm21664-garnet.dtb
 dtb-$(CONFIG_ARCH_BERLIN) += \
        berlin2-sony-nsz-gs7.dtb        \
-       berlin2cd-google-chromecast.dtb
+       berlin2cd-google-chromecast.dtb \
+       berlin2q-marvell-dmp.dtb
 dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \
        da850-evm.dtb
 dtb-$(CONFIG_ARCH_EFM32) += efm32gg-dk3750.dtb
@@ -157,10 +158,12 @@ dtb-$(CONFIG_ARCH_MXC) += \
        imx27-phytec-phycard-s-rdk.dtb \
        imx31-bug.dtb \
        imx35-eukrea-mbimxsd35-baseboard.dtb \
+       imx35-pdk.dtb \
        imx50-evk.dtb \
        imx51-apf51.dtb \
        imx51-apf51dev.dtb \
        imx51-babbage.dtb \
+       imx51-digi-connectcore-jsk.dtb \
        imx51-eukrea-mbimxsd51-baseboard.dtb \
        imx53-ard.dtb \
        imx53-m53evk.dtb \
@@ -179,6 +182,7 @@ dtb-$(CONFIG_ARCH_MXC) += \
        imx6dl-gw54xx.dtb \
        imx6dl-hummingboard.dtb \
        imx6dl-nitrogen6x.dtb \
+       imx6dl-phytec-pbab01.dtb \
        imx6dl-sabreauto.dtb \
        imx6dl-sabrelite.dtb \
        imx6dl-sabresd.dtb \
@@ -203,6 +207,7 @@ dtb-$(CONFIG_ARCH_MXC) += \
        imx6q-udoo.dtb \
        imx6q-wandboard.dtb \
        imx6sl-evk.dtb \
+       vf610-colibri.dtb \
        vf610-cosmic.dtb \
        vf610-twr.dtb
 dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \
@@ -289,7 +294,10 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
        am43x-epos-evm.dtb \
        am437x-gp-evm.dtb \
        dra7-evm.dtb
-dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb
+dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-d2-network.dtb \
+       orion5x-lacie-ethernet-disk-mini-v2.dtb \
+       orion5x-maxtor-shared-storage-2.dtb \
+       orion5x-rd88f5182-nas.dtb
 dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb
 dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \
        qcom-msm8960-cdp.dtb \
@@ -297,8 +305,7 @@ dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \
 dtb-$(CONFIG_ARCH_S3C24XX) += s3c2416-smdk2416.dtb
 dtb-$(CONFIG_ARCH_S3C64XX) += s3c6410-mini6410.dtb \
        s3c6410-smdk6410.dtb
-dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += emev2-kzm9d.dtb \
-       r7s72100-genmai.dtb \
+dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += r7s72100-genmai.dtb \
        r7s72100-genmai-reference.dtb \
        r8a7740-armadillo800eva.dtb \
        r8a7778-bockw.dtb \
@@ -315,6 +322,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += emev2-kzm9d.dtb \
        sh7372-mackerel.dtb
 dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \
        r7s72100-genmai-reference.dtb \
+       r8a7791-henninger.dtb \
        r8a7791-koelsch.dtb \
        r8a7790-lager.dtb
 dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_arria5_socdk.dtb \
@@ -361,6 +369,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
        tegra30-cardhu-a02.dtb \
        tegra30-cardhu-a04.dtb \
        tegra114-dalmore.dtb \
+       tegra114-tn7.dtb \
+       tegra124-jetson-tk1.dtb \
        tegra124-venice2.dtb
 dtb-$(CONFIG_ARCH_U300) += ste-u300.dtb
 dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \
index 07f283c20eb12260f362753e544ddd2e6584b75d..baf56cc92040ed27ecb006ef32defaef6f7cf037 100644 (file)
                mac: ethernet@4a100000 {
                        compatible = "ti,cpsw";
                        ti,hwmods = "cpgmac0";
+                       clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;
+                       clock-names = "fck", "cpts";
                        cpdma_channels = <8>;
                        ale_entries = <1024>;
                        bd_ram_size = <0x2000>;
                              <0x46000000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <80>, <81>;
-                       interrupts-names = "tx", "rx";
+                       interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 8>,
                                <&edma 9>;
                              <0x46400000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <82>, <83>;
-                       interrupts-names = "tx", "rx";
+                       interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 10>,
                                <&edma 11>;
index 788391f916844130d8d6cdb2722479163863a707..5a452fdd7c5d9711cec9f6d0196f90b0726fefc3 100644 (file)
        };
 };
 
+&iva {
+       status = "disabled";
+};
+
+&mailbox {
+       status = "disabled";
+};
+
+&mmu_isp {
+       status = "disabled";
+};
+
+&smartreflex_mpu_iva {
+       status = "disabled";
+};
+
 /include/ "am35xx-clocks.dtsi"
 /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
index 36d523a268314d3e1948dd894ae6b07141ac946e..03a2255051260ce50f8480f974316996dbae57f4 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ti,hwmods = "cpgmac0";
+                       clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;
+                       clock-names = "fck", "cpts";
                        status = "disabled";
                        cpdma_channels = <8>;
                        ale_entries = <1024>;
                              <0x46000000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <80>, <81>;
-                       interrupts-names = "tx", "rx";
+                       interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 8>,
                               <&edma 9>;
                              <0x46400000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <82>, <83>;
-                       interrupts-names = "tx", "rx";
+                       interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 10>,
                               <&edma 11>;
index df8798e8bd255bbf789da0b44f5229b9f3dc80dd..a055f7f0f14ae5a3e080489c9c424bd37be0e1c0 100644 (file)
        status = "okay";
 };
 
+&gpio5 {
+       status = "okay";
+       ti,no-reset-on-init;
+};
+
 &mmc1 {
        status = "okay";
        vmmc-supply = <&vmmcsd_fixed>;
index 82f238a9063ffe47d10dbe083f136e1876f8efd2..416f4e5a69c154cbf673d22bcf7021d63b2267ec 100644 (file)
@@ -35,7 +35,6 @@
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
                        sata@a0000 {
@@ -67,6 +66,7 @@
                        i2c@11000 {
                                pinctrl-0 = <&i2c0_pins>;
                                pinctrl-names = "default";
+                               clock-frequency = <100000>;
                                status = "okay";
                                audio_codec: audio-codec@4a {
                                        compatible = "cirrus,cs42l51";
index 2354fe023ee01ee6f9df5e1b0f23e6e9498acf86..097df7d8f0f6c624fb5531d0257d7f5f67eee4fc 100644 (file)
@@ -47,7 +47,6 @@
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
                        timer@20300 {
index 651aeb5ef43956e27cb945ae1e5d6dc2bce560e9..d6d572e5af321482b20aa1fd08baed1f445a37eb 100644 (file)
@@ -50,7 +50,6 @@
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
 
index 4e27587667bf5df680bb18af95f43633e90fced1..c5fe8b5dcdc7dab6250597efb80b7b2b0c8ea321 100644 (file)
@@ -50,7 +50,6 @@
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
 
index 3e2c857d600008a896d3402572fedd8d68bbf624..4169f4096ea3bd6885339f31106135c89b6fc681 100644 (file)
@@ -51,7 +51,6 @@
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
                        sata@a0000 {
index bb77970c0b1223499137ef80079ad39446919f42..23227e0027ec3f96baf017d3e84fafe4319ff683 100644 (file)
                                reg-shift = <2>;
                                interrupts = <41>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
                        serial@12100 {
                                reg-shift = <2>;
                                interrupts = <42>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
 
                                reg = <0x20300 0x34>, <0x20704 0x4>;
                        };
 
+                       pmsu@22000 {
+                               compatible = "marvell,armada-370-pmsu";
+                               reg = <0x22000 0x1000>;
+                       };
+
                        usb@50000 {
                                compatible = "marvell,orion-ehci";
                                reg = <0x50000 0x500>;
index af1f11e9e5a011d526f64f8afaa60d000ef87542..21b588b6f6bd7559d30109e27913e9ea27919dc6 100644 (file)
                                clocks = <&coreclk 2>;
                        };
 
+                       cpurst@20800 {
+                               compatible = "marvell,armada-370-cpu-reset";
+                               reg = <0x20800 0x8>;
+                       };
+
                        audio_controller: audio-controller@30000 {
                                compatible = "marvell,armada370-audio";
                                reg = <0x30000 0x4000>;
index 9378d3136b41d7b37f11abdf01186c019758f7f1..20f1f33c947d730c89456c1554137afd7b457a18 100644 (file)
@@ -68,7 +68,6 @@
                        };
 
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
 
                                };
                        };
 
+                       sata@a0000 {
+                               status = "okay";
+                               nr-ports = <2>;
+                       };
+
                        nand: nand@d0000 {
                                pinctrl-0 = <&nand_pins>;
                                pinctrl-names = "default";
index 3877693fb2d875ef0249a67aa748f00e557f32f3..3b6de4c0e37922cb7bfa7d4fb1850b05de0913b2 100644 (file)
@@ -39,6 +39,8 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
+               enable-method = "marvell,armada-375-smp";
+
                cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                                cache-level = <2>;
                        };
 
+                       scu@c000 {
+                               compatible = "arm,cortex-a9-scu";
+                               reg = <0xc000 0x58>;
+                       };
+
                        timer@c600 {
                                compatible = "arm,cortex-a9-twd-timer";
                                reg = <0xc600 0x20>;
                                reg-shift = <2>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
 
                                reg-shift = <2>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
 
                                clocks = <&coreclk 0>;
                        };
 
+                       watchdog@20300 {
+                               compatible = "marvell,armada-375-wdt";
+                               reg = <0x20300 0x34>, <0x20704 0x4>, <0x18254 0x4>;
+                               clocks = <&coreclk 0>;
+                       };
+
+                       cpurst@20800 {
+                               compatible = "marvell,armada-370-cpu-reset";
+                               reg = <0x20800 0x10>;
+                       };
+
+                       coherency-fabric@21010 {
+                               compatible = "marvell,armada-375-coherency-fabric";
+                               reg = <0x21010 0x1c>;
+                       };
+
                        xor@60800 {
                                compatible = "marvell,orion-xor";
                                reg = <0x60800 0x100
                                status = "disabled";
                        };
 
+                       thermal@e8078 {
+                               compatible = "marvell,armada375-thermal";
+                               reg = <0xe8078 0x4>, <0xe807c 0x8>;
+                               status = "okay";
+                       };
+
                        coreclk: mvebu-sar@e8204 {
                                compatible = "marvell,armada-375-core-clock";
                                reg = <0xe8204 0x04>;
index 068031f0f263ef081f590eae7ac3da0df629ab2d..aa71718b549d0a7d5278d14641ff4a130cdb6d70 100644 (file)
@@ -21,6 +21,8 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
+               enable-method = "marvell,armada-380-smp";
+
                cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
index 6828d77696a67647397c568e5bce65f007e0c10d..7fcbc0d2a85ff868329058c9eab96ba518f7b073 100644 (file)
@@ -55,7 +55,6 @@
                        };
 
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
 
                                };
                        };
 
+                       sata@a8000 {
+                               status = "okay";
+                       };
+
+                       sata@e0000 {
+                               status = "okay";
+                       };
+
                        flash@d0000 {
                                status = "okay";
                                num-cs = <1>;
                                        reg = <0x1000000 0x3f000000>;
                                };
                        };
+
+                       sdhci@d8000 {
+                               clock-frequency = <200000000>;
+                               broken-cd;
+                               wp-inverted;
+                               bus-width = <8>;
+                               status = "okay";
+                       };
                };
 
                pcie-controller {
index 45250c88814b89c6b83213c7572c8896f7190e2b..4b39bed4ed07d11e4e1b70613a782b74694b8650 100644 (file)
@@ -51,7 +51,6 @@
                        };
 
                        serial@12000 {
-                               clock-frequency = <200000000>;
                                status = "okay";
                        };
 
index e2919f02e1d47687c77477b1a9bd389a32a4134e..2c7990d6efa220e4524de0ecb5913c05ad953a96 100644 (file)
@@ -21,6 +21,8 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
+               enable-method = "marvell,armada-380-smp";
+
                cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
index ca8813bb99ba627d52e7c9d163005d39481f3e1a..6ee59a34408902e4ab8182ceff8a1900841090b3 100644 (file)
                                cache-level = <2>;
                        };
 
+                       scu@c000 {
+                               compatible = "arm,cortex-a9-scu";
+                               reg = <0xc000 0x58>;
+                       };
+
                        timer@c600 {
                                compatible = "arm,cortex-a9-twd-timer";
                                reg = <0xc600 0x20>;
                                reg-shift = <2>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
 
                                reg-shift = <2>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
 
                                clock-names = "nbclk", "fixed";
                        };
 
+                       watchdog@20300 {
+                               compatible = "marvell,armada-380-wdt";
+                               reg = <0x20300 0x34>, <0x20704 0x4>, <0x18260 0x4>;
+                               clocks = <&coreclk 2>, <&refclk>;
+                               clock-names = "nbclk", "fixed";
+                       };
+
+                       cpurst@20800 {
+                               compatible = "marvell,armada-370-cpu-reset";
+                               reg = <0x20800 0x10>;
+                       };
+
+                       coherency-fabric@21010 {
+                               compatible = "marvell,armada-380-coherency-fabric";
+                               reg = <0x21010 0x1c>;
+                       };
+
+                       pmsu@22000 {
+                               compatible = "marvell,armada-380-pmsu";
+                               reg = <0x22000 0x1000>;
+                       };
+
                        eth1: ethernet@30000 {
                                compatible = "marvell,armada-370-neta";
                                reg = <0x30000 0x4000>;
                                clocks = <&gateclk 4>;
                        };
 
+                       sata@a8000 {
+                               compatible = "marvell,armada-380-ahci";
+                               reg = <0xa8000 0x2000>;
+                               interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&gateclk 15>;
+                               status = "disabled";
+                       };
+
+                       sata@e0000 {
+                               compatible = "marvell,armada-380-ahci";
+                               reg = <0xe0000 0x2000>;
+                               interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&gateclk 30>;
+                               status = "disabled";
+                       };
+
                        coredivclk: clock@e4250 {
                                compatible = "marvell,armada-380-corediv-clock";
                                reg = <0xe4250 0xc>;
                                clock-output-names = "nand";
                        };
 
+                       thermal@e8078 {
+                               compatible = "marvell,armada380-thermal";
+                               reg = <0xe4078 0x4>, <0xe4074 0x4>;
+                               status = "okay";
+                       };
+
                        flash@d0000 {
                                compatible = "marvell,armada370-nand";
                                reg = <0xd0000 0x54>;
                                clocks = <&coredivclk 0>;
                                status = "disabled";
                        };
+
+                       sdhci@d8000 {
+                               compatible = "marvell,armada-380-sdhci";
+                               reg = <0xd8000 0x1000>, <0xdc000 0x100>;
+                               interrupts = <0 25 0x4>;
+                               clocks = <&gateclk 17>;
+                               mrvl,clk-delay-cycles = <0x1F>;
+                               status = "disabled";
+                       };
                };
        };
 
index d83d7d69ac01ff7f33c33677ff16bf7d906d5f1c..a55a97a705056a72a0e480c9c6a60fc4c1a50381 100644 (file)
                        };
 
                        serial@12000 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
 
                        serial@12100 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
 
index 448373c4b0e534c1d2ce08592981f5d38bad39a8..42ddb2864365684a046bbb64461dc096b96c022e 100644 (file)
@@ -49,7 +49,7 @@
                        /* Device Bus parameters are required */
 
                        /* Read parameters */
-                       devbus,bus-width    = <8>;
+                       devbus,bus-width    = <16>;
                        devbus,turn-off-ps  = <60000>;
                        devbus,badr-skew-ps = <0>;
                        devbus,acc-first-ps = <124000>;
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12100 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12200 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12300 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
 
index 61bda687f782f65485f958adb8d8ec2822ebde35..0478c55ca6567a6e780098598ef0a36d2fb223ea 100644 (file)
@@ -59,7 +59,7 @@
                        /* Device Bus parameters are required */
 
                        /* Read parameters */
-                       devbus,bus-width    = <8>;
+                       devbus,bus-width    = <16>;
                        devbus,turn-off-ps  = <60000>;
                        devbus,badr-skew-ps = <0>;
                        devbus,acc-first-ps = <124000>;
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12100 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12200 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12300 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
 
                        ethernet@70000 {
                                status = "okay";
                                phy = <&phy0>;
-                               phy-mode = "rgmii-id";
+                               phy-mode = "qsgmii";
                        };
                        ethernet@74000 {
                                status = "okay";
                                phy = <&phy1>;
-                               phy-mode = "rgmii-id";
+                               phy-mode = "qsgmii";
                        };
                        ethernet@30000 {
                                status = "okay";
                                phy = <&phy2>;
-                               phy-mode = "rgmii-id";
+                               phy-mode = "qsgmii";
                        };
                        ethernet@34000 {
                                status = "okay";
                                phy = <&phy3>;
-                               phy-mode = "rgmii-id";
+                               phy-mode = "qsgmii";
                        };
 
                        /* Front-side USB slot */
index c2242745b9b87a29afcfcc2fc77bf9178d5814f9..25674fe81f703d279dc154ff75d02d366b34cef6 100644 (file)
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12100 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12200 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12300 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
 
index 98335fb34b7ad5a11d9f40b6564bddc161431455..1257ff1ed278e68a33793eb9cf0c40be08e0b169 100644 (file)
@@ -27,6 +27,7 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
+               enable-method = "marvell,armada-xp-smp";
 
                cpu@0 {
                        device_type = "cpu";
index 9480cf891f8cd0ce475d87cf2eed904a6a740eb7..3396b25b39e179cb1a444435adfa28c87385e8ed 100644 (file)
@@ -29,6 +29,7 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
+               enable-method = "marvell,armada-xp-smp";
 
                cpu@0 {
                        device_type = "cpu";
index 31ba6d8fbadf8803f28aca6312c8205c79c23aee..6da84bf40aaf48849d308453755c1eca3605396b 100644 (file)
@@ -30,6 +30,7 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
+               enable-method = "marvell,armada-xp-smp";
 
                cpu@0 {
                        device_type = "cpu";
index ff049ee862ebd2d8a271d70a0b2e20206f47592f..0cf999abc4ed768abf20b2b32c9d5299a7be9a71 100644 (file)
                        };
 
                        serial@12000 {
-                               clocks = <&coreclk 0>;
                                status = "okay";
                        };
 
index 985948ce67b3271a65c9b4a413a99e7d255b12e7..e5c6a0492ca00b922c5a5cebae7e770de2e15e2f 100644 (file)
@@ -39,7 +39,7 @@
                        /* Device Bus parameters are required */
 
                        /* Read parameters */
-                       devbus,bus-width    = <8>;
+                       devbus,bus-width    = <16>;
                        devbus,turn-off-ps  = <60000>;
                        devbus,badr-skew-ps = <0>;
                        devbus,acc-first-ps = <124000>;
 
                internal-regs {
                        serial@12000 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        serial@12100 {
-                               clock-frequency = <250000000>;
                                status = "okay";
                        };
                        pinctrl {
index abb9f9dcc525a6a7c1583e5f1f7c65d4ff29e485..5902e8359c9165c33cc265b0a304df33acb640b5 100644 (file)
@@ -58,6 +58,7 @@
                                reg-shift = <2>;
                                interrupts = <43>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
                        serial@12300 {
@@ -66,6 +67,7 @@
                                reg-shift = <2>;
                                interrupts = <44>;
                                reg-io-width = <1>;
+                               clocks = <&coreclk 0>;
                                status = "disabled";
                        };
 
                                clock-names = "nbclk", "fixed";
                        };
 
-                       armada-370-xp-pmsu@22000 {
-                               compatible = "marvell,armada-370-xp-pmsu";
-                               reg = <0x22100 0x400>, <0x20800 0x20>;
+                       cpurst@20800 {
+                               compatible = "marvell,armada-370-cpu-reset";
+                               reg = <0x20800 0x20>;
                        };
 
                        eth2: ethernet@30000 {
index ce1375595e5f27117c37881bcafa5fc5805b1455..4537259ce5299baf8cf68978d7c2d106c5f67c32 100644 (file)
@@ -34,7 +34,7 @@
                        };
 
                        spi0: spi@f0004000 {
-                               cs-gpios = <&pioD 13 0>;
+                               cs-gpios = <&pioD 13 0>, <0>, <0>, <&pioD 16 0>;
                                status = "okay";
                        };
 
@@ -79,7 +79,7 @@
                        };
 
                        spi1: spi@f8008000 {
-                               cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>;
+                               cs-gpios = <&pioC 25 0>;
                                status = "okay";
                        };
 
index e21dda0e8986574b2531c1675eca1b4de164822d..3be973e9889a2b0ef29cc45657ad6eeb056e7f5f 100644 (file)
@@ -10,7 +10,7 @@
 #include <dt-bindings/pinctrl/at91.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/clk/at91.h>
+#include <dt-bindings/clock/at91.h>
 
 / {
        model = "Atmel AT91SAM9261 family SoC";
index 9cdaecff13b3996932fc7564a8c4927cd97024c6..ace6bf197b708dd79e29054773d50c5f1a3fd864 100644 (file)
                                      >;
 
                                /* shared pinctrl settings */
+                               adc0 {
+                                       pinctrl_adc0_adtrg: adc0_adtrg {
+                                               atmel,pins = <AT91_PIOD 28 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad0: adc0_ad0 {
+                                               atmel,pins = <AT91_PIOD 20 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad1: adc0_ad1 {
+                                               atmel,pins = <AT91_PIOD 21 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad2: adc0_ad2 {
+                                               atmel,pins = <AT91_PIOD 22 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad3: adc0_ad3 {
+                                               atmel,pins = <AT91_PIOD 23 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad4: adc0_ad4 {
+                                               atmel,pins = <AT91_PIOD 24 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad5: adc0_ad5 {
+                                               atmel,pins = <AT91_PIOD 25 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad6: adc0_ad6 {
+                                               atmel,pins = <AT91_PIOD 26 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                                       pinctrl_adc0_ad7: adc0_ad7 {
+                                               atmel,pins = <AT91_PIOD 27 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
+                               };
+
                                dbgu {
                                        pinctrl_dbgu: dbgu-0 {
                                                atmel,pins =
                        adc0: adc@fffb0000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "atmel,at91sam9260-adc";
+                               compatible = "atmel,at91sam9g45-adc";
                                reg = <0xfffb0000 0x100>;
                                interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>;
-                               atmel,adc-use-external-triggers;
                                atmel,adc-channels-used = <0xff>;
                                atmel,adc-vref = <3300>;
                                atmel,adc-startup-time = <40>;
index 7ff665a8c7080b2634fd2095e9b24fb550044a4b..9f5b0a6749955755b75ece053be16d6c563be051 100644 (file)
@@ -8,6 +8,7 @@
  */
 /dts-v1/;
 #include "at91sam9g45.dtsi"
+#include <dt-bindings/pwm/pwm.h>
 
 / {
        model = "Atmel AT91SAM9M10G45-EK";
                                status = "okay";
                        };
 
+                       adc0: adc@fffb0000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <
+                                       &pinctrl_adc0_ad0
+                                       &pinctrl_adc0_ad1
+                                       &pinctrl_adc0_ad2
+                                       &pinctrl_adc0_ad3
+                                       &pinctrl_adc0_ad4
+                                       &pinctrl_adc0_ad5
+                                       &pinctrl_adc0_ad6
+                                       &pinctrl_adc0_ad7>;
+                               atmel,adc-ts-wires = <4>;
+                               status = "okay";
+                       };
+
                        pwm0: pwm@fffb8000 {
                                status = "okay";
 
 
                d6 {
                        label = "d6";
-                       pwms = <&pwm0 3 5000 0>;
+                       pwms = <&pwm0 3 5000 PWM_POLARITY_INVERTED>;
                        max-brightness = <255>;
                        linux,default-trigger = "nand-disk";
                };
 
                d7 {
                        label = "d7";
-                       pwms = <&pwm0 1 5000 0>;
+                       pwms = <&pwm0 1 5000 PWM_POLARITY_INVERTED>;
                        max-brightness = <255>;
                        linux,default-trigger = "mmc0";
                };
index 63e1784d272c556974023fcfd7d46ba7a0510e3d..b9714f5c61dcd5b27693c5c675a50c4c9dae99bf 100644 (file)
@@ -8,9 +8,10 @@
 
 #include "skeleton.dtsi"
 #include <dt-bindings/pinctrl/at91.h>
-#include <dt-bindings/clk/at91.h>
+#include <dt-bindings/clock/at91.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
        model = "Atmel AT91SAM9RL family SoC";
@@ -32,6 +33,7 @@
                i2c1 = &i2c1;
                ssc0 = &ssc0;
                ssc1 = &ssc1;
+               pwm0 = &pwm0;
        };
 
        cpus {
                reg = <0x20000000 0x04000000>;
        };
 
+       clocks {
+               adc_op_clk: adc_op_clk{
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <1000000>;
+               };
+       };
+
        ahb {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                ranges;
 
+               fb0: fb@00500000 {
+                       compatible = "atmel,at91sam9rl-lcdc";
+                       reg = <0x00500000 0x1000>;
+                       interrupts = <23 IRQ_TYPE_LEVEL_HIGH 3>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_fb>;
+                       clocks = <&lcd_clk>, <&lcd_clk>;
+                       clock-names = "hclk", "lcdc_clk";
+                       status = "disabled";
+               };
+
                nand0: nand@40000000 {
                        compatible = "atmel,at91rm9200-nand";
                        #address-cells = <1>;
                                status = "disabled";
                        };
 
+                       pwm0: pwm@fffc8000 {
+                               compatible = "atmel,at91sam9rl-pwm";
+                               reg = <0xfffc8000 0x300>;
+                               interrupts = <19 IRQ_TYPE_LEVEL_HIGH 4>;
+                               #pwm-cells = <3>;
+                               clocks = <&pwm_clk>;
+                               clock-names = "pwm_clk";
+                               status = "disabled";
+                       };
+
                        spi0: spi@fffcc000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
                                status = "disabled";
                        };
 
+                       adc0: adc@fffd0000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "atmel,at91sam9rl-adc";
+                               reg = <0xfffd0000 0x100>;
+                               interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>;
+                               clocks = <&adc_clk>, <&adc_op_clk>;
+                               clock-names = "adc_clk", "adc_op_clk";
+                               atmel,adc-use-external-triggers;
+                               atmel,adc-channels-used = <0x3f>;
+                               atmel,adc-vref = <3300>;
+                               atmel,adc-startup-time = <40>;
+                               atmel,adc-res = <8 10>;
+                               atmel,adc-res-names = "lowres", "highres";
+                               atmel,adc-use-res = "highres";
+
+                               trigger@0 {
+                                       reg = <0>;
+                                       trigger-name = "timer-counter-0";
+                                       trigger-value = <0x1>;
+                               };
+                               trigger@1 {
+                                       reg = <1>;
+                                       trigger-name = "timer-counter-1";
+                                       trigger-value = <0x3>;
+                               };
+
+                               trigger@2 {
+                                       reg = <2>;
+                                       trigger-name = "timer-counter-2";
+                                       trigger-value = <0x5>;
+                               };
+
+                               trigger@3 {
+                                       reg = <3>;
+                                       trigger-name = "external";
+                                       trigger-value = <0x13>;
+                                       trigger-external;
+                               };
+                       };
+
+                       usb0: gadget@fffd4000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "atmel,at91sam9rl-udc";
+                               reg = <0x00600000 0x100000>,
+                                     <0xfffd4000 0x4000>;
+                               interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
+                               clocks = <&udphs_clk>, <&utmi>;
+                               clock-names = "pclk", "hclk";
+                               status = "disabled";
+
+                               ep0 {
+                                       reg = <0>;
+                                       atmel,fifo-size = <64>;
+                                       atmel,nb-banks = <1>;
+                               };
+
+                               ep1 {
+                                       reg = <1>;
+                                       atmel,fifo-size = <1024>;
+                                       atmel,nb-banks = <2>;
+                                       atmel,can-dma;
+                                       atmel,can-isoc;
+                               };
+
+                               ep2 {
+                                       reg = <2>;
+                                       atmel,fifo-size = <1024>;
+                                       atmel,nb-banks = <2>;
+                                       atmel,can-dma;
+                                       atmel,can-isoc;
+                               };
+
+                               ep3 {
+                                       reg = <3>;
+                                       atmel,fifo-size = <1024>;
+                                       atmel,nb-banks = <3>;
+                                       atmel,can-dma;
+                               };
+
+                               ep4 {
+                                       reg = <4>;
+                                       atmel,fifo-size = <1024>;
+                                       atmel,nb-banks = <3>;
+                                       atmel,can-dma;
+                               };
+
+                               ep5 {
+                                       reg = <5>;
+                                       atmel,fifo-size = <1024>;
+                                       atmel,nb-banks = <3>;
+                                       atmel,can-dma;
+                                       atmel,can-isoc;
+                               };
+
+                               ep6 {
+                                       reg = <6>;
+                                       atmel,fifo-size = <1024>;
+                                       atmel,nb-banks = <3>;
+                                       atmel,can-dma;
+                                       atmel,can-isoc;
+                               };
+                       };
+
                        ramc0: ramc@ffffea00 {
                                compatible = "atmel,at91sam9260-sdramc";
                                reg = <0xffffea00 0x200>;
                                        <0x003fffff 0x0001ff3c>;  /* pioD */
 
                                /* shared pinctrl settings */
+                               adc0 {
+                                       pinctrl_adc0_ts: adc0_ts-0 {
+                                               atmel,pins =
+                                                       <AT91_PIOA 17 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOA 18 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOA 19 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOA 20 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_ad0: adc0_ad0-0 {
+                                               atmel,pins = <AT91_PIOA 17 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_ad1: adc0_ad1-0 {
+                                               atmel,pins = <AT91_PIOA 18 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_ad2: adc0_ad2-0 {
+                                               atmel,pins = <AT91_PIOA 19 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_ad3: adc0_ad3-0 {
+                                               atmel,pins = <AT91_PIOA 20 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_ad4: adc0_ad4-0 {
+                                               atmel,pins = <AT91_PIOD 6 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_ad5: adc0_ad5-0 {
+                                               atmel,pins = <AT91_PIOD 7 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_adc0_adtrg: adc0_adtrg-0 {
+                                               atmel,pins = <AT91_PIOB 15 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+                               };
+
                                dbgu {
                                        pinctrl_dbgu: dbgu-0 {
                                                atmel,pins =
                                        };
                                };
 
+                               fb {
+                                       pinctrl_fb: fb-0 {
+                                               atmel,pins =
+                                                       <AT91_PIOC 1 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 3 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 5 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 6 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 7 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 9 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 10 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 11 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 12 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 13 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 15 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 16 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 17 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 18 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 19 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 20 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 21 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 22 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 23 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 24 AT91_PERIPH_B AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOC 25 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+                               };
+
                                i2c_gpio0 {
                                        pinctrl_i2c_gpio0: i2c_gpio0-0 {
                                                atmel,pins =
                                        };
                                };
 
+                               pwm0 {
+                                       pinctrl_pwm0_pwm0_0: pwm0_pwm0-0 {
+                                               atmel,pins = <AT91_PIOB 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm0_1: pwm0_pwm0-1 {
+                                               atmel,pins = <AT91_PIOC 2 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm0_2: pwm0_pwm0-2 {
+                                               atmel,pins = <AT91_PIOD 14 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm1_0: pwm0_pwm1-0 {
+                                               atmel,pins = <AT91_PIOB 9 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm1_1: pwm0_pwm1-1 {
+                                               atmel,pins = <AT91_PIOC 3 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm1_2: pwm0_pwm1-2 {
+                                               atmel,pins = <AT91_PIOD 15 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm2_0: pwm0_pwm2-0 {
+                                               atmel,pins = <AT91_PIOD 5 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm2_1: pwm0_pwm2-1 {
+                                               atmel,pins = <AT91_PIOD 12 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm2_2: pwm0_pwm2-2 {
+                                               atmel,pins = <AT91_PIOD 16 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm3_0: pwm0_pwm3-0 {
+                                               atmel,pins = <AT91_PIOD 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+                                       };
+
+                                       pinctrl_pwm0_pwm3_1: pwm0_pwm3-1 {
+                                               atmel,pins = <AT91_PIOD 18 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+                               };
+
+                               spi0 {
+                                       pinctrl_spi0: spi0-0 {
+                                               atmel,pins =
+                                                       <AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+                                                       <AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+                                       };
+                               };
+
                                ssc0 {
                                        pinctrl_ssc0_tx: ssc0_tx-0 {
                                                atmel,pins =
                                        };
                                };
 
-                               spi0 {
-                                       pinctrl_spi0: spi0-0 {
-                                               atmel,pins =
-                                                       <AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE>,
-                                                       <AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE>,
-                                                       <AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_NONE>;
-                                       };
-                               };
-
                                tcb0 {
                                        pinctrl_tcb0_tclk0: tcb0_tclk0-0 {
                                                atmel,pins = <AT91_PIOA 3 AT91_PERIPH_B AT91_PINCTRL_NONE>;
index cddb37825fad5adc5990b1cbfa216853ce62b3bb..f148fa4b3ab98d470d6c5a8adcc8a74986c9e94d 100644 (file)
        };
 
        ahb {
+               fb0: fb@00500000 {
+                       display = <&display0>;
+                       status = "okay";
+
+                       display0: display {
+                               bits-per-pixel = <16>;
+                               atmel,lcdcon-backlight;
+                               atmel,dmacon = <0x1>;
+                               atmel,lcdcon2 = <0x80008002>;
+                               atmel,guard-time = <1>;
+                               atmel,lcd-wiring-mode = "RGB";
+
+                               display-timings {
+                                       native-mode = <&timing0>;
+                                       timing0: timing0 {
+                                               clock-frequency = <4965000>;
+                                               hactive = <240>;
+                                               vactive = <320>;
+                                               hback-porch = <1>;
+                                               hfront-porch = <33>;
+                                               vback-porch = <1>;
+                                               vfront-porch = <0>;
+                                               hsync-len = <5>;
+                                               vsync-len = <1>;
+                                               hsync-active = <1>;
+                                               vsync-active = <1>;
+                                       };
+                               };
+                       };
+               };
+
                nand0: nand@40000000 {
                        nand-bus-width = <8>;
                        nand-ecc-mode = "soft";
                                status = "okay";
                        };
 
+                       adc0: adc@fffd0000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <
+                                       &pinctrl_adc0_ad0
+                                       &pinctrl_adc0_ad1
+                                       &pinctrl_adc0_ad2
+                                       &pinctrl_adc0_ad3
+                                       &pinctrl_adc0_ad4
+                                       &pinctrl_adc0_ad5
+                                       &pinctrl_adc0_adtrg>;
+                               atmel,adc-ts-wires = <4>;
+                               status = "okay";
+                       };
+
+                       usb0: gadget@fffd4000 {
+                               atmel,vbus-gpio = <&pioA 8 GPIO_ACTIVE_HIGH>;
+                               status = "okay";
+                       };
+
+                       spi0: spi@fffcc000 {
+                               status = "okay";
+                               cs-gpios = <&pioA 28 0>, <0>, <0>, <0>;
+                               mtd_dataflash@0 {
+                                       compatible = "atmel,at45", "atmel,dataflash";
+                                       spi-max-frequency = <15000000>;
+                                       reg = <0>;
+                               };
+                       };
+
+                       pwm0: pwm@fffc8000 {
+                               status = "okay";
+
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_pwm0_pwm1_2>,
+                                       <&pinctrl_pwm0_pwm2_2>;
+                       };
+
                        dbgu: serial@fffff200 {
                                status = "okay";
                        };
                };
        };
 
-       leds {
-               compatible = "gpio-leds";
+       pwmleds {
+               compatible = "pwm-leds";
 
                ds1 {
                        label = "ds1";
-                       gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
+                       pwms = <&pwm0 1 5000 PWM_POLARITY_INVERTED>;
+                       max-brightness = <255>;
                };
 
                ds2 {
                        label = "ds2";
-                       gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
+                       pwms = <&pwm0 2 5000 PWM_POLARITY_INVERTED>;
+                       max-brightness = <255>;
                };
+       };
+
+       leds {
+               compatible = "gpio-leds";
 
                ds3 {
                        label = "ds3";
                        gpio-key,wakeup;
                };
        };
+
+       i2c@0 {
+               status = "okay";
+       };
+
+       i2c@1 {
+               status = "okay";
+       };
 };
index 56a1af2f10529bbfc473e0a8eff00bc1e1a9bf2c..74f7812a84b543c80c4befbfadcb5e2429ea7a4d 100644 (file)
                };
        };
 
-       clocks {
-               smclk: sysmgr-clock {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <25000000>;
-               };
+       smclk: sysmgr-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
 
-               cfgclk: cfg-clock {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <100000000>;
-               };
+       cfgclk: cfg-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <100000000>;
+       };
 
-               sysclk: system-clock {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <400000000>;
-               };
+       twdclk: twdclk {
+               compatible = "fixed-factor-clock";
+               #clock-cells = <0>;
+               clocks = <&cpupll>;
+               clock-mult = <1>;
+               clock-div = <3>;
        };
 
        soc {
                        cache-level = <2>;
                };
 
+               scu: snoop-control-unit@ad0000 {
+                       compatible = "arm,cortex-a9-scu";
+                       reg = <0xad0000 0x58>;
+               };
+
                gic: interrupt-controller@ad1000 {
                        compatible = "arm,cortex-a9-gic";
                        reg = <0xad1000 0x1000>, <0xad0100 0x0100>;
                        compatible = "arm,cortex-a9-twd-timer";
                        reg = <0xad0600 0x20>;
                        interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&sysclk>;
+                       clocks = <&twdclk>;
+               };
+
+               syspll: syspll@ea0014 {
+                       compatible = "marvell,berlin2-pll";
+                       clocks = <&smclk>;
+                       #clock-cells = <0>;
+                       reg = <0xea0014 0x8>;
+               };
+
+               cpupll: cpupll@ea003c {
+                       compatible = "marvell,berlin2-pll";
+                       clocks = <&smclk>;
+                       #clock-cells = <0>;
+                       reg = <0xea003c 0x8>;
                };
 
                apb@e80000 {
                        ranges = <0 0xe80000 0x10000>;
                        interrupt-parent = <&aic>;
 
+                       gpio0: gpio@0400 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0400 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porta: gpio-port@0 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <0>;
+                               };
+                       };
+
+                       gpio1: gpio@0800 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0800 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portb: gpio-port@1 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <1>;
+                               };
+                       };
+
+                       gpio2: gpio@0c00 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0c00 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portc: gpio-port@2 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <2>;
+                               };
+                       };
+
+                       gpio3: gpio@1000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x1000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portd: gpio-port@3 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <3>;
+                               };
+                       };
+
                        timer0: timer@2c00 {
                                compatible = "snps,dw-apb-timer";
                                reg = <0x2c00 0x14>;
                        };
                };
 
+               generic-regs@ea0184 {
+                       compatible = "marvell,berlin-generic-regs", "syscon";
+                       reg = <0xea0184 0x10>;
+               };
+
                apb@fc0000 {
                        compatible = "simple-bus";
                        #address-cells = <1>;
                        ranges = <0 0xfc0000 0x10000>;
                        interrupt-parent = <&sic>;
 
+                       sm_gpio1: gpio@5000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x5000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portf: gpio-port@5 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                               };
+                       };
+
+                       sm_gpio0: gpio@c000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0xc000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porte: gpio-port@4 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <11>;
+                               };
+                       };
+
                        uart0: serial@9000 {
                                compatible = "snps,dw-apb-uart";
                                reg = <0x9000 0x100>;
index 094968c275339be40b95a9d1dc437699a1e04aa7..b8163394b4c104c7ea6727f0a1d9b6fd9c345716 100644 (file)
                };
        };
 
-       clocks {
-               smclk: sysmgr-clock {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <25000000>;
-               };
+       smclk: sysmgr-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
 
-               cfgclk: cfg-clock {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <75000000>;
-               };
+       cfgclk: cfg-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <75000000>;
+       };
 
-               sysclk: system-clock {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <300000000>;
-               };
+       twdclk: twdclk {
+               compatible = "fixed-factor-clock";
+               #clock-cells = <0>;
+               clocks = <&cpupll>;
+               clock-mult = <1>;
+               clock-div = <3>;
        };
 
        soc {
                        compatible = "arm,cortex-a9-twd-timer";
                        reg = <0xad0600 0x20>;
                        interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&sysclk>;
+                       clocks = <&twdclk>;
+               };
+
+               syspll: syspll@ea0014 {
+                       compatible = "marvell,berlin2-pll";
+                       clocks = <&smclk>;
+                       #clock-cells = <0>;
+                       reg = <0xea0014 0x8>;
+               };
+
+               cpupll: cpupll@ea003c {
+                       compatible = "marvell,berlin2-pll";
+                       clocks = <&smclk>;
+                       #clock-cells = <0>;
+                       reg = <0xea003c 0x8>;
                };
 
                apb@e80000 {
                        ranges = <0 0xe80000 0x10000>;
                        interrupt-parent = <&aic>;
 
+                       gpio0: gpio@0400 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0400 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porta: gpio-port@0 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <0>;
+                               };
+                       };
+
+                       gpio1: gpio@0800 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0800 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portb: gpio-port@1 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <1>;
+                               };
+                       };
+
+                       gpio2: gpio@0c00 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0c00 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portc: gpio-port@2 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <2>;
+                               };
+                       };
+
+                       gpio3: gpio@1000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x1000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portd: gpio-port@3 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <3>;
+                               };
+                       };
+
                        timer0: timer@2c00 {
                                compatible = "snps,dw-apb-timer";
                                reg = <0x2c00 0x14>;
                        ranges = <0 0xfc0000 0x10000>;
                        interrupt-parent = <&sic>;
 
+                       sm_gpio1: gpio@5000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x5000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portf: gpio-port@5 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                               };
+                       };
+
+                       sm_gpio0: gpio@c000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0xc000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porte: gpio-port@4 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <8>;
+                                       reg = <0>;
+                               };
+                       };
+
                        uart0: serial@9000 {
                                compatible = "snps,dw-apb-uart";
                                reg = <0x9000 0x100>;
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
new file mode 100644 (file)
index 0000000..995150f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Antoine Ténart <antoine.tenart@free-electrons.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.
+ */
+
+/dts-v1/;
+#include "berlin2q.dtsi"
+
+/ {
+       model = "Marvell BG2-Q DMP";
+       compatible = "marvell,berlin2q-dmp", "marvell,berlin2q", "marvell,berlin";
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x80000000>;
+       };
+
+       choosen {
+               bootargs = "console=ttyS0,115200 earlyprintk";
+       };
+};
+
+&sdhci1 {
+       broken-cd;
+       sdhci,wp-inverted;
+       status = "okay";
+};
+
+&sdhci2 {
+       non-removable;
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
new file mode 100644 (file)
index 0000000..1a0caba
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2014 Antoine Ténart <antoine.tenart@free-electrons.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 <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "skeleton.dtsi"
+
+/ {
+       model = "Marvell Armada 1500 pro (BG2-Q) SoC";
+       compatible = "marvell,berlin2q", "marvell,berlin";
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       compatible = "arm,cortex-a9";
+                       device_type = "cpu";
+                       next-level-cache = <&l2>;
+                       reg = <0>;
+               };
+
+               cpu@1 {
+                       compatible = "arm,cortex-a9";
+                       device_type = "cpu";
+                       next-level-cache = <&l2>;
+                       reg = <1>;
+               };
+
+               cpu@2 {
+                       compatible = "arm,cortex-a9";
+                       device_type = "cpu";
+                       next-level-cache = <&l2>;
+                       reg = <2>;
+               };
+
+               cpu@3 {
+                       compatible = "arm,cortex-a9";
+                       device_type = "cpu";
+                       next-level-cache = <&l2>;
+                       reg = <3>;
+               };
+       };
+
+       smclk: sysmgr-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
+
+       cfgclk: config-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <100000000>;
+       };
+
+       twdclk: twdclk {
+               compatible = "fixed-factor-clock";
+               #clock-cells = <0>;
+               clocks = <&cpupll>;
+               clock-mult = <1>;
+               clock-div = <3>;
+       };
+
+       sdio1clk: sdio1clk {
+               compatible = "fixed-factor-clock";
+               #clock-cells = <0>;
+               clocks = <&syspll>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               ranges = <0 0xf7000000 0x1000000>;
+               interrupt-parent = <&gic>;
+
+               sdhci0: sdhci@ab0000 {
+                       compatible = "mrvl,pxav3-mmc";
+                       reg = <0xab0000 0x200>;
+                       clocks = <&sdio1clk>;
+                       interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
+               sdhci1: sdhci@ab0800 {
+                       compatible = "mrvl,pxav3-mmc";
+                       reg = <0xab0800 0x200>;
+                       clocks = <&sdio1clk>;
+                       interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
+               sdhci2: sdhci@ab1000 {
+                       compatible = "mrvl,pxav3-mmc";
+                       reg = <0xab1000 0x200>;
+                       interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&sdio1clk>;
+                       status = "disabled";
+               };
+
+               l2: l2-cache-controller@ac0000 {
+                       compatible = "arm,pl310-cache";
+                       reg = <0xac0000 0x1000>;
+                       cache-level = <2>;
+               };
+
+               scu: snoop-control-unit@ad0000 {
+                       compatible = "arm,cortex-a9-scu";
+                       reg = <0xad0000 0x58>;
+               };
+
+               local-timer@ad0600 {
+                       compatible = "arm,cortex-a9-twd-timer";
+                       reg = <0xad0600 0x20>;
+                       clocks = <&twdclk>;
+                       interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               gic: interrupt-controller@ad1000 {
+                       compatible = "arm,cortex-a9-gic";
+                       reg = <0xad1000 0x1000>, <0xad0100 0x100>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+               };
+
+               cpupll: cpupll@dd0170 {
+                       compatible = "marvell,berlin2q-pll";
+                       clocks = <&smclk>;
+                       #clock-cells = <0>;
+                       reg = <0xdd0170 0x8>;
+               };
+
+               syspll: syspll@ea0030 {
+                       compatible = "marvell,berlin2q-pll";
+                       clocks = <&smclk>;
+                       #clock-cells = <0>;
+                       reg = <0xea0030 0x8>;
+               };
+
+               apb@e80000 {
+                       compatible = "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       ranges = <0 0xe80000 0x10000>;
+                       interrupt-parent = <&aic>;
+
+                       gpio0: gpio@0400 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0400 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porta: gpio-port@0 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <0>;
+                               };
+                       };
+
+                       gpio1: gpio@0800 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0800 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portb: gpio-port@1 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <1>;
+                               };
+                       };
+
+                       gpio2: gpio@0c00 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x0c00 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portc: gpio-port@2 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <2>;
+                               };
+                       };
+
+                       gpio3: gpio@1000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x1000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portd: gpio-port@3 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                                       interrupts = <3>;
+                               };
+                       };
+
+                       timer0: timer@2c00 {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c00 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               interrupts = <8>;
+                       };
+
+                       timer1: timer@2c14 {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c14 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       timer2: timer@2c28 {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c28 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       timer3: timer@2c3c {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c3c 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       timer4: timer@2c50 {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c50 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       timer5: timer@2c64 {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c64 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       timer6: timer@2c78 {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c78 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       timer7: timer@2c8c {
+                               compatible = "snps,dw-apb-timer";
+                               reg = <0x2c8c 0x14>;
+                               clocks = <&cfgclk>;
+                               clock-names = "timer";
+                               status = "disabled";
+                       };
+
+                       aic: interrupt-controller@3800 {
+                               compatible = "snps,dw-apb-ictl";
+                               reg = <0x3800 0x30>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               interrupt-parent = <&gic>;
+                               interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       gpio4: gpio@5000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x5000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porte: gpio-port@4 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                               };
+                       };
+
+                       gpio5: gpio@c000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0xc000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portf: gpio-port@5 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                               };
+                       };
+               };
+
+               generic-regs@ea0110 {
+                       compatible = "marvell,berlin-generic-regs", "syscon";
+                       reg = <0xea0110 0x10>;
+               };
+
+               apb@fc0000 {
+                       compatible = "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       ranges = <0 0xfc0000 0x10000>;
+                       interrupt-parent = <&sic>;
+
+                       uart0: uart@9000 {
+                               compatible = "snps,dw-apb-uart";
+                               reg = <0x9000 0x100>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <8>;
+                               clocks = <&smclk>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       uart1: uart@a000 {
+                               compatible = "snps,dw-apb-uart";
+                               reg = <0xa000 0x100>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <9>;
+                               clocks = <&smclk>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       sic: interrupt-controller@e000 {
+                               compatible = "snps,dw-apb-ictl";
+                               reg = <0xe000 0x30>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               interrupt-parent = <&gic>;
+                               interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+       };
+};
index 62fb3da50bdbf7a84f9f872b3e9216c1617e0f3a..ad12da38fc922874823828e3369b64b7d1ad9474 100644 (file)
        fsl,uart-has-rtscts;
        status = "okay";
 };
+
+&usbhost1 {
+       phy_type = "serial";
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usbotg {
+       phy_type = "utmi";
+       dr_mode = "otg";
+       external-vbus-divider;
+       status = "okay";
+};
index f607ce520edae56fd9060ac8ca61e2663fbf35fc..c608942b8a3b65605ac8156fb9e9fe511b5c2792 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/input/input.h>
 #include "imx25.dtsi"
 
 / {
        memory {
                reg = <0x80000000 0x4000000>;
        };
+
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               reg_fec_3v3: regulator@0 {
+                       compatible = "regulator-fixed";
+                       reg = <0>;
+                       regulator-name = "fec-3v3";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio2 3 0>;
+                       enable-active-high;
+               };
+
+               reg_2p5v: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "2P5V";
+                       regulator-min-microvolt = <2500000>;
+                       regulator-max-microvolt = <2500000>;
+               };
+
+               reg_3p3v: regulator@2 {
+                       compatible = "regulator-fixed";
+                       reg = <2>;
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+               };
+
+               reg_can_3v3: regulator@3 {
+                       compatible = "regulator-fixed";
+                       reg = <3>;
+                       regulator-name = "can-3v3";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio4 6 0>;
+               };
+       };
+
+       sound {
+               compatible = "fsl,imx25-pdk-sgtl5000",
+                            "fsl,imx-audio-sgtl5000";
+               model = "imx25-pdk-sgtl5000";
+               ssi-controller = <&ssi1>;
+               audio-codec = <&codec>;
+               audio-routing =
+                       "MIC_IN", "Mic Jack",
+                       "Mic Jack", "Mic Bias",
+                       "Headphone Jack", "HP_OUT";
+               mux-int-port = <1>;
+               mux-ext-port = <4>;
+       };
 };
 
-&uart1 {
+&audmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_audmux>;
+       status = "okay";
+};
+
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_can1>;
+       xceiver-supply = <&reg_can_3v3>;
+       status = "okay";
+};
+
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       cd-gpios = <&gpio2 1 0>;
+       wp-gpios = <&gpio2 0 0>;
        status = "okay";
 };
 
 &fec {
        phy-mode = "rmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-supply = <&reg_fec_3v3>;
+       phy-reset-gpios = <&gpio4 8 0>;
        status = "okay";
 };
 
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       codec: sgtl5000@0a {
+               compatible = "fsl,sgtl5000";
+               reg = <0x0a>;
+               clocks = <&clks 129>;
+               VDDA-supply = <&reg_2p5v>;
+               VDDIO-supply = <&reg_3p3v>;
+       };
+};
+
+&iomuxc {
+       imx25-pdk {
+               pinctrl_audmux: audmuxgrp {
+                       fsl,pins = <
+                               MX25_PAD_RW__AUD4_TXFS                  0xe0
+                               MX25_PAD_OE__AUD4_TXC                   0xe0
+                               MX25_PAD_EB0__AUD4_TXD                  0xe0
+                               MX25_PAD_EB1__AUD4_RXD                  0xe0
+                       >;
+               };
+
+               pinctrl_can1: can1grp {
+                       fsl,pins = <
+                               MX25_PAD_GPIO_A__CAN1_TX                0x0
+                               MX25_PAD_GPIO_B__CAN1_RX                0x0
+                               MX25_PAD_D14__GPIO_4_6                  0x80000000
+                       >;
+               };
+
+               pinctrl_esdhc1: esdhc1grp {
+                       fsl,pins = <
+                               MX25_PAD_SD1_CMD__SD1_CMD               0x80000000
+                               MX25_PAD_SD1_CLK__SD1_CLK               0x80000000
+                               MX25_PAD_SD1_DATA0__SD1_DATA0           0x80000000
+                               MX25_PAD_SD1_DATA1__SD1_DATA1           0x80000000
+                               MX25_PAD_SD1_DATA2__SD1_DATA2           0x80000000
+                               MX25_PAD_SD1_DATA3__SD1_DATA3           0x80000000
+                               MX25_PAD_A14__GPIO_2_0                  0x80000000
+                               MX25_PAD_A15__GPIO_2_1                  0x80000000
+                       >;
+               };
+
+               pinctrl_fec: fecgrp {
+                       fsl,pins = <
+                               MX25_PAD_FEC_MDC__FEC_MDC               0x80000000
+                               MX25_PAD_FEC_MDIO__FEC_MDIO             0x400001e0
+                               MX25_PAD_FEC_TDATA0__FEC_TDATA0         0x80000000
+                               MX25_PAD_FEC_TDATA1__FEC_TDATA1         0x80000000
+                               MX25_PAD_FEC_TX_EN__FEC_TX_EN           0x80000000
+                               MX25_PAD_FEC_RDATA0__FEC_RDATA0         0x80000000
+                               MX25_PAD_FEC_RDATA1__FEC_RDATA1         0x80000000
+                               MX25_PAD_FEC_RX_DV__FEC_RX_DV           0x80000000
+                               MX25_PAD_FEC_TX_CLK__FEC_TX_CLK         0x1c0
+                               MX25_PAD_A17__GPIO_2_3                  0x80000000
+                               MX25_PAD_D12__GPIO_4_8                  0x80000000
+                       >;
+               };
+
+               pinctrl_i2c1: i2c1grp {
+                       fsl,pins = <
+                               MX25_PAD_I2C1_CLK__I2C1_CLK             0x80000000
+                               MX25_PAD_I2C1_DAT__I2C1_DAT             0x80000000
+                       >;
+               };
+
+               pinctrl_kpp: kppgrp {
+                       fsl,pins = <
+                               MX25_PAD_KPP_ROW0__KPP_ROW0     0x80000000
+                               MX25_PAD_KPP_ROW1__KPP_ROW1     0x80000000
+                               MX25_PAD_KPP_ROW2__KPP_ROW2     0x80000000
+                               MX25_PAD_KPP_ROW3__KPP_ROW3     0x80000000
+                               MX25_PAD_KPP_COL0__KPP_COL0     0x80000000
+                               MX25_PAD_KPP_COL1__KPP_COL1     0x80000000
+                               MX25_PAD_KPP_COL2__KPP_COL2     0x80000000
+                               MX25_PAD_KPP_COL3__KPP_COL3     0x80000000
+                       >;
+               };
+
+
+               pinctrl_uart1: uart1grp {
+                       fsl,pins = <
+                               MX25_PAD_UART1_RTS__UART1_RTS           0xe0
+                               MX25_PAD_UART1_CTS__UART1_CTS           0xe0
+                               MX25_PAD_UART1_TXD__UART1_TXD           0x80000000
+                               MX25_PAD_UART1_RXD__UART1_RXD           0xc0
+                       >;
+               };
+       };
+};
+
 &nfc {
        nand-on-flash-bbt;
        status = "okay";
 };
+
+&kpp {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_kpp>;
+       linux,keymap = <
+                       MATRIX_KEY(0x0, 0x0, KEY_UP)
+                       MATRIX_KEY(0x0, 0x1, KEY_DOWN)
+                       MATRIX_KEY(0x0, 0x2, KEY_VOLUMEDOWN)
+                       MATRIX_KEY(0x0, 0x3, KEY_HOME)
+                       MATRIX_KEY(0x1, 0x0, KEY_RIGHT)
+                       MATRIX_KEY(0x1, 0x1, KEY_LEFT)
+                       MATRIX_KEY(0x1, 0x2, KEY_ENTER)
+                       MATRIX_KEY(0x1, 0x3, KEY_VOLUMEUP)
+                       MATRIX_KEY(0x2, 0x0, KEY_F6)
+                       MATRIX_KEY(0x2, 0x1, KEY_F8)
+                       MATRIX_KEY(0x2, 0x2, KEY_F9)
+                       MATRIX_KEY(0x2, 0x3, KEY_F10)
+                       MATRIX_KEY(0x3, 0x0, KEY_F1)
+                       MATRIX_KEY(0x3, 0x1, KEY_F2)
+                       MATRIX_KEY(0x3, 0x2, KEY_F3)
+                       MATRIX_KEY(0x3, 0x2, KEY_POWER)
+       >;
+       status = "okay";
+};
+
+&ssi1 {
+       codec-handle = <&codec>;
+       fsl,mode = "i2s-slave";
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       fsl,uart-has-rtscts;
+       status = "okay";
+};
+
+&usbhost1 {
+       phy_type = "serial";
+       dr_mode = "host";
+       status = "okay";
+};
index ea323f09dc78f83ecbf934ff894ef25f79f4a99e..563e168c88a01a294f3f725d796fbe39f826db72 100644 (file)
@@ -14,6 +14,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                                status = "disabled";
                        };
 
-                       kpp@43fa8000 {
+                       kpp: kpp@43fa8000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
+                               compatible = "fsl,imx25-kpp", "fsl,imx21-kpp";
                                reg = <0x43fa8000 0x4000>;
                                clocks = <&clks 102>;
                                clock-names = "";
                                clocks = <&clks 99>;
                        };
 
-                       usbphy1: usbphy@1 {
-                               compatible = "nop-usbphy";
-                               status = "disabled";
-                       };
-
-                       usbphy2: usbphy@2 {
-                               compatible = "nop-usbphy";
-                               status = "disabled";
-                       };
-
                        usbotg: usb@53ff4000 {
                                compatible = "fsl,imx25-usb", "fsl,imx27-usb";
                                reg = <0x53ff4000 0x0200>;
                                interrupts = <37>;
-                               clocks = <&clks 9>, <&clks 70>, <&clks 8>;
-                               clock-names = "ipg", "ahb", "per";
+                               clocks = <&clks 70>;
                                fsl,usbmisc = <&usbmisc 0>;
+                               fsl,usbphy = <&usbphy0>;
                                status = "disabled";
                        };
 
                                compatible = "fsl,imx25-usb", "fsl,imx27-usb";
                                reg = <0x53ff4400 0x0200>;
                                interrupts = <35>;
-                               clocks = <&clks 9>, <&clks 70>, <&clks 8>;
-                               clock-names = "ipg", "ahb", "per";
+                               clocks = <&clks 70>;
                                fsl,usbmisc = <&usbmisc 1>;
+                               fsl,usbphy = <&usbphy1>;
                                status = "disabled";
                        };
 
                                clocks = <&clks 9>, <&clks 70>, <&clks 8>;
                                clock-names = "ipg", "ahb", "per";
                                reg = <0x53ff4600 0x00f>;
-                               status = "disabled";
                        };
 
                        dryice@53ffc000 {
                        };
                };
        };
+
+       usbphy {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               usbphy0: usb-phy@0 {
+                       reg = <0>;
+                       compatible = "usb-nop-xceiv";
+               };
+
+               usbphy1: usb-phy@1 {
+                       reg = <1>;
+                       compatible = "usb-nop-xceiv";
+               };
+       };
 };
index 5ce89aa275df179618cf3874f887a87bcaaca0fb..4c317716b510ab4db06a183bbf7567745be9d5c8 100644 (file)
        compatible = "fsl,imx27-pdk", "fsl,imx27";
 
        memory {
-               reg = <0x0 0x0>;
+               reg = <0xa0000000 0x08000000>;
        };
+
+       usbphy {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               usbphy0: usbphy@0 {
+                       compatible = "usb-nop-xceiv";
+                       reg = <0>;
+                       clocks = <&clks 0>;
+                       clock-names = "main_clk";
+               };
+       };
+};
+
+&cspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_cspi2>;
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       pmic: mc13783@0 {
+               compatible = "fsl,mc13783";
+               reg = <0>;
+               spi-cs-high;
+               spi-max-frequency = <1000000>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+
+               regulators {
+                       vgen_reg: vgen {
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       vmmc1_reg: vmmc1 {
+                               regulator-min-microvolt = <1600000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+
+                       gpo1_reg: gpo1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       gpo3_reg: gpo3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+               };
+       };
+};
+
+&fec {
+       phy-mode = "mii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       status = "okay";
+};
+
+&kpp {
+       linux,keymap = <
+               MATRIX_KEY(0, 0, KEY_UP)
+               MATRIX_KEY(0, 1, KEY_DOWN)
+               MATRIX_KEY(1, 0, KEY_RIGHT)
+               MATRIX_KEY(1, 1, KEY_LEFT)
+               MATRIX_KEY(1, 2, KEY_ENTER)
+               MATRIX_KEY(2, 0, KEY_F6)
+               MATRIX_KEY(2, 1, KEY_F8)
+               MATRIX_KEY(2, 2, KEY_F9)
+               MATRIX_KEY(2, 3, KEY_F10)
+       >;
+       status = "okay";
+};
+
+&nfc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_nand>;
+       nand-ecc-mode = "hw";
+       nand-on-flash-bbt;
+       status = "okay";
 };
 
 &uart1 {
        fsl,uart-has-rtscts;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
        status = "okay";
 };
 
-&fec {
+&usbotg {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       dr_mode = "otg";
+       fsl,usbphy = <&usbphy0>;
+       phy_type = "ulpi";
        status = "okay";
 };
+
+&iomuxc {
+       imx27-pdk {
+               pinctrl_cspi2: cspi2grp {
+                       fsl,pins = <
+                               MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x0
+                               MX27_PAD_CSPI2_MOSI__CSPI2_MOSI 0x0
+                               MX27_PAD_CSPI2_SCLK__CSPI2_SCLK 0x0
+                               MX27_PAD_CSPI2_SS0__GPIO4_21    0x0 /* SPI2 CS0 */
+                               MX27_PAD_TOUT__GPIO3_14         0x0 /* PMIC IRQ */
+                       >;
+               };
+
+               pinctrl_fec: fecgrp {
+                       fsl,pins = <
+                               MX27_PAD_SD3_CMD__FEC_TXD0 0x0
+                               MX27_PAD_SD3_CLK__FEC_TXD1 0x0
+                               MX27_PAD_ATA_DATA0__FEC_TXD2 0x0
+                               MX27_PAD_ATA_DATA1__FEC_TXD3 0x0
+                               MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0
+                               MX27_PAD_ATA_DATA3__FEC_RXD1 0x0
+                               MX27_PAD_ATA_DATA4__FEC_RXD2 0x0
+                               MX27_PAD_ATA_DATA5__FEC_RXD3 0x0
+                               MX27_PAD_ATA_DATA6__FEC_MDIO 0x0
+                               MX27_PAD_ATA_DATA7__FEC_MDC 0x0
+                               MX27_PAD_ATA_DATA8__FEC_CRS 0x0
+                               MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0
+                               MX27_PAD_ATA_DATA10__FEC_RXD0 0x0
+                               MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0
+                               MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0
+                               MX27_PAD_ATA_DATA13__FEC_COL 0x0
+                               MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0
+                               MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0
+                       >;
+               };
+
+               pinctrl_nand: nandgrp {
+                       fsl,pins = <
+                               MX27_PAD_NFRB__NFRB     0x0
+                               MX27_PAD_NFCLE__NFCLE   0x0
+                               MX27_PAD_NFWP_B__NFWP_B 0x0
+                               MX27_PAD_NFCE_B__NFCE_B 0x0
+                               MX27_PAD_NFALE__NFALE   0x0
+                               MX27_PAD_NFRE_B__NFRE_B 0x0
+                               MX27_PAD_NFWE_B__NFWE_B 0x0
+                       >;
+               };
+
+               pinctrl_uart1: uart1grp {
+                       fsl,pins = <
+                               MX27_PAD_UART1_TXD__UART1_TXD 0x0
+                               MX27_PAD_UART1_RXD__UART1_RXD 0x0
+                               MX27_PAD_UART1_CTS__UART1_CTS 0x0
+                               MX27_PAD_UART1_RTS__UART1_RTS 0x0
+                       >;
+               };
+
+               pinctrl_usbotg: usbotggrp {
+                       fsl,pins = <
+                               MX27_PAD_USBOTG_NXT__USBOTG_NXT 0x0
+                               MX27_PAD_USBOTG_STP__USBOTG_STP 0x0
+                               MX27_PAD_USBOTG_DIR__USBOTG_DIR 0x0
+                               MX27_PAD_USBOTG_CLK__USBOTG_CLK 0x0
+                               MX27_PAD_USBOTG_DATA0__USBOTG_DATA0 0x0
+                               MX27_PAD_USBOTG_DATA1__USBOTG_DATA1 0x0
+                               MX27_PAD_USBOTG_DATA2__USBOTG_DATA2 0x0
+                               MX27_PAD_USBOTG_DATA3__USBOTG_DATA3 0x0
+                               MX27_PAD_USBOTG_DATA4__USBOTG_DATA4 0x0
+                               MX27_PAD_USBOTG_DATA5__USBOTG_DATA5 0x0
+                               MX27_PAD_USBOTG_DATA6__USBOTG_DATA6 0x0
+                               MX27_PAD_USBOTG_DATA7__USBOTG_DATA7 0x0
+                       >;
+               };
+       };
+};
index df3b2e7318358e6dc65cdee4459f4714873bc301..d0b693f12cd2fa97e52f1ad51ae072a6275cbecb 100644 (file)
 / {
        model = "Phytec pcm970";
        compatible = "phytec,imx27-pcm970", "phytec,imx27-pcm038", "fsl,imx27";
+
+       display0: LQ035Q7 {
+               model = "Sharp-LQ035Q7";
+               native-mode = <&timing0>;
+               bits-per-pixel = <16>;
+               fsl,pcr = <0xf00080c0>;
+
+               display-timings {
+                       timing0: 240x320 {
+                               clock-frequency = <5500000>;
+                               hactive = <240>;
+                               vactive = <320>;
+                               hback-porch = <5>;
+                               hsync-len = <7>;
+                               hfront-porch = <16>;
+                               vback-porch = <7>;
+                               vsync-len = <1>;
+                               vfront-porch = <9>;
+                               pixelclk-active = <1>;
+                               hsync-active = <1>;
+                               vsync-active = <1>;
+                               de-active = <0>;
+                       };
+               };
+       };
+
+       regulators {
+               regulator@2 {
+                       compatible = "regulator-fixed";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_csien>;
+                       reg = <2>;
+                       regulator-name = "CSI_EN";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio2 24 GPIO_ACTIVE_LOW>;
+                       regulator-always-on;
+               };
+       };
+
+       usbphy {
+               usbphy2: usbphy@2 {
+                       compatible = "usb-nop-xceiv";
+                       reg = <2>;
+                       vcc-supply = <&reg_5v0>;
+                       clocks = <&clks 0>;
+                       clock-names = "main_clk";
+               };
+       };
 };
 
 &cspi1 {
+       pinctrl-0 = <&pinctrl_cspi1>, <&pinctrl_cspi1cs1>;
        fsl,spi-num-chipselects = <2>;
        cs-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>,
                   <&gpio4 27 GPIO_ACTIVE_LOW>;
 };
 
+&fb {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_imxfb1>;
+       display = <&display0>;
+       lcd-supply = <&reg_5v0>;
+       fsl,dmacr = <0x00020010>;
+       fsl,lscr1 = <0x00120300>;
+       fsl,lpccr = <0x00a903ff>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <400000>;
        pinctrl-names = "default";
 
 &iomuxc {
        imx27_phycore_rdk {
+               pinctrl_csien: csiengrp {
+                       fsl,pins = <
+                               MX27_PAD_USB_OC_B__GPIO2_24 0x0
+                       >;
+               };
+
+               pinctrl_cspi1cs1: cspi1cs1grp {
+                       fsl,pins = <
+                               MX27_PAD_CSPI1_SS1__GPIO4_27 0x0
+                       >;
+               };
+
+               pinctrl_imxfb1: imxfbgrp {
+                       fsl,pins = <
+                               MX27_PAD_LD0__LD0 0x0
+                               MX27_PAD_LD1__LD1 0x0
+                               MX27_PAD_LD2__LD2 0x0
+                               MX27_PAD_LD3__LD3 0x0
+                               MX27_PAD_LD4__LD4 0x0
+                               MX27_PAD_LD5__LD5 0x0
+                               MX27_PAD_LD6__LD6 0x0
+                               MX27_PAD_LD7__LD7 0x0
+                               MX27_PAD_LD8__LD8 0x0
+                               MX27_PAD_LD9__LD9 0x0
+                               MX27_PAD_LD10__LD10 0x0
+                               MX27_PAD_LD11__LD11 0x0
+                               MX27_PAD_LD12__LD12 0x0
+                               MX27_PAD_LD13__LD13 0x0
+                               MX27_PAD_LD14__LD14 0x0
+                               MX27_PAD_LD15__LD15 0x0
+                               MX27_PAD_LD16__LD16 0x0
+                               MX27_PAD_LD17__LD17 0x0
+                               MX27_PAD_CLS__CLS 0x0
+                               MX27_PAD_CONTRAST__CONTRAST 0x0
+                               MX27_PAD_LSCLK__LSCLK 0x0
+                               MX27_PAD_OE_ACD__OE_ACD 0x0
+                               MX27_PAD_PS__PS 0x0
+                               MX27_PAD_REV__REV 0x0
+                               MX27_PAD_SPL_SPR__SPL_SPR 0x0
+                               MX27_PAD_HSYNC__HSYNC 0x0
+                               MX27_PAD_VSYNC__VSYNC 0x0
+                       >;
+               };
+
                pinctrl_i2c1: i2c1grp {
                        /* Add pullup to DATA line */
                        fsl,pins = <
        dr_mode = "host";
        phy_type = "ulpi";
        vbus-supply = <&reg_5v0>;
+       fsl,usbphy = <&usbphy2>;
        disable-over-current;
        status = "okay";
 };
 
-&usbphy2 {
-       vcc-supply = <&reg_5v0>;
-};
-
 &weim {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_weim>;
 
-       can@d4000000 {
+       can@4,0 {
                compatible = "nxp,sja1000";
                reg = <4 0x00000000 0x00000100>;
                interrupt-parent = <&gpio5>;
index cefaa6994623f2a135aa7c74b65680a8a11b27dd..31e9f7049f73351f325c3e58b1fb6e4e116763df 100644 (file)
                        regulator-max-microvolt = <5000000>;
                };
        };
+
+       usbphy {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               usbphy0: usbphy@0 {
+                       compatible = "usb-nop-xceiv";
+                       reg = <0>;
+                       vcc-supply = <&sw3_reg>;
+                       clocks = <&clks 0>;
+                       clock-names = "main_clk";
+               };
+       };
 };
 
 &audmux {
@@ -66,9 +80,9 @@
        status = "okay";
 
        pmic: mc13783@0 {
-               #address-cells = <1>;
-               #size-cells = <0>;
                compatible = "fsl,mc13783";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic>;
                reg = <0>;
                spi-cs-high;
                spi-max-frequency = <20000000>;
 
 &fec {
        phy-mode = "mii";
-       phy-reset-gpios = <&gpio3 30 GPIO_ACTIVE_HIGH>;
+       phy-reset-gpios = <&gpio3 30 GPIO_ACTIVE_LOW>;
        phy-supply = <&reg_3v3>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec1>;
                                MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x0
                                MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x0
                                MX27_PAD_CSPI1_SS0__GPIO4_28    0x0 /* SPI1 CS0 */
-                               MX27_PAD_USB_PWR__GPIO2_23      0x0 /* PMIC IRQ */
                        >;
                };
 
                        >;
                };
 
+               pinctrl_pmic: pmicgrp {
+                       fsl,pins = <
+                               MX27_PAD_USB_PWR__GPIO2_23      0x0 /* PMIC IRQ */
+                       >;
+               };
+
+               pinctrl_ssi1: ssi1grp {
+                       fsl,pins = <
+                               MX27_PAD_SSI1_FS__SSI1_FS 0x0
+                               MX27_PAD_SSI1_RXDAT__SSI1_RXDAT 0x0
+                               MX27_PAD_SSI1_TXDAT__SSI1_TXDAT 0x0
+                               MX27_PAD_SSI1_CLK__SSI1_CLK 0x0
+                       >;
+               };
+
                pinctrl_usbotg: usbotggrp {
                        fsl,pins = <
                                MX27_PAD_USBOTG_CLK__USBOTG_CLK 0x0
        status = "okay";
 };
 
+&ssi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ssi1>;
+       fsl,mode = "i2s-slave";
+       status = "okay";
+};
+
 &usbotg {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usbotg>;
        dr_mode = "otg";
        phy_type = "ulpi";
+       fsl,usbphy = <&usbphy0>;
        vbus-supply = <&sw3_reg>;
+       disable-over-current;
        status = "okay";
 };
 
-&usbphy0 {
-       vcc-supply = <&sw3_reg>;
-};
-
 &weim {
        status = "okay";
 
-       nor: nor@c0000000 {
+       nor: nor@0,0 {
                compatible = "cfi-flash";
                reg = <0 0x00000000 0x02000000>;
                bank-width = <2>;
                #size-cells = <1>;
        };
 
-       sram: sram@c8000000 {
+       sram: sram@1,0 {
                compatible = "mtd-ram";
                reg = <1 0x00000000 0x00800000>;
                bank-width = <2>;
index 137e010eab35bebd9cad861574713ce9288adc68..a75555c39533d71edd6828dd475ae8d73df81511 100644 (file)
 
 #include "skeleton.dtsi"
 #include "imx27-pinfunc.h"
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/gpio/gpio.h>
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                };
        };
 
-       usbphy {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               usbphy0: usbphy@0 {
-                       compatible = "usb-nop-xceiv";
-                       reg = <0>;
-                       clocks = <&clks 75>;
-                       clock-names = "main_clk";
-               };
-
-               usbphy2: usbphy@2 {
-                       compatible = "usb-nop-xceiv";
-                       reg = <2>;
-                       clocks = <&clks 75>;
-                       clock-names = "main_clk";
-               };
-       };
-
        soc {
                #address-cells = <1>;
                #size-cells = <1>;
                                compatible = "fsl,imx27-usb";
                                reg = <0x10024000 0x200>;
                                interrupts = <56>;
-                               clocks = <&clks 15>;
+                               clocks = <&clks 75>;
                                fsl,usbmisc = <&usbmisc 0>;
-                               fsl,usbphy = <&usbphy0>;
                                status = "disabled";
                        };
 
                                compatible = "fsl,imx27-usb";
                                reg = <0x10024200 0x200>;
                                interrupts = <54>;
-                               clocks = <&clks 15>;
+                               clocks = <&clks 75>;
                                fsl,usbmisc = <&usbmisc 1>;
                                status = "disabled";
                        };
                                compatible = "fsl,imx27-usb";
                                reg = <0x10024400 0x200>;
                                interrupts = <55>;
-                               clocks = <&clks 15>;
+                               clocks = <&clks 75>;
                                fsl,usbmisc = <&usbmisc 2>;
-                               fsl,usbphy = <&usbphy2>;
                                status = "disabled";
                        };
 
index 5f326c1c1850b349eeb6877e11a8e1cf491d19fb..ce1a7effba3770ce8708cfb44ecae6e781d6a79f 100644 (file)
@@ -25,9 +25,9 @@
                        ssp0: ssp@80010000 {
                                compatible = "fsl,imx28-mmc";
                                pinctrl-names = "default";
-                               pinctrl-0 = <&mmc0_8bit_pins_a
+                               pinctrl-0 = <&mmc0_4bit_pins_a
                                        &mmc0_cd_cfg &mmc0_sck_cfg>;
-                               bus-width = <8>;
+                               bus-width = <4>;
                                vmmc-supply = <&reg_3p3v>;
                                status = "okay";
                        };
@@ -39,7 +39,7 @@
                                hog_pins_a: hog@0 {
                                        reg = <0>;
                                        fsl,pinmux-ids = <
-                                               MX28_PAD_ENET0_RX_CLK__GPIO_4_13 /* PHY Reset */
+                                               MX28_PAD_SSP0_DATA7__GPIO_2_7 /* PHY Reset */
                                        >;
                                        fsl,drive-strength = <MXS_DRIVE_4mA>;
                                        fsl,voltage = <MXS_VOLTAGE_HIGH>;
@@ -82,7 +82,7 @@
                        pinctrl-names = "default";
                        pinctrl-0 = <&mac0_pins_a>;
                        phy-supply = <&reg_3p3v>;
-                       phy-reset-gpios = <&gpio4 13 0>;
+                       phy-reset-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
                        phy-reset-duration = <100>;
                        status = "okay";
                };
 
                status {
                        label = "duckbill:green:status";
-                       gpios = <&gpio3 5 0>;
+                       gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>;
                };
 
                failure {
                        label = "duckbill:red:status";
-                       gpios = <&gpio3 4 0>;
+                       gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
                };
        };
 };
index 90a579532b8b7619c334b77ef740ec3b0f6b233e..a95cc5358ff460cc688d97535bccc8722c9f0358 100644 (file)
@@ -9,6 +9,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <dt-bindings/gpio/gpio.h>
 #include "skeleton.dtsi"
 #include "imx28-pinfunc.h"
 
index 906ae937b01366e2b8f3060920bf70086104600e..9c2b715ab8bfd9463dbc0768f6e5284302385c8a 100644 (file)
                compatible = "nxp,pcf8563";
                reg = <0x51>;
        };
+
+       tsc2007: tsc2007@48 {
+               compatible = "ti,tsc2007";
+               gpios = <&gpio3 2 0>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <0x2 0x8>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tsc2007_1>;
+               reg = <0x48>;
+               ti,x-plate-ohms = <180>;
+       };
 };
 
 &iomuxc {
                                MX35_PAD_I2C1_DAT__I2C1_SDA             0x80000000
                        >;
                };
+
+               pinctrl_tsc2007_1: tsc2007grp-1 {
+                       fsl,pins = <MX35_PAD_ATA_DA2__GPIO3_2 0x80000000>;
+               };
        };
 };
 
index 1bdec21f45332565ee25ea615ff07898ab3c490f..f04ae91eea8908b541ae170998982ec6c24bc570 100644 (file)
                        linux,default-trigger = "heartbeat";
                };
        };
+
+       sound {
+               compatible = "eukrea,asoc-tlv320";
+               eukrea,model = "imx35-eukrea-tlv320aic23";
+               ssi-controller = <&ssi1>;
+               fsl,mux-int-port = <1>;
+               fsl,mux-ext-port = <4>;
+       };
 };
 
 &audmux {
 };
 
 &ssi1 {
+       codec-handle = <&tlv320aic23>;
        fsl,mode = "i2s-slave";
        status = "okay";
 };
        fsl,uart-has-rtscts;
        status = "okay";
 };
+
+&usbhost1 {
+       phy_type = "serial";
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usbotg {
+       phy_type = "utmi";
+       dr_mode = "otg";
+       external-vbus-divider;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx35-pdk.dts b/arch/arm/boot/dts/imx35-pdk.dts
new file mode 100644 (file)
index 0000000..db69ff0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013 Eukréa Electromatique <denis@eukrea.com>
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * 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 "imx35.dtsi"
+
+/ {
+       model = "Freescale i.MX35 Product Development Kit";
+       compatible = "fsl,imx35-pdk", "fsl,imx35";
+
+       memory {
+               reg = <0x80000000 0x8000000>;
+       };
+};
+
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       status = "okay";
+};
+
+&iomuxc {
+       imx35-pdk {
+               pinctrl_esdhc1: esdhc1grp {
+                       fsl,pins = <
+                               MX35_PAD_SD1_CMD__ESDHC1_CMD            0x80000000
+                               MX35_PAD_SD1_CLK__ESDHC1_CLK            0x80000000
+                               MX35_PAD_SD1_DATA0__ESDHC1_DAT0         0x80000000
+                               MX35_PAD_SD1_DATA1__ESDHC1_DAT1         0x80000000
+                               MX35_PAD_SD1_DATA2__ESDHC1_DAT2         0x80000000
+                               MX35_PAD_SD1_DATA3__ESDHC1_DAT3         0x80000000
+                       >;
+               };
+
+               pinctrl_uart1: uart1grp {
+                       fsl,pins = <
+                               MX35_PAD_TXD1__UART1_TXD_MUX            0x1c5
+                               MX35_PAD_RXD1__UART1_RXD_MUX            0x1c5
+                               MX35_PAD_CTS1__UART1_CTS                0x1c5
+                               MX35_PAD_RTS1__UART1_RTS                0x1c5
+                       >;
+               };
+       };
+};
+
+&nfc {
+       nand-bus-width = <16>;
+       nand-ecc-mode = "hw";
+       nand-on-flash-bbt;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       fsl,uart-has-rtscts;
+       status = "okay";
+};
index 88b218f8f81049aa8f787fa511639cea250ea461..4759abb4943615d393c3b7404731141ac19392f0 100644 (file)
@@ -13,6 +13,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                                compatible = "fsl,imx35-usb", "fsl,imx27-usb";
                                reg = <0x53ff4000 0x0200>;
                                interrupts = <37>;
-                               clocks = <&clks 9>, <&clks 73>, <&clks 28>;
-                               clock-names = "ipg", "ahb", "per";
+                               clocks = <&clks 73>;
                                fsl,usbmisc = <&usbmisc 0>;
+                               fsl,usbphy = <&usbphy0>;
                                status = "disabled";
                        };
 
                                compatible = "fsl,imx35-usb", "fsl,imx27-usb";
                                reg = <0x53ff4400 0x0200>;
                                interrupts = <35>;
-                               clocks = <&clks 9>, <&clks 73>, <&clks 28>;
-                               clock-names = "ipg", "ahb", "per";
+                               clocks = <&clks 73>;
                                fsl,usbmisc = <&usbmisc 1>;
+                               fsl,usbphy = <&usbphy1>;
                                status = "disabled";
                        };
 
                        };
                };
        };
+
+       usbphy {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               usbphy0: usb-phy@0 {
+                       reg = <0>;
+                       compatible = "usb-nop-xceiv";
+               };
+
+               usbphy1: usb-phy@1 {
+                       reg = <1>;
+                       compatible = "usb-nop-xceiv";
+               };
+       };
 };
index 9c89d1ca97c2ce771a587c3066f968be22b52005..6a201cf54366345b3f966d91f251dda73016e50d 100644 (file)
@@ -17,6 +17,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
index 9e9deb244b76ff1dfb5b4952b1d16294f1ed652f..89470bfca16075fcede6562b1e291ebbd4ecf6dc 100644 (file)
                reg = <0x90000000 0x20000000>;
        };
 
+       clocks {
+               ckih1 {
+                       clock-frequency = <22579200>;
+               };
+
+               clk_26M: codec_clock {
+                       compatible = "fixed-clock";
+                       reg=<0>;
+                       #clock-cells = <0>;
+                       clock-frequency = <26000000>;
+                       gpios = <&gpio4 26 GPIO_ACTIVE_LOW>;
+               };
+       };
+
        display0: display@di0 {
                compatible = "fsl,imx-parallel-display";
                interface-pix-fmt = "rgb24";
 
        gpio-keys {
                compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_keys>;
 
                power {
                        label = "Power Button";
                        gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
-                       linux,code = <116>; /* KEY_POWER */
+                       linux,code = <KEY_POWER>;
                        gpio-key,wakeup;
                };
        };
                };
        };
 
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               reg_usbh1_vbus: regulator@0 {
+                       compatible = "regulator-fixed";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usbh1reg>;
+                       reg = <0>;
+                       regulator-name = "usbh1_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio2 5 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+               };
+
+               reg_usbotg_vbus: regulator@1 {
+                       compatible = "regulator-fixed";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usbotgreg>;
+                       reg = <1>;
+                       regulator-name = "usbotg_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+               };
+       };
+
        sound {
                compatible = "fsl,imx51-babbage-sgtl5000",
                             "fsl,imx-audio-sgtl5000";
                mux-ext-port = <3>;
        };
 
-       clocks {
-               ckih1 {
-                       clock-frequency = <22579200>;
-               };
+       usbphy {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "simple-bus";
 
-               clk_26M: codec_clock {
-                       compatible = "fixed-clock";
-                       reg=<0>;
-                       #clock-cells = <0>;
-                       clock-frequency = <26000000>;
-                       gpios = <&gpio4 26 GPIO_ACTIVE_LOW>;
+               usbh1phy: usbh1phy@0 {
+                       compatible = "usb-nop-xceiv";
+                       reg = <0>;
+                       clocks = <&clks IMX5_CLK_DUMMY>;
+                       clock-names = "main_clk";
                };
        };
 };
 
-&esdhc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_esdhc1>;
-       fsl,cd-controller;
-       fsl,wp-controller;
-       status = "okay";
-};
-
-&esdhc2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_esdhc2>;
-       cd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
-       wp-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
-       status = "okay";
-};
-
-&uart3 {
+&audmux {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart3>;
-       fsl,uart-has-rtscts;
+       pinctrl-0 = <&pinctrl_audmux>;
        status = "okay";
 };
 
        status = "okay";
 
        pmic: mc13892@0 {
-               #address-cells = <1>;
-               #size-cells = <0>;
                compatible = "fsl,mc13892";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic>;
                spi-max-frequency = <6000000>;
                spi-cs-high;
                reg = <0>;
        };
 };
 
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       fsl,cd-controller;
+       fsl,wp-controller;
+       status = "okay";
+};
+
+&esdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc2>;
+       cd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+       wp-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-mode = "mii";
+       phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
+       phy-reset-duration = <1>;
+       status = "okay";
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+
+       sgtl5000: codec@0a {
+               compatible = "fsl,sgtl5000";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_clkcodec>;
+               reg = <0x0a>;
+               clocks = <&clk_26M>;
+               VDDA-supply = <&vdig_reg>;
+               VDDIO-supply = <&vvideo_reg>;
+       };
+};
+
 &ipu_di0_disp0 {
        remote-endpoint = <&display0_in>;
 };
        remote-endpoint = <&display1_in>;
 };
 
+&kpp {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_kpp>;
+       linux,keymap = <
+               MATRIX_KEY(0, 0, KEY_UP)
+               MATRIX_KEY(0, 1, KEY_DOWN)
+               MATRIX_KEY(0, 2, KEY_VOLUMEDOWN)
+               MATRIX_KEY(0, 3, KEY_HOME)
+               MATRIX_KEY(1, 0, KEY_RIGHT)
+               MATRIX_KEY(1, 1, KEY_LEFT)
+               MATRIX_KEY(1, 2, KEY_ENTER)
+               MATRIX_KEY(1, 3, KEY_VOLUMEUP)
+               MATRIX_KEY(2, 0, KEY_F6)
+               MATRIX_KEY(2, 1, KEY_F8)
+               MATRIX_KEY(2, 2, KEY_F9)
+               MATRIX_KEY(2, 3, KEY_F10)
+               MATRIX_KEY(3, 0, KEY_F1)
+               MATRIX_KEY(3, 1, KEY_F2)
+               MATRIX_KEY(3, 2, KEY_F3)
+               MATRIX_KEY(3, 3, KEY_POWER)
+       >;
+       status = "okay";
+};
+
 &ssi2 {
        fsl,mode = "i2s-slave";
        status = "okay";
 };
 
-&iomuxc {
+&uart1 {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_hog>;
+       pinctrl-0 = <&pinctrl_uart1>;
+       fsl,uart-has-rtscts;
+       status = "okay";
+};
 
-       imx51-babbage {
-               pinctrl_hog: hoggrp {
-                       fsl,pins = <
-                               MX51_PAD_GPIO1_0__SD1_CD     0x20d5
-                               MX51_PAD_GPIO1_1__SD1_WP     0x20d5
-                               MX51_PAD_GPIO1_5__GPIO1_5    0x100
-                               MX51_PAD_GPIO1_6__GPIO1_6    0x100
-                               MX51_PAD_EIM_A27__GPIO2_21   0x5
-                               MX51_PAD_CSPI1_SS0__GPIO4_24 0x85
-                               MX51_PAD_CSPI1_SS1__GPIO4_25 0x85
-                               MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000
-                       >;
-               };
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
 
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       fsl,uart-has-rtscts;
+       status = "okay";
+};
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       vbus-supply = <&reg_usbh1_vbus>;
+       fsl,usbphy = <&usbh1phy>;
+       phy_type = "ulpi";
+       status = "okay";
+};
+
+&usbotg {
+       dr_mode = "otg";
+       disable-over-current;
+       phy_type = "utmi_wide";
+       vbus-supply = <&reg_usbotg_vbus>;
+       status = "okay";
+};
+
+&iomuxc {
+       imx51-babbage {
                pinctrl_audmux: audmuxgrp {
                        fsl,pins = <
                                MX51_PAD_AUD3_BB_TXD__AUD3_TXD          0x80000000
                        >;
                };
 
+               pinctrl_clkcodec: clkcodecgrp {
+                       fsl,pins = <
+                               MX51_PAD_CSPI1_RDY__GPIO4_26            0x80000000
+                       >;
+               };
+
                pinctrl_ecspi1: ecspi1grp {
                        fsl,pins = <
                                MX51_PAD_CSPI1_MISO__ECSPI1_MISO        0x185
                                MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI        0x185
                                MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK        0x185
+                               MX51_PAD_CSPI1_SS0__GPIO4_24            0x85 /* CS0 */
+                               MX51_PAD_CSPI1_SS1__GPIO4_25            0x85 /* CS1 */
                        >;
                };
 
                                MX51_PAD_SD1_DATA1__SD1_DATA1           0x20d5
                                MX51_PAD_SD1_DATA2__SD1_DATA2           0x20d5
                                MX51_PAD_SD1_DATA3__SD1_DATA3           0x20d5
+                               MX51_PAD_GPIO1_0__SD1_CD                0x20d5
+                               MX51_PAD_GPIO1_1__SD1_WP                0x20d5
                        >;
                };
 
                                MX51_PAD_SD2_DATA1__SD2_DATA1           0x20d5
                                MX51_PAD_SD2_DATA2__SD2_DATA2           0x20d5
                                MX51_PAD_SD2_DATA3__SD2_DATA3           0x20d5
+                               MX51_PAD_GPIO1_5__GPIO1_5               0x100 /* WP */
+                               MX51_PAD_GPIO1_6__GPIO1_6               0x100 /* CD */
                        >;
                };
 
                                MX51_PAD_NANDF_CS6__FEC_TDATA3          0x80000000
                                MX51_PAD_NANDF_CS7__FEC_TX_EN           0x80000000
                                MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK      0x80000000
-                               MX51_PAD_EIM_A20__GPIO2_14 0x85 /* Reset */
+                               MX51_PAD_EIM_A20__GPIO2_14              0x85 /* Reset */
+                       >;
+               };
+
+               pinctrl_gpio_keys: gpiokeysgrp {
+                       fsl,pins = <
+                               MX51_PAD_EIM_A27__GPIO2_21              0x5
                        >;
                };
 
                        >;
                };
 
+               pinctrl_i2c1: i2c1grp {
+                       fsl,pins = <
+                               MX51_PAD_EIM_D19__I2C1_SCL              0x400001ed
+                               MX51_PAD_EIM_D16__I2C1_SDA              0x400001ed
+                       >;
+               };
+
                pinctrl_i2c2: i2c2grp {
                        fsl,pins = <
                                MX51_PAD_KEY_COL4__I2C2_SCL             0x400001ed
                        >;
                };
 
+               pinctrl_pmic: pmicgrp {
+                       fsl,pins = <
+                               MX51_PAD_GPIO1_8__GPIO1_8               0xe5 /* IRQ */
+                       >;
+               };
+
                pinctrl_uart1: uart1grp {
                        fsl,pins = <
                                MX51_PAD_UART1_RXD__UART1_RXD           0x1c5
                                MX51_PAD_EIM_D24__UART3_CTS             0x1c5
                        >;
                };
-       };
-};
 
-&uart1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart1>;
-       fsl,uart-has-rtscts;
-       status = "okay";
-};
-
-&uart2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart2>;
-       status = "okay";
-};
+               pinctrl_usbh1: usbh1grp {
+                       fsl,pins = <
+                               MX51_PAD_USBH1_CLK__USBH1_CLK           0x80000000
+                               MX51_PAD_USBH1_DIR__USBH1_DIR           0x80000000
+                               MX51_PAD_USBH1_NXT__USBH1_NXT           0x80000000
+                               MX51_PAD_USBH1_DATA0__USBH1_DATA0       0x80000000
+                               MX51_PAD_USBH1_DATA1__USBH1_DATA1       0x80000000
+                               MX51_PAD_USBH1_DATA2__USBH1_DATA2       0x80000000
+                               MX51_PAD_USBH1_DATA3__USBH1_DATA3       0x80000000
+                               MX51_PAD_USBH1_DATA4__USBH1_DATA4       0x80000000
+                               MX51_PAD_USBH1_DATA5__USBH1_DATA5       0x80000000
+                               MX51_PAD_USBH1_DATA6__USBH1_DATA6       0x80000000
+                               MX51_PAD_USBH1_DATA7__USBH1_DATA7       0x80000000
+                       >;
+               };
 
-&i2c2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c2>;
-       status = "okay";
+               pinctrl_usbh1reg: usbh1reggrp {
+                       fsl,pins = <
+                               MX51_PAD_EIM_D21__GPIO2_5               0x85
+                       >;
+               };
 
-       sgtl5000: codec@0a {
-               compatible = "fsl,sgtl5000";
-               reg = <0x0a>;
-               clocks = <&clk_26M>;
-               VDDA-supply = <&vdig_reg>;
-               VDDIO-supply = <&vvideo_reg>;
+               pinctrl_usbotgreg: usbotgreggrp {
+                       fsl,pins = <
+                               MX51_PAD_GPIO1_7__GPIO1_7               0x85
+                       >;
+               };
        };
 };
-
-&audmux {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_audmux>;
-       status = "okay";
-};
-
-&fec {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_fec>;
-       phy-mode = "mii";
-       phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
-       phy-reset-duration = <1>;
-       status = "okay";
-};
-
-&kpp {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_kpp>;
-       linux,keymap = <
-               MATRIX_KEY(0, 0, KEY_UP)
-               MATRIX_KEY(0, 1, KEY_DOWN)
-               MATRIX_KEY(0, 2, KEY_VOLUMEDOWN)
-               MATRIX_KEY(0, 3, KEY_HOME)
-               MATRIX_KEY(1, 0, KEY_RIGHT)
-               MATRIX_KEY(1, 1, KEY_LEFT)
-               MATRIX_KEY(1, 2, KEY_ENTER)
-               MATRIX_KEY(1, 3, KEY_VOLUMEUP)
-               MATRIX_KEY(2, 0, KEY_F6)
-               MATRIX_KEY(2, 1, KEY_F8)
-               MATRIX_KEY(2, 2, KEY_F9)
-               MATRIX_KEY(2, 3, KEY_F10)
-               MATRIX_KEY(3, 0, KEY_F1)
-               MATRIX_KEY(3, 1, KEY_F2)
-               MATRIX_KEY(3, 2, KEY_F3)
-               MATRIX_KEY(3, 3, KEY_POWER)
-               >;
-       status = "okay";
-};
diff --git a/arch/arm/boot/dts/imx51-digi-connectcore-jsk.dts b/arch/arm/boot/dts/imx51-digi-connectcore-jsk.dts
new file mode 100644 (file)
index 0000000..1db517d
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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
+ */
+
+#include "imx51-digi-connectcore-som.dtsi"
+
+/ {
+       model = "Digi ConnectCore CC(W)-MX51 JSK";
+       compatible = "digi,connectcore-ccxmx51-jsk",
+                    "digi,connectcore-ccxmx51-som", "fsl,imx51";
+
+       chosen {
+               linux,stdout-path = &uart1;
+       };
+};
+
+&owire {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_owire>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       status = "okay";
+};
+
+&usbotg {
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       dr_mode = "host";
+       phy_type = "ulpi";
+       disable-over-current;
+       status = "okay";
+};
+
+&iomuxc {
+       imx51-digi-connectcore-jsk {
+               pinctrl_owire: owiregrp {
+                       fsl,pins = <
+                               MX51_PAD_OWIRE_LINE__OWIRE_LINE         0x40000000
+                       >;
+               };
+
+               pinctrl_uart1: uart1grp {
+                       fsl,pins = <
+                               MX51_PAD_UART1_RXD__UART1_RXD           0x1c5
+                               MX51_PAD_UART1_TXD__UART1_TXD           0x1c5
+                       >;
+               };
+
+               pinctrl_uart2: uart2grp {
+                       fsl,pins = <
+                               MX51_PAD_UART2_RXD__UART2_RXD           0x1c5
+                               MX51_PAD_UART2_TXD__UART2_TXD           0x1c5
+                       >;
+               };
+
+               pinctrl_uart3: uart3grp {
+                       fsl,pins = <
+                               MX51_PAD_UART3_RXD__UART3_RXD           0x1c5
+                               MX51_PAD_UART3_TXD__UART3_TXD           0x1c5
+                       >;
+               };
+
+               pinctrl_usbh1: usbh1grp {
+                       fsl,pins = <
+                               MX51_PAD_USBH1_DATA0__USBH1_DATA0       0x1e5
+                               MX51_PAD_USBH1_DATA1__USBH1_DATA1       0x1e5
+                               MX51_PAD_USBH1_DATA2__USBH1_DATA2       0x1e5
+                               MX51_PAD_USBH1_DATA3__USBH1_DATA3       0x1e5
+                               MX51_PAD_USBH1_DATA4__USBH1_DATA4       0x1e5
+                               MX51_PAD_USBH1_DATA5__USBH1_DATA5       0x1e5
+                               MX51_PAD_USBH1_DATA6__USBH1_DATA6       0x1e5
+                               MX51_PAD_USBH1_DATA7__USBH1_DATA7       0x1e5
+                               MX51_PAD_USBH1_CLK__USBH1_CLK           0x1e5
+                               MX51_PAD_USBH1_DIR__USBH1_DIR           0x1e5
+                               MX51_PAD_USBH1_NXT__USBH1_NXT           0x1e5
+                               MX51_PAD_USBH1_STP__USBH1_STP           0x1e5
+                       >;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi
new file mode 100644 (file)
index 0000000..321662f
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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 "imx51.dtsi"
+
+/ {
+       model = "Digi ConnectCore CC(W)-MX51";
+       compatible = "digi,connectcore-ccxmx51-som", "fsl,imx51";
+
+       memory {
+               reg = <0x90000000 0x08000000>;
+       };
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       pmic: mc13892@0 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_mc13892>;
+               compatible = "fsl,mc13892";
+               spi-max-frequency = <16000000>;
+               spi-cs-high;
+               reg = <0>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+               fsl,mc13xxx-uses-rtc;
+
+               regulators {
+                       sw1_reg: sw1 {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <1225000>;
+                               regulator-max-microvolt = <1225000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3_reg: sw3 {
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst { };
+
+                       viohi_reg: viohi {
+                               regulator-always-on;
+                       };
+
+                       vpll_reg: vpll {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                       };
+
+                       vdig_reg: vdig {
+                               regulator-min-microvolt = <1250000>;
+                               regulator-max-microvolt = <1250000>;
+                               regulator-always-on;
+                       };
+
+                       vsd_reg: vsd {
+                               regulator-min-microvolt = <3150000>;
+                               regulator-max-microvolt = <3150000>;
+                               regulator-always-on;
+                       };
+
+                       vusb2_reg: vusb2 {
+                               regulator-min-microvolt = <2600000>;
+                               regulator-max-microvolt = <2600000>;
+                               regulator-always-on;
+                       };
+
+                       vvideo_reg: vvideo {
+                               regulator-min-microvolt = <2775000>;
+                               regulator-max-microvolt = <2775000>;
+                               regulator-always-on;
+                       };
+
+                       vaudio_reg: vaudio {
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                       };
+
+                       vcam_reg: vcam {
+                               regulator-min-microvolt = <2750000>;
+                               regulator-max-microvolt = <2750000>;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vgen1 {
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-always-on;
+                       };
+
+                       vgen2_reg: vgen2 {
+                               regulator-min-microvolt = <3150000>;
+                               regulator-max-microvolt = <3150000>;
+                               regulator-always-on;
+                       };
+
+                       vgen3_reg: vgen3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                       };
+
+                       vusb_reg: vusb {
+                               regulator-always-on;
+                       };
+
+                       gpo1_reg: gpo1 { };
+
+                       gpo2_reg: gpo2 { };
+
+                       gpo3_reg: gpo3 { };
+
+                       gpo4_reg: gpo4 { };
+
+                       pwgt2spi_reg: pwgt2spi {
+                               regulator-always-on;
+                       };
+
+                       vcoincell_reg: vcoincell {
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                       };
+               };
+       };
+};
+
+&esdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc2>;
+       cap-sdio-irq;
+       enable-sdio-wakeup;
+       keep-power-in-suspend;
+       max-frequency = <50000000>;
+       no-1-8-v;
+       non-removable;
+       vmmc-supply = <&gpo4_reg>;
+       status = "okay";
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-mode = "mii";
+       phy-supply = <&gpo3_reg>;
+       /* Pins shared with LCD2, keep status disabled */
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       clock-frequency = <400000>;
+       status = "okay";
+
+       mma7455l@1d {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_mma7455l>;
+               compatible = "fsl,mma7455l";
+               reg = <0x1d>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <7 IRQ_TYPE_LEVEL_HIGH>, <6 IRQ_TYPE_LEVEL_HIGH>;
+       };
+};
+
+&nfc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_nfc>;
+       nand-bus-width = <8>;
+       nand-ecc-mode = "hw";
+       nand-on-flash-bbt;
+       status = "okay";
+};
+
+&usbotg {
+       phy_type = "utmi_wide";
+       disable-over-current;
+       /* Device role is not known, keep status disabled */
+};
+
+&weim {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_weim>;
+       status = "okay";
+
+       lan9221: lan9221@5,0 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_lan9221>;
+               compatible = "smsc,lan9221", "smsc,lan9115";
+               reg = <5 0x00000000 0x1000>;
+               fsl,weim-cs-timing = <
+                       0x00420081 0x00000000
+                       0x32260000 0x00000000
+                       0x72080f00 0x00000000
+               >;
+               clocks = <&clks IMX5_CLK_DUMMY>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+               phy-mode = "mii";
+               reg-io-width = <2>;
+               smsc,irq-push-pull;
+               vdd33a-supply = <&gpo2_reg>;
+               vddvario-supply = <&gpo2_reg>;
+       };
+};
+
+&iomuxc {
+       imx51-digi-connectcore-som {
+               pinctrl_ecspi1: ecspi1grp {
+                       fsl,pins = <
+                               MX51_PAD_CSPI1_MISO__ECSPI1_MISO        0x185
+                               MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI        0x185
+                               MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK        0x185
+                               MX51_PAD_CSPI1_SS0__GPIO4_24            0x85 /* CS0 */
+                       >;
+               };
+
+               pinctrl_esdhc2: esdhc2grp {
+                       fsl,pins = <
+                               MX51_PAD_SD2_CMD__SD2_CMD               0x400020d5
+                               MX51_PAD_SD2_CLK__SD2_CLK               0x20d5
+                               MX51_PAD_SD2_DATA0__SD2_DATA0           0x20d5
+                               MX51_PAD_SD2_DATA1__SD2_DATA1           0x20d5
+                               MX51_PAD_SD2_DATA2__SD2_DATA2           0x20d5
+                               MX51_PAD_SD2_DATA3__SD2_DATA3           0x20d5
+                       >;
+               };
+
+               pinctrl_fec: fecgrp {
+                       fsl,pins = <
+                               MX51_PAD_DI_GP3__FEC_TX_ER              0x80000000
+                               MX51_PAD_DI2_PIN4__FEC_CRS              0x80000000
+                               MX51_PAD_DI2_PIN2__FEC_MDC              0x80000000
+                               MX51_PAD_DI2_PIN3__FEC_MDIO             0x80000000
+                               MX51_PAD_DI2_DISP_CLK__FEC_RDATA1       0x80000000
+                               MX51_PAD_DI_GP4__FEC_RDATA2             0x80000000
+                               MX51_PAD_DISP2_DAT0__FEC_RDATA3         0x80000000
+                               MX51_PAD_DISP2_DAT1__FEC_RX_ER          0x80000000
+                               MX51_PAD_DISP2_DAT6__FEC_TDATA1         0x80000000
+                               MX51_PAD_DISP2_DAT7__FEC_TDATA2         0x80000000
+                               MX51_PAD_DISP2_DAT8__FEC_TDATA3         0x80000000
+                               MX51_PAD_DISP2_DAT9__FEC_TX_EN          0x80000000
+                               MX51_PAD_DISP2_DAT10__FEC_COL           0x80000000
+                               MX51_PAD_DISP2_DAT11__FEC_RX_CLK        0x80000000
+                               MX51_PAD_DISP2_DAT12__FEC_RX_DV         0x80000000
+                               MX51_PAD_DISP2_DAT13__FEC_TX_CLK        0x80000000
+                               MX51_PAD_DISP2_DAT14__FEC_RDATA0        0x80000000
+                               MX51_PAD_DISP2_DAT15__FEC_TDATA0        0x80000000
+                       >;
+               };
+
+               pinctrl_i2c2: i2c2grp {
+                       fsl,pins = <
+                               MX51_PAD_GPIO1_2__I2C2_SCL              0x400001ed
+                               MX51_PAD_GPIO1_3__I2C2_SDA              0x400001ed
+                       >;
+               };
+
+               pinctrl_nfc: nfcgrp {
+                       fsl,pins = <
+                               MX51_PAD_NANDF_D0__NANDF_D0             0x80000000
+                               MX51_PAD_NANDF_D1__NANDF_D1             0x80000000
+                               MX51_PAD_NANDF_D2__NANDF_D2             0x80000000
+                               MX51_PAD_NANDF_D3__NANDF_D3             0x80000000
+                               MX51_PAD_NANDF_D4__NANDF_D4             0x80000000
+                               MX51_PAD_NANDF_D5__NANDF_D5             0x80000000
+                               MX51_PAD_NANDF_D6__NANDF_D6             0x80000000
+                               MX51_PAD_NANDF_D7__NANDF_D7             0x80000000
+                               MX51_PAD_NANDF_ALE__NANDF_ALE           0x80000000
+                               MX51_PAD_NANDF_CLE__NANDF_CLE           0x80000000
+                               MX51_PAD_NANDF_RE_B__NANDF_RE_B         0x80000000
+                               MX51_PAD_NANDF_WE_B__NANDF_WE_B         0x80000000
+                               MX51_PAD_NANDF_WP_B__NANDF_WP_B         0x80000000
+                               MX51_PAD_NANDF_CS0__NANDF_CS0           0x80000000
+                               MX51_PAD_NANDF_RB0__NANDF_RB0           0x80000000
+                       >;
+               };
+
+               pinctrl_lan9221: lan9221grp {
+                       fsl,pins = <
+                               MX51_PAD_GPIO1_9__GPIO1_9               0xe5 /* IRQ */
+                       >;
+               };
+
+               pinctrl_mc13892: mc13892grp {
+                       fsl,pins = <
+                               MX51_PAD_GPIO1_5__GPIO1_5               0xe5 /* IRQ */
+                       >;
+               };
+
+               pinctrl_mma7455l: mma7455lgrp {
+                       fsl,pins = <
+                               MX51_PAD_GPIO1_7__GPIO1_7               0xe5 /* IRQ1 */
+                               MX51_PAD_GPIO1_6__GPIO1_6               0xe5 /* IRQ2 */
+                       >;
+               };
+
+               pinctrl_weim: weimgrp {
+                       fsl,pins = <
+                               MX51_PAD_EIM_DA0__EIM_DA0               0x80000000
+                               MX51_PAD_EIM_DA1__EIM_DA1               0x80000000
+                               MX51_PAD_EIM_DA2__EIM_DA2               0x80000000
+                               MX51_PAD_EIM_DA3__EIM_DA3               0x80000000
+                               MX51_PAD_EIM_DA4__EIM_DA4               0x80000000
+                               MX51_PAD_EIM_DA5__EIM_DA5               0x80000000
+                               MX51_PAD_EIM_DA6__EIM_DA6               0x80000000
+                               MX51_PAD_EIM_DA7__EIM_DA7               0x80000000
+                               MX51_PAD_EIM_DA8__EIM_DA8               0x80000000
+                               MX51_PAD_EIM_DA9__EIM_DA9               0x80000000
+                               MX51_PAD_EIM_DA10__EIM_DA10             0x80000000
+                               MX51_PAD_EIM_DA11__EIM_DA11             0x80000000
+                               MX51_PAD_EIM_DA12__EIM_DA12             0x80000000
+                               MX51_PAD_EIM_DA13__EIM_DA13             0x80000000
+                               MX51_PAD_EIM_DA14__EIM_DA14             0x80000000
+                               MX51_PAD_EIM_DA15__EIM_DA15             0x80000000
+                               MX51_PAD_EIM_A16__EIM_A16               0x80000000
+                               MX51_PAD_EIM_A17__EIM_A17               0x80000000
+                               MX51_PAD_EIM_A18__EIM_A18               0x80000000
+                               MX51_PAD_EIM_A19__EIM_A19               0x80000000
+                               MX51_PAD_EIM_A20__EIM_A20               0x80000000
+                               MX51_PAD_EIM_A21__EIM_A21               0x80000000
+                               MX51_PAD_EIM_A22__EIM_A22               0x80000000
+                               MX51_PAD_EIM_A23__EIM_A23               0x80000000
+                               MX51_PAD_EIM_A24__EIM_A24               0x80000000
+                               MX51_PAD_EIM_A25__EIM_A25               0x80000000
+                               MX51_PAD_EIM_A26__EIM_A26               0x80000000
+                               MX51_PAD_EIM_A27__EIM_A27               0x80000000
+                               MX51_PAD_EIM_D16__EIM_D16               0x80000000
+                               MX51_PAD_EIM_D17__EIM_D17               0x80000000
+                               MX51_PAD_EIM_D18__EIM_D18               0x80000000
+                               MX51_PAD_EIM_D19__EIM_D19               0x80000000
+                               MX51_PAD_EIM_D20__EIM_D20               0x80000000
+                               MX51_PAD_EIM_D21__EIM_D21               0x80000000
+                               MX51_PAD_EIM_D22__EIM_D22               0x80000000
+                               MX51_PAD_EIM_D23__EIM_D23               0x80000000
+                               MX51_PAD_EIM_D24__EIM_D24               0x80000000
+                               MX51_PAD_EIM_D25__EIM_D25               0x80000000
+                               MX51_PAD_EIM_D26__EIM_D26               0x80000000
+                               MX51_PAD_EIM_D27__EIM_D27               0x80000000
+                               MX51_PAD_EIM_D28__EIM_D28               0x80000000
+                               MX51_PAD_EIM_D29__EIM_D29               0x80000000
+                               MX51_PAD_EIM_D30__EIM_D30               0x80000000
+                               MX51_PAD_EIM_D31__EIM_D31               0x80000000
+                               MX51_PAD_EIM_OE__EIM_OE                 0x80000000
+                               MX51_PAD_EIM_DTACK__EIM_DTACK           0x80000000
+                               MX51_PAD_EIM_LBA__EIM_LBA               0x80000000
+                               MX51_PAD_EIM_CS5__EIM_CS5               0x80000000 /* CS5 */
+                       >;
+               };
+       };
+};
index 9b3acf6e4282f3735e27e3a7c0467821fcfe95bc..63164266af8309c04ed8e82e17257d5ea02e6633 100644 (file)
                compatible = "nxp,pcf8563";
                reg = <0x51>;
        };
+
+       tsc2007: tsc2007@49 {
+               compatible = "ti,tsc2007";
+               gpios = <&gpio4 0 1>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <0x0 0x8>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tsc2007_1>;
+               reg = <0x49>;
+               ti,x-plate-ohms = <180>;
+       };
 };
 
 &iomuxc {
index 5cec4f322096086b05f88a1e011dae2e210c8f10..8b1098ebaf79015f59dddc019f0d1af5f6f616e8 100644 (file)
                fsl,mux-int-port = <2>;
                fsl,mux-ext-port = <3>;
        };
+
+       usbphy {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "simple-bus";
+
+               usbh1phy: usbh1phy@0 {
+                       compatible = "usb-nop-xceiv";
+                       reg = <0>;
+                       clocks = <&clks IMX5_CLK_USB_PHY_GATE>;
+                       clock-names = "main_clk";
+                       clock-frequency = <19200000>;
+               };
+       };
 };
 
 &audmux {
                                MX51_PAD_CSI1_D9__GPIO3_13 0x1f5
                        >;
                };
+
+               pinctrl_usbh1: usbh1grp {
+                       fsl,pins = <
+                               MX51_PAD_USBH1_CLK__USBH1_CLK     0x1e5
+                               MX51_PAD_USBH1_DIR__USBH1_DIR     0x1e5
+                               MX51_PAD_USBH1_NXT__USBH1_NXT     0x1e5
+                               MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5
+                               MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5
+                               MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5
+                               MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5
+                               MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5
+                               MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5
+                               MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5
+                               MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5
+                               MX51_PAD_USBH1_STP__USBH1_STP     0x1e5
+                       >;
+               };
+
+               pinctrl_usbh1_vbus: usbh1-vbusgrp {
+                       fsl,pins = <
+                               MX51_PAD_EIM_CS3__GPIO2_28 0x1f5
+                       >;
+               };
        };
 };
 
        fsl,uart-has-rtscts;
        status = "okay";
 };
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       fsl,usbphy = <&usbh1phy>;
+       dr_mode = "host";
+       phy_type = "ulpi";
+       status = "okay";
+};
+
+&usbotg {
+       dr_mode = "otg";
+       phy_type = "utmi_wide";
+       status = "okay";
+};
+
+&usbphy0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1_vbus>;
+       reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
+};
index 150bb4e2f744374fd712895ce30786dc9fdb7b25..bebbf3ba0d5e37acac9b12e11fbefc732110bff6 100644 (file)
@@ -19,6 +19,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                        };
 
                        nfc: nand@83fdb000 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
                                compatible = "fsl,imx51-nand";
                                reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>;
                                interrupts = <8>;
index ede04fa4161f63aeb925e35267608a12a0c5b0cc..df9cd9d41c4f8081345b09f7bc47f49d1271b49d 100644 (file)
                        >;
                };
 
+               pinctrl_vga_sync: vgasync-grp {
+                       fsl,pins = <
+                               /* VGA_HSYNC, VSYNC with max drive strength */
+                               MX53_PAD_EIM_OE__IPU_DI1_PIN7 0xe6
+                               MX53_PAD_EIM_RW__IPU_DI1_PIN8 0xe6
+                       >;
+               };
+
                pinctrl_uart1: uart1grp {
                        fsl,pins = <
                                MX53_PAD_CSI0_DAT10__UART1_TXD_MUX      0x1e4
        };
 };
 
+&tve {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_vga_sync>;
+       fsl,tve-mode = "vga";
+       fsl,hsync-pin = <4>;
+       fsl,vsync-pin = <6>;
+       status = "okay";
+};
+
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
index 9c2bff2252d0d078514348ab2bc92aad7ea5a6fb..375e66fad578e2e67ef611174fff6bd66708f6a2 100644 (file)
@@ -18,6 +18,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                                clocks = <&clks IMX5_CLK_VPU_GATE>,
                                         <&clks IMX5_CLK_VPU_GATE>;
                                clock-names = "per", "ahb";
+                               resets = <&src 1>;
                                iram = <&ocram>;
-                               status = "disabled";
                        };
                };
 
diff --git a/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts b/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts
new file mode 100644 (file)
index 0000000..08e9780
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH
+ *
+ * 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 "imx6dl-phytec-pfla02.dtsi"
+#include "imx6qdl-phytec-pbab01.dtsi"
+
+/ {
+       model = "Phytec phyFLEX-i.MX6 DualLite/Solo Carrier-Board";
+       compatible = "phytec,imx6dl-pbab01", "phytec,imx6dl-pfla02", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi
new file mode 100644 (file)
index 0000000..964bc2a
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH
+ *
+ * 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
+ */
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-phytec-pfla02.dtsi"
+
+/ {
+       model = "Phytec phyFLEX-i.MX6 DualLite/Solo";
+       compatible = "phytec,imx6dl-pfla02", "fsl,imx6dl";
+
+       memory {
+               reg = <0x10000000 0x20000000>;
+       };
+};
index 4a9b4dc9afc0ab85801ad0acb94e45d209be6922..0f0c50be8859c3bdf9b3ab163c2f6651c0653a7d 100644 (file)
        };
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
 /* Internal I2C */
 &i2c2 {
        pinctrl-names = "default";
index e51bb3f0fd560ddec5372582549b8b3a8f922cb0..3689eaa58826eecebce2ec4dd4adda99b12d2fc2 100644 (file)
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
index 5607c331fca8f4db3356a93a2aa75f97b1b2b11f..3a43dab728a82045d86c7ee021301e4f7a26ea20 100644 (file)
 
 /dts-v1/;
 #include "imx6q-phytec-pfla02.dtsi"
+#include "imx6qdl-phytec-pbab01.dtsi"
 
 / {
        model = "Phytec phyFLEX-i.MX6 Quad Carrier-Board";
        compatible = "phytec,imx6q-pbab01", "phytec,imx6q-pfla02", "fsl,imx6q";
 };
 
-&fec {
-       status = "okay";
-};
-
-&gpmi {
-       status = "okay";
-};
-
 &sata {
-       status = "okay";
-};
-
-&uart4 {
-       status = "okay";
-};
-
-&usbh1 {
-       status = "okay";
-};
-
-&usbotg {
-       status = "okay";
-};
-
-&usdhc2 {
-       status = "okay";
-};
-
-&usdhc3 {
-       status = "okay";
+        status = "okay";
 };
index 324f1550976b6503d641c23a5da07c1187fc96c9..cd20d0a948de4ce45d726b6e0616d4de82bcb795 100644 (file)
  */
 
 #include "imx6q.dtsi"
+#include "imx6qdl-phytec-pfla02.dtsi"
 
 / {
-       model = "Phytec phyFLEX-i.MX6 Ouad";
+       model = "Phytec phyFLEX-i.MX6 Quad";
        compatible = "phytec,imx6q-pfla02", "fsl,imx6q";
 
        memory {
                reg = <0x10000000 0x80000000>;
        };
-
-       regulators {
-               compatible = "simple-bus";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               reg_usb_otg_vbus: regulator@0 {
-                       compatible = "regulator-fixed";
-                       reg = <0>;
-                       regulator-name = "usb_otg_vbus";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       gpio = <&gpio4 15 0>;
-               };
-
-               reg_usb_h1_vbus: regulator@1 {
-                       compatible = "regulator-fixed";
-                       reg = <1>;
-                       regulator-name = "usb_h1_vbus";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       gpio = <&gpio1 0 0>;
-               };
-       };
-};
-
-&ecspi3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi3>;
-       status = "okay";
-       fsl,spi-num-chipselects = <1>;
-       cs-gpios = <&gpio4 24 0>;
-
-       flash@0 {
-               compatible = "m25p80";
-               spi-max-frequency = <20000000>;
-               reg = <0>;
-       };
-};
-
-&i2c1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c1>;
-       status = "okay";
-
-       eeprom@50 {
-               compatible = "atmel,24c32";
-               reg = <0x50>;
-       };
-
-       pmic@58 {
-               compatible = "dialog,da9063";
-               reg = <0x58>;
-               interrupt-parent = <&gpio4>;
-               interrupts = <17 0x8>; /* active-low GPIO4_17 */
-
-               regulators {
-                       vddcore_reg: bcore1 {
-                               regulator-min-microvolt = <730000>;
-                               regulator-max-microvolt = <1380000>;
-                               regulator-always-on;
-                       };
-
-                       vddsoc_reg: bcore2 {
-                               regulator-min-microvolt = <730000>;
-                               regulator-max-microvolt = <1380000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_ddr3_reg: bpro {
-                               regulator-min-microvolt = <1500000>;
-                               regulator-max-microvolt = <1500000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_3v3_reg: bperi {
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_buckmem_reg: bmem {
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_eth_reg: bio {
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <1200000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_eth_io_reg: ldo4 {
-                               regulator-min-microvolt = <2500000>;
-                               regulator-max-microvolt = <2500000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_mx6_snvs_reg: ldo5 {
-                               regulator-min-microvolt = <3000000>;
-                               regulator-max-microvolt = <3000000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_3v3_pmic_io_reg: ldo6 {
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_sd0_reg: ldo9 {
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                       };
-
-                       vdd_sd1_reg: ldo10 {
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                       };
-
-                       vdd_mx6_high_reg: ldo11 {
-                               regulator-min-microvolt = <3000000>;
-                               regulator-max-microvolt = <3000000>;
-                               regulator-always-on;
-                       };
-               };
-       };
-};
-
-&iomuxc {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_hog>;
-
-       imx6q-phytec-pfla02 {
-               pinctrl_hog: hoggrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000
-                               MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */
-                               MX6QDL_PAD_DI0_PIN15__GPIO4_IO17  0x80000000 /* PMIC interrupt */
-                       >;
-               };
-
-               pinctrl_ecspi3: ecspi3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO      0x100b1
-                               MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI      0x100b1
-                               MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK      0x100b1
-                       >;
-               };
-
-               pinctrl_enet: enetgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b0b0
-                               MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
-                               MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x1b0b0
-                               MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x1b0b0
-                               MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x1b0b0
-                               MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x1b0b0
-                               MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x1b0b0
-                               MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x1b0b0
-                               MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x1b0b0
-                               MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x1b0b0
-                               MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x1b0b0
-                               MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x1b0b0
-                               MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1b0b0
-                               MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1b0b0
-                               MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x1b0b0
-                               MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN       0x1b0b0
-                       >;
-               };
-
-               pinctrl_gpmi_nand: gpminandgrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_NANDF_CLE__NAND_CLE          0xb0b1
-                               MX6QDL_PAD_NANDF_ALE__NAND_ALE          0xb0b1
-                               MX6QDL_PAD_NANDF_WP_B__NAND_WP_B        0xb0b1
-                               MX6QDL_PAD_NANDF_RB0__NAND_READY_B      0xb000
-                               MX6QDL_PAD_NANDF_CS0__NAND_CE0_B        0xb0b1
-                               MX6QDL_PAD_NANDF_CS1__NAND_CE1_B        0xb0b1
-                               MX6QDL_PAD_SD4_CMD__NAND_RE_B           0xb0b1
-                               MX6QDL_PAD_SD4_CLK__NAND_WE_B           0xb0b1
-                               MX6QDL_PAD_NANDF_D0__NAND_DATA00        0xb0b1
-                               MX6QDL_PAD_NANDF_D1__NAND_DATA01        0xb0b1
-                               MX6QDL_PAD_NANDF_D2__NAND_DATA02        0xb0b1
-                               MX6QDL_PAD_NANDF_D3__NAND_DATA03        0xb0b1
-                               MX6QDL_PAD_NANDF_D4__NAND_DATA04        0xb0b1
-                               MX6QDL_PAD_NANDF_D5__NAND_DATA05        0xb0b1
-                               MX6QDL_PAD_NANDF_D6__NAND_DATA06        0xb0b1
-                               MX6QDL_PAD_NANDF_D7__NAND_DATA07        0xb0b1
-                               MX6QDL_PAD_SD4_DAT0__NAND_DQS           0x00b1
-                       >;
-               };
-
-               pinctrl_i2c1: i2c1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_EIM_D21__I2C1_SCL            0x4001b8b1
-                               MX6QDL_PAD_EIM_D28__I2C1_SDA            0x4001b8b1
-                       >;
-               };
-
-               pinctrl_uart4: uart4grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_KEY_COL0__UART4_TX_DATA      0x1b0b1
-                               MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA      0x1b0b1
-                       >;
-               };
-
-               pinctrl_usbh1: usbh1grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_0__USB_H1_PWR           0x80000000
-                       >;
-               };
-
-               pinctrl_usbotg: usbotggrp {
-                       fsl,pins = <
-                               MX6QDL_PAD_GPIO_1__USB_OTG_ID           0x17059
-                               MX6QDL_PAD_KEY_COL4__USB_OTG_OC         0x1b0b0
-                               MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0x80000000
-                       >;
-               };
-
-               pinctrl_usdhc2: usdhc2grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD2_CMD__SD2_CMD             0x17059
-                               MX6QDL_PAD_SD2_CLK__SD2_CLK             0x10059
-                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0          0x17059
-                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1          0x17059
-                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2          0x17059
-                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3          0x17059
-                       >;
-               };
-
-               pinctrl_usdhc3: usdhc3grp {
-                       fsl,pins = <
-                               MX6QDL_PAD_SD3_CMD__SD3_CMD             0x17059
-                               MX6QDL_PAD_SD3_CLK__SD3_CLK             0x10059
-                               MX6QDL_PAD_SD3_DAT0__SD3_DATA0          0x17059
-                               MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x17059
-                               MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x17059
-                               MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
-                       >;
-               };
-
-               pinctrl_usdhc3_cdwp: usdhc3cdwp {
-                       fsl,pins = <
-                               MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000
-                               MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000
-                       >;
-               };
-       };
-};
-
-&fec {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
-       phy-reset-gpios = <&gpio3 23 0>;
-       status = "disabled";
-};
-
-&gpmi {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpmi_nand>;
-       nand-on-flash-bbt;
-       status = "disabled";
-};
-
-&uart4 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart4>;
-       status = "disabled";
-};
-
-&usbh1 {
-       vbus-supply = <&reg_usb_h1_vbus>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usbh1>;
-       status = "disabled";
-};
-
-&usbotg {
-       vbus-supply = <&reg_usb_otg_vbus>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usbotg>;
-       disable-over-current;
-       status = "disabled";
-};
-
-&usdhc2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio1 4 0>;
-       wp-gpios = <&gpio1 2 0>;
-       status = "disabled";
-};
-
-&usdhc3 {
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_usdhc3
-                    &pinctrl_usdhc3_cdwp>;
-        cd-gpios = <&gpio1 27 0>;
-        wp-gpios = <&gpio1 29 0>;
-        status = "disabled";
 };
index 98a422153ce7b9d6bf9b292093763659af676a10..31665adcbf399ee436082d3ff3a1dc20334c9c9a 100644 (file)
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
index 035d3a85c318b1f842d0d3664a2e0cd9d56ab798..102219761b206e5e11af2071838dfae7a4fd7038 100644 (file)
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
index c8e5ae06deaf51474447675a1a3ade8658884f0d..523f26f11eea435c67b31809aa1241d2d6ba3d9f 100644 (file)
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
index 2795dfc8c92632ff0d6222e71e9826b59af232cc..cab94bfdf69191c194c72f8ee3fc42879291da8d 100644 (file)
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi
new file mode 100644 (file)
index 0000000..5847212
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH
+ *
+ * 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
+ */
+
+/ {
+       chosen {
+               linux,stdout-path = &uart4;
+       };
+};
+
+&fec {
+       status = "okay";
+};
+
+&gpmi {
+       status = "okay";
+};
+
+&hdmi {
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       clock-frequency = <100000>;
+       status = "okay";
+
+       tlv320@18 {
+               compatible = "ti,tlv320aic3x";
+               reg = <0x18>;
+       };
+
+       stmpe@41 {
+               compatible = "st,stmpe811";
+               reg = <0x41>;
+       };
+
+       rtc@51 {
+               compatible = "nxp,rtc8564";
+               reg = <0x51>;
+       };
+
+       adc@64 {
+               compatible = "maxim,max1037";
+               reg = <0x64>;
+       };
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       clock-frequency = <100000>;
+       status = "okay";
+};
+
+&uart3 {
+       status = "okay";
+};
+
+&uart4 {
+       status = "okay";
+};
+
+&usbh1 {
+       status = "okay";
+};
+
+&usbotg {
+       status = "okay";
+};
+
+&usdhc2 {
+       status = "okay";
+};
+
+&usdhc3 {
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_EB2__I2C2_SCL            0x4001b8b1
+                       MX6QDL_PAD_EIM_D16__I2C2_SDA            0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D17__I2C3_SCL            0x4001b8b1
+                       MX6QDL_PAD_EIM_D18__I2C3_SDA            0x4001b8b1
+               >;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
new file mode 100644 (file)
index 0000000..faa3494
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH
+ *
+ * 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
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Phytec phyFLEX-i.MX6 Ouad";
+       compatible = "phytec,imx6q-pfla02", "fsl,imx6q";
+
+       memory {
+               reg = <0x10000000 0x80000000>;
+       };
+
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               reg_usb_otg_vbus: regulator@0 {
+                       compatible = "regulator-fixed";
+                       reg = <0>;
+                       regulator-name = "usb_otg_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio4 15 0>;
+               };
+
+               reg_usb_h1_vbus: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "usb_h1_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio1 0 0>;
+               };
+       };
+
+       gpio_leds: leds {
+               compatible = "gpio-leds";
+
+               green {
+                       label = "phyflex:green";
+                       gpios = <&gpio1 30 0>;
+               };
+
+               red {
+                       label = "phyflex:red";
+                       gpios = <&gpio2 31 0>;
+               };
+       };
+};
+
+&ecspi3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi3>;
+       status = "okay";
+       fsl,spi-num-chipselects = <1>;
+       cs-gpios = <&gpio4 24 0>;
+
+       flash@0 {
+               compatible = "m25p80";
+               spi-max-frequency = <20000000>;
+               reg = <0>;
+       };
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c32";
+               reg = <0x50>;
+       };
+
+       pmic@58 {
+               compatible = "dialog,da9063";
+               reg = <0x58>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <17 0x8>; /* active-low GPIO4_17 */
+
+               regulators {
+                       vddcore_reg: bcore1 {
+                               regulator-min-microvolt = <730000>;
+                               regulator-max-microvolt = <1380000>;
+                               regulator-always-on;
+                       };
+
+                       vddsoc_reg: bcore2 {
+                               regulator-min-microvolt = <730000>;
+                               regulator-max-microvolt = <1380000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_ddr3_reg: bpro {
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_3v3_reg: bperi {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_buckmem_reg: bmem {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_eth_reg: bio {
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_eth_io_reg: ldo4 {
+                               regulator-min-microvolt = <2500000>;
+                               regulator-max-microvolt = <2500000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_mx6_snvs_reg: ldo5 {
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_3v3_pmic_io_reg: ldo6 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vdd_sd0_reg: ldo9 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vdd_sd1_reg: ldo10 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vdd_mx6_high_reg: ldo11 {
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                       };
+               };
+       };
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       imx6q-phytec-pfla02 {
+               pinctrl_hog: hoggrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000
+                               MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */
+                               MX6QDL_PAD_DI0_PIN15__GPIO4_IO17  0x80000000 /* PMIC interrupt */
+                               MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */
+                               MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */
+                       >;
+               };
+
+               pinctrl_ecspi3: ecspi3grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO      0x100b1
+                               MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI      0x100b1
+                               MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK      0x100b1
+                       >;
+               };
+
+               pinctrl_enet: enetgrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b0b0
+                               MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
+                               MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x1b0b0
+                               MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x1b0b0
+                               MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x1b0b0
+                               MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x1b0b0
+                               MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x1b0b0
+                               MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x1b0b0
+                               MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1b0b0
+                               MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1b0b0
+                               MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x1b0b0
+                               MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN       0x1b0b0
+                       >;
+               };
+
+               pinctrl_gpmi_nand: gpminandgrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_NANDF_CLE__NAND_CLE          0xb0b1
+                               MX6QDL_PAD_NANDF_ALE__NAND_ALE          0xb0b1
+                               MX6QDL_PAD_NANDF_WP_B__NAND_WP_B        0xb0b1
+                               MX6QDL_PAD_NANDF_RB0__NAND_READY_B      0xb000
+                               MX6QDL_PAD_NANDF_CS0__NAND_CE0_B        0xb0b1
+                               MX6QDL_PAD_NANDF_CS1__NAND_CE1_B        0xb0b1
+                               MX6QDL_PAD_SD4_CMD__NAND_RE_B           0xb0b1
+                               MX6QDL_PAD_SD4_CLK__NAND_WE_B           0xb0b1
+                               MX6QDL_PAD_NANDF_D0__NAND_DATA00        0xb0b1
+                               MX6QDL_PAD_NANDF_D1__NAND_DATA01        0xb0b1
+                               MX6QDL_PAD_NANDF_D2__NAND_DATA02        0xb0b1
+                               MX6QDL_PAD_NANDF_D3__NAND_DATA03        0xb0b1
+                               MX6QDL_PAD_NANDF_D4__NAND_DATA04        0xb0b1
+                               MX6QDL_PAD_NANDF_D5__NAND_DATA05        0xb0b1
+                               MX6QDL_PAD_NANDF_D6__NAND_DATA06        0xb0b1
+                               MX6QDL_PAD_NANDF_D7__NAND_DATA07        0xb0b1
+                               MX6QDL_PAD_SD4_DAT0__NAND_DQS           0x00b1
+                       >;
+               };
+
+               pinctrl_i2c1: i2c1grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D21__I2C1_SCL            0x4001b8b1
+                               MX6QDL_PAD_EIM_D28__I2C1_SDA            0x4001b8b1
+                       >;
+               };
+
+               pinctrl_uart3: uart3grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D24__UART3_TX_DATA       0x1b0b1
+                               MX6QDL_PAD_EIM_D25__UART3_RX_DATA       0x1b0b1
+                               MX6QDL_PAD_EIM_D30__UART3_RTS_B         0x1b0b1
+                               MX6QDL_PAD_EIM_D31__UART3_CTS_B         0x1b0b1
+                       >;
+               };
+
+               pinctrl_uart4: uart4grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_KEY_COL0__UART4_TX_DATA      0x1b0b1
+                               MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA      0x1b0b1
+                       >;
+               };
+
+               pinctrl_usbh1: usbh1grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_0__USB_H1_PWR           0x80000000
+                       >;
+               };
+
+               pinctrl_usbotg: usbotggrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_1__USB_OTG_ID           0x17059
+                               MX6QDL_PAD_KEY_COL4__USB_OTG_OC         0x1b0b0
+                               MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0x80000000
+                       >;
+               };
+
+               pinctrl_usdhc2: usdhc2grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD2_CMD__SD2_CMD             0x17059
+                               MX6QDL_PAD_SD2_CLK__SD2_CLK             0x10059
+                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0          0x17059
+                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1          0x17059
+                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2          0x17059
+                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3          0x17059
+                       >;
+               };
+
+               pinctrl_usdhc3: usdhc3grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD3_CMD__SD3_CMD             0x17059
+                               MX6QDL_PAD_SD3_CLK__SD3_CLK             0x10059
+                               MX6QDL_PAD_SD3_DAT0__SD3_DATA0          0x17059
+                               MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x17059
+                               MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x17059
+                               MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
+                       >;
+               };
+
+               pinctrl_usdhc3_cdwp: usdhc3cdwp {
+                       fsl,pins = <
+                               MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000
+                               MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000
+                       >;
+               };
+       };
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-mode = "rgmii";
+       phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+       status = "disabled";
+};
+
+&gpmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpmi_nand>;
+       nand-on-flash-bbt;
+       status = "disabled";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       status = "disabled";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       status = "disabled";
+};
+
+&usbh1 {
+       vbus-supply = <&reg_usb_h1_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       status = "disabled";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usb_otg_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       disable-over-current;
+       status = "disabled";
+};
+
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       cd-gpios = <&gpio1 4 0>;
+       wp-gpios = <&gpio1 2 0>;
+       status = "disabled";
+};
+
+&usdhc3 {
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_usdhc3
+                    &pinctrl_usdhc3_cdwp>;
+        cd-gpios = <&gpio1 27 0>;
+        wp-gpios = <&gpio1 29 0>;
+        status = "disabled";
+};
index 0d816d3be4b697a30998506be266244b78d45590..dbbd35b899856c18dcc271583ca566a70a73ab0d 100644 (file)
                default-brightness-level = <7>;
                status = "okay";
        };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_leds>;
+
+               red {
+                       gpios = <&gpio1 2 0>;
+                       default-state = "on";
+               };
+       };
 };
 
 &audmux {
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c2>;
+       status = "okay";
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
                        >;
                };
 
+               pinctrl_pcie: pciegrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D19__GPIO3_IO19  0x80000000
+                               MX6QDL_PAD_GPIO_17__GPIO7_IO12  0x80000000
+                       >;
+               };
+
                pinctrl_pwm1: pwm1grp {
                        fsl,pins = <
                                MX6QDL_PAD_SD1_DAT3__PWM1_OUT           0x1b0b1
                        >;
                };
        };
+
+       gpio_leds {
+               pinctrl_gpio_leds: gpioledsgrp {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000
+                       >;
+               };
+       };
 };
 
 &ldb {
        };
 };
 
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       power-on-gpio = <&gpio3 19 0>;
+       reset-gpio = <&gpio7 12 0>;
+       status = "okay";
+};
+
 &pwm1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm1>;
index bdfdf89d405fcf4ae2202844445eeb4adeaa80e7..5c6f10c43f65644bb4ab1367843fbf46918b90a9 100644 (file)
        status = "okay";
 };
 
+&hdmi {
+       ddc-i2c-bus = <&i2c1>;
+       status = "okay";
+};
+
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
 &i2c2 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
                        >;
                };
 
+               pinctrl_i2c1: i2c1grp {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D21__I2C1_SCL            0x4001b8b1
+                               MX6QDL_PAD_EIM_D28__I2C1_SDA            0x4001b8b1
+                       >;
+               };
+
                pinctrl_i2c2: i2c2grp {
                        fsl,pins = <
                                MX6QDL_PAD_KEY_COL3__I2C2_SCL           0x4001b8b1
index eca0971d4db1ae7885985e8ce966d6475b3f3991..ce0599134a699dd338b6f42adef8378e94a7d6e1 100644 (file)
@@ -16,6 +16,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                can0 = &can1;
                can1 = &can2;
                gpio0 = &gpio1;
                                  0x81000000 0 0          0x01f80000 0 0x00010000 /* downstream I/O */
                                  0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
                        num-lanes = <1>;
-                       interrupts = <0 123 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
                                        <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
                                        <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
                                        <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clks 189>, <&clks 187>, <&clks 206>, <&clks 144>;
-                       clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi";
+                       clocks = <&clks 144>, <&clks 206>, <&clks 189>;
+                       clock-names = "pcie", "pcie_bus", "pcie_phy";
                        status = "disabled";
                };
 
index d26b099260a35da021d85c9f20907294fcd27625..2d4e5285f3f36556a15c4d0b0ff6561ae3db4d2a 100644 (file)
@@ -14,6 +14,7 @@
 
 / {
        aliases {
+               ethernet0 = &fec;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
index 3916937d6818032bc0c6aeb19594f8db3773479b..dd81508b919b87349b2cc3260f405470e84957d8 100644 (file)
@@ -1,6 +1,6 @@
 / {
        mbus {
-               pcie-controller {
+               pciec: pcie-controller {
                        compatible = "marvell,kirkwood-pcie";
                        status = "disabled";
                        device_type = "pci";
@@ -15,7 +15,7 @@
                                0x82000000 0x1 0     MBUS_ID(0x04, 0xe8) 0       1 0 /* Port 0.0 MEM */
                                0x81000000 0x1 0     MBUS_ID(0x04, 0xe0) 0       1 0 /* Port 0.0 IO  */>;
 
-                       pcie@1,0 {
+                       pcie0: pcie@1,0 {
                                device_type = "pci";
                                assigned-addresses = <0x82000800 0 0x00040000 0 0x2000>;
                                reg = <0x0800 0 0 0 0>;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        compatible = "marvell,88f6192-pinctrl";
-                       reg = <0x10000 0x20>;
 
-                       pmx_nand: pmx-nand {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3",
-                                              "mpp4", "mpp5", "mpp18",
-                                              "mpp19";
-                               marvell,function = "nand";
-                       };
                        pmx_sata0: pmx-sata0 {
                                marvell,pins = "mpp5", "mpp21", "mpp23";
                                marvell,function = "sata0";
                                marvell,pins = "mpp4", "mpp20", "mpp22";
                                marvell,function = "sata1";
                        };
-                       pmx_spi: pmx-spi {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3";
-                               marvell,function = "spi";
-                       };
-                       pmx_twsi0: pmx-twsi0 {
-                               marvell,pins = "mpp8", "mpp9";
-                               marvell,function = "twsi0";
-                       };
-                       pmx_uart0: pmx-uart0 {
-                               marvell,pins = "mpp10", "mpp11";
-                               marvell,function = "uart0";
-                       };
-                       pmx_uart1: pmx-uart1 {
-                               marvell,pins = "mpp13", "mpp14";
-                               marvell,function = "uart1";
-                       };
                        pmx_sdio: pmx-sdio {
                                marvell,pins = "mpp12", "mpp13", "mpp14",
                                               "mpp15", "mpp16", "mpp17";
                        };
                };
 
-               rtc@10300 {
+               rtc: rtc@10300 {
                        compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc";
                        reg = <0x10300 0x20>;
                        interrupts = <53>;
                        clocks = <&gate_clk 7>;
                };
 
-               sata@80000 {
+               sata: sata@80000 {
                        compatible = "marvell,orion-sata";
                        reg = <0x80000 0x5000>;
                        interrupts = <21>;
@@ -92,7 +69,7 @@
                        status = "disabled";
                };
 
-               mvsdio@90000 {
+               sdio: mvsdio@90000 {
                        compatible = "marvell,orion-sdio";
                        reg = <0x90000 0x200>;
                        interrupts = <28>;
index 416d96e1302fab6e9af0d61ebb5cdbbe0290cfa7..7dc7d6782e8325012b8b7ad8fe52676ab15ca404 100644 (file)
@@ -1,6 +1,6 @@
 / {
        mbus {
-               pcie-controller {
+               pciec: pcie-controller {
                        compatible = "marvell,kirkwood-pcie";
                        status = "disabled";
                        device_type = "pci";
@@ -15,7 +15,7 @@
                                0x82000000 0x1 0     MBUS_ID(0x04, 0xe8) 0       1 0 /* Port 0.0 MEM */
                                0x81000000 0x1 0     MBUS_ID(0x04, 0xe0) 0       1 0 /* Port 0.0 IO  */>;
 
-                       pcie@1,0 {
+                       pcie0: pcie@1,0 {
                                device_type = "pci";
                                assigned-addresses = <0x82000800 0 0x00040000 0 0x2000>;
                                reg = <0x0800 0 0 0 0>;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        compatible = "marvell,88f6281-pinctrl";
-                       reg = <0x10000 0x20>;
 
-                       pmx_nand: pmx-nand {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3",
-                                              "mpp4", "mpp5", "mpp18",
-                                              "mpp19";
-                               marvell,function = "nand";
-                       };
                        pmx_sata0: pmx-sata0 {
                                marvell,pins = "mpp5", "mpp21", "mpp23";
                                marvell,function = "sata0";
                                marvell,pins = "mpp4", "mpp20", "mpp22";
                                marvell,function = "sata1";
                        };
-                       pmx_spi: pmx-spi {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3";
-                               marvell,function = "spi";
-                       };
-                       pmx_twsi0: pmx-twsi0 {
-                               marvell,pins = "mpp8", "mpp9";
-                               marvell,function = "twsi0";
-                       };
-                       pmx_uart0: pmx-uart0 {
-                               marvell,pins = "mpp10", "mpp11";
-                               marvell,function = "uart0";
-                       };
-                       pmx_uart1: pmx-uart1 {
-                               marvell,pins = "mpp13", "mpp14";
-                               marvell,function = "uart1";
-                       };
                        pmx_sdio: pmx-sdio {
                                marvell,pins = "mpp12", "mpp13", "mpp14",
                                               "mpp15", "mpp16", "mpp17";
                        };
                };
 
-               rtc@10300 {
+               rtc: rtc@10300 {
                        compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc";
                        reg = <0x10300 0x20>;
                        interrupts = <53>;
                        clocks = <&gate_clk 7>;
                };
 
-               sata@80000 {
+               sata: sata@80000 {
                        compatible = "marvell,orion-sata";
                        reg = <0x80000 0x5000>;
                        interrupts = <21>;
@@ -94,7 +71,7 @@
                        status = "disabled";
                };
 
-               mvsdio@90000 {
+               sdio: mvsdio@90000 {
                        compatible = "marvell,orion-sdio";
                        reg = <0x90000 0x200>;
                        interrupts = <28>;
index 2902e0d7971d061599d13ef8733e3a3c4ad49fd2..4680eec990f0cd3bc92a985b57e954303ee2f0b4 100644 (file)
@@ -1,6 +1,6 @@
 / {
        mbus {
-               pcie-controller {
+               pciec: pcie-controller {
                        compatible = "marvell,kirkwood-pcie";
                        status = "disabled";
                        device_type = "pci";
@@ -19,7 +19,7 @@
                                0x82000000 0x2 0     MBUS_ID(0x04, 0xd8) 0       1 0 /* Port 1.0 MEM */
                                0x81000000 0x2 0     MBUS_ID(0x04, 0xd0) 0       1 0 /* Port 1.0 IO  */>;
 
-                       pcie@1,0 {
+                       pcie0: pcie@1,0 {
                                device_type = "pci";
                                assigned-addresses = <0x82000800 0 0x00040000 0 0x2000>;
                                reg = <0x0800 0 0 0 0>;
@@ -36,7 +36,7 @@
                                status = "disabled";
                        };
 
-                       pcie@2,0 {
+                       pcie1: pcie@2,0 {
                                device_type = "pci";
                                assigned-addresses = <0x82001000 0 0x00044000 0 0x2000>;
                                reg = <0x1000 0 0 0 0>;
        };
        ocp@f1000000 {
 
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        compatible = "marvell,88f6282-pinctrl";
-                       reg = <0x10000 0x20>;
-
-                       pmx_nand: pmx-nand {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3",
-                                                       "mpp4", "mpp5", "mpp18", "mpp19";
-                               marvell,function = "nand";
-                       };
 
                        pmx_sata0: pmx-sata0 {
                                marvell,pins = "mpp5", "mpp21", "mpp23";
                                marvell,pins = "mpp4", "mpp20", "mpp22";
                                marvell,function = "sata1";
                        };
-                       pmx_spi: pmx-spi {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3";
-                               marvell,function = "spi";
-                       };
-                       pmx_twsi0: pmx-twsi0 {
-                               marvell,pins = "mpp8", "mpp9";
-                               marvell,function = "twsi0";
-                       };
 
+                       /*
+                        * Default I2C1 pinctrl setting on mpp36/mpp37,
+                        * overwrite marvell,pins on board level if required.
+                        */
                        pmx_twsi1: pmx-twsi1 {
                                marvell,pins = "mpp36", "mpp37";
                                marvell,function = "twsi1";
                        };
 
-                       pmx_uart0: pmx-uart0 {
-                               marvell,pins = "mpp10", "mpp11";
-                               marvell,function = "uart0";
-                       };
-
-                       pmx_uart1: pmx-uart1 {
-                               marvell,pins = "mpp13", "mpp14";
-                               marvell,function = "uart1";
-                       };
                        pmx_sdio: pmx-sdio {
                                marvell,pins = "mpp12", "mpp13", "mpp14",
                                               "mpp15", "mpp16", "mpp17";
                        };
                };
 
-               thermal@10078 {
+               thermal: thermal@10078 {
                        compatible = "marvell,kirkwood-thermal";
                        reg = <0x10078 0x4>;
                        status = "okay";
                };
 
-               rtc@10300 {
+               rtc: rtc@10300 {
                        compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc";
                        reg = <0x10300 0x20>;
                        interrupts = <53>;
                        clocks = <&gate_clk 7>;
                };
 
-               i2c@11100 {
+               i2c1: i2c@11100 {
                        compatible = "marvell,mv64xxx-i2c";
                        reg = <0x11100 0x20>;
                        #address-cells = <1>;
                        interrupts = <32>;
                        clock-frequency = <100000>;
                        clocks = <&gate_clk 7>;
+                       pinctrl-0 = <&pmx_twsi1>;
+                       pinctrl-names = "default";
                        status = "disabled";
                };
 
-               sata@80000 {
+               sata: sata@80000 {
                        compatible = "marvell,orion-sata";
                        reg = <0x80000 0x5000>;
                        interrupts = <21>;
                        status = "disabled";
                };
 
-               mvsdio@90000 {
+               sdio: mvsdio@90000 {
                        compatible = "marvell,orion-sdio";
                        reg = <0x90000 0x200>;
                        interrupts = <28>;
index 3271e4c8ea07c61549232e19c5489e62bfe3adf6..2e8e412b9db0ddb655adf70c4933f58216bffa9c 100644 (file)
@@ -1,31 +1,8 @@
 / {
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        compatible = "marvell,98dx4122-pinctrl";
-                       reg = <0x10000 0x20>;
 
-                       pmx_nand: pmx-nand {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3",
-                                              "mpp4", "mpp5", "mpp18",
-                                              "mpp19";
-                               marvell,function = "nand";
-                       };
-                       pmx_spi: pmx-spi {
-                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3";
-                               marvell,function = "spi";
-                       };
-                       pmx_twsi0: pmx-twsi0 {
-                               marvell,pins = "mpp8", "mpp9";
-                               marvell,function = "twsi0";
-                       };
-                       pmx_uart0: pmx-uart0 {
-                               marvell,pins = "mpp10", "mpp11";
-                               marvell,function = "uart0";
-                       };
-                       pmx_uart1: pmx-uart1 {
-                               marvell,pins = "mpp13", "mpp14";
-                               marvell,function = "uart1";
-                       };
                };
        };
 };
index 6becedebaa4e946e9fc080096a771053d06854df..c9247f8672ae14c24487f9b6902187c48e25fcd3 100644 (file)
@@ -30,6 +30,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -44,7 +45,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_button_power: pmx-button-power {
                                marvell,pins = "mpp39";
                                marvell,function = "gpio";
@@ -69,8 +70,6 @@
 
                spi@10600 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
 
                        m25p16@0 {
                                #address-cells = <1>;
                         * UART0_TX = Testpoint 66
                         * See the Excito Wiki for more details.
                         */
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
 
index 3b62aeeaa3a2fe1ff5b01eab47e7c25718b45647..ab6ab4933e6bae498216b00efc433ceaf9c157fa 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_cloudbox_sata0: pmx-cloudbox-sata0 {
                                marvell,pins = "mpp15";
                                marvell,function = "sata0";
@@ -25,9 +26,6 @@
                };
 
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
-                       clock-frequency = <166666667>;
                        status = "okay";
                };
 
@@ -39,8 +37,6 @@
                };
 
                spi@10600 {
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
                        status = "okay";
 
                        flash@0 {
index 02d1225ef99f8364c1d9a03987d73ed357b4c428..812df691ae3d11a82df137ae894aa069ef237d56 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl@10000 {
+               pin-controller@10000 {
                        pmx_sdio_gpios: pmx-sdio-gpios {
                                marvell,pins = "mpp37", "mpp38";
                                marvell,function = "gpio";
                };
 
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
-                       clock-frequency = <200000000>;
-                       status = "ok";
+                       status = "okay";
                };
 
                sata@80000 {
@@ -59,8 +57,6 @@
 };
 
 &nand {
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
        chip-delay = <25>;
        status = "okay";
 
index bf7fe8ab88f4353d0e1688d7fdf8cbd9718e1f7e..d85ef0a91b5019d005dbbd199072aff4e90b14aa 100644 (file)
@@ -13,6 +13,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        gpio-leds {
@@ -51,8 +52,6 @@
                };
 
                serial@12100 {
-                       pinctrl-0 = <&pmx_uart1>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
        };
index cb9978c652f2d1635b762e5aa3ef09097aa0b79e..5e586ed04c58a45d2f6ddb61db84b4e9cd53e457 100644 (file)
@@ -13,6 +13,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        gpio-leds {
index d5aa9564a287ee44589ede975c4d591f43747842..113dcf056dcfb792d4220ec089a9dae748e4a587 100644 (file)
@@ -50,7 +50,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
 
                        pinctrl-0 = <&pmx_power_back_on &pmx_present_sata0
                                     &pmx_present_sata1 &pmx_fan_tacho
 };
 
 &nand {
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
        status = "okay";
        chip-delay = <35>;
 
index f31312ebd0d60b17538dd1b8bd8250ee80bf88ea..849736349511433644dcf749633ff317737efb17 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk root=/dev/sda1 rootdelay=10";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_usb_power_enable: pmx-usb-power-enable {
                                marvell,pins = "mpp29";
                                marvell,function = "gpio";
index 28b3ee369778f945379096fea755796ef6156cef..6467c7924195900f66e91e0ce3bdecc50cf13827 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_led_bluetooth: pmx-led-bluetooth {
                                marvell,pins = "mpp47";
                                marvell,function = "gpio";
@@ -37,8 +38,6 @@
 
                spi@10600 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
 
                        m25p40@0 {
                                #address-cells = <1>;
index 772092c94ca34ab3546ad732ae6f6a06da4f724d..d4bcc1c7f6b31a1897baf620c9ce5634a10c52b8 100644 (file)
@@ -25,6 +25,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-32-35 {
index aabafbe0da4c77f5e2381f93ab8dcc3ddd681dd3..95bf83b91b4acac4aaf659f796d4813c940c42e2 100644 (file)
@@ -25,6 +25,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-32-35 {
index 16ec7fbab5734a3b1e8c2fdc2beb93b73cf85e6c..61f47fbe44d0d6b12354da1641a7c7cc05b5cf22 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-1 {
index cff1b2388765bb86d7e751401d0b4c0890129721..bf4143c6cb8f10991d4abbaae126966f9f9c753c 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-1 {
index 330411993d386547addb426980578259fa7c2476..6d25093a9ac48290eb52a8daae4ded18239ebcc3 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-32-35 {
index 6052eaa37d4f3126d45236bd2e401b142d8ff15a..2f1933efcac1f4020f4c12b1e77a9662f843d0ce 100644 (file)
@@ -26,6 +26,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-32-35 {
index 7f76cd30e84e73257d57f5cd8ca16ba249c70148..99afd462f956ff2030f8e6d639ffb2052a78857a 100644 (file)
@@ -27,6 +27,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-1 {
index 1f83a00f1f74e4ebd4d919c707726ce1cace125d..f5c4213fc67cc8f7195d56f42a5fa1e3c54d9203 100644 (file)
@@ -25,6 +25,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-32-35 {
index 0a573add44a252d8b6a2a7d4bd43d8488f355fd5..e80a962ebba0a54262b9ff31fc61196a0ebb02a4 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-15-18 {
index 1848a6245fd30ab67a67c3833cd493c4fb16304e..cae5af4b88b56152583885707c9ae24751a126ea 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-32-35 {
index a1737b4311c628b5329fac6b4083894841cc00e3..623cd4a37d7171bfe3d262513c98feb48eae0f71 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-1 {
index 0cde914eceaee417b551ccbfccdfc148c19b243b..3348e330f0742f83828480048320a2902c047767 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-15-18 {
index aef0cadc2c781f80855a514297bd8dc0d276064d..a0a1fad8b4de5fae9690a11ad0bc2670a2e0bd81 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-1 {
index eb93294201070aa84cd212b23924e7720ecd9b24..aa60a0b049a7722dcb4b587e2f9cfd5fc56ae3de 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk root=/dev/sda1 rootdelay=10";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_usb_power_enable: pmx-usb-power-enable {
                                marvell,pins = "mpp29";
                                marvell,function = "gpio";
index 2d51fce74a5ad17894d6e9661384f0aacdced2d1..c5a1fc75c7a3b43778e0f8634776a2d6a2150aed 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_led_health_r: pmx-led-health-r {
                                marvell,pins = "mpp46";
                                marvell,function = "gpio";
@@ -36,7 +37,6 @@
                        };
                };
                serial@12000 {
-                       clock-frequency = <200000000>;
                        status = "ok";
                };
 
        status = "okay";
 
        ethphy0: ethernet-phy@0 {
-               compatible = "marvell,88e1121";
+               /* Marvell 88E1121R */
+               compatible = "ethernet-phy-id0141.0cb0",
+                            "ethernet-phy-ieee802.3-c22";
                reg = <0>;
+               phy-connection-type = "rgmii-id";
        };
 
        ethphy1: ethernet-phy@1 {
-               compatible = "marvell,88e1121";
+               /* Marvell 88E1121R */
+               compatible = "ethernet-phy-id0141.0cb0",
+                            "ethernet-phy-ieee802.3-c22";
                reg = <1>;
+               phy-connection-type = "rgmii-id";
        };
 };
 
index a1add3f215e394aaeb006c711c5f2f8ce5fbf58c..bfa5edde179c30d38d55cb80dd462dc6c3ee8084 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_led_os_red: pmx-led-os-red {
                                marvell,pins = "mpp22";
                                marvell,function = "gpio";
 
 &nand {
        status = "okay";
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
 
        partition@0 {
                label = "u-boot";
index 8d8c80e3656d6ebaf36c71dfc0351dbe28efe5b3..38e31d15a62d3fc41d91425beba35a41c44fa7a1 100644 (file)
@@ -14,6 +14,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
                linux,initrd-start = <0x4500040>;
                linux,initrd-end   = <0x4800000>;
        };
@@ -29,7 +30,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_button_reset: pmx-button-reset {
                                marvell,pins = "mpp12";
                                marvell,function = "gpio";
index 59e7a5adeedbcb7791994bc2a506dca5d73c2e05..05291f3990d03561ff50940f42956d5b11019724 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = < &pmx_led_sata_brt_ctrl_1
                                      &pmx_led_sata_brt_ctrl_2
                                      &pmx_led_backup_brt_ctrl_1
index 04a1e44541b34b302a1e86100dd13a169e60c440..61139bf309858cba22f6c678e087fdd7e5cdd32c 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = < &pmx_i2c_gpio_sda &pmx_i2c_gpio_scl >;
                        pinctrl-names = "default";
 
@@ -45,9 +46,7 @@
 };
 
 &nand {
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
-       status = "ok";
+       status = "okay";
        chip-delay = <25>;
 };
 
index 6761ffa2c4ab7eb9e130dbef6a00e4a2faea1714..24425660e973c47edf90087589cf62fcef324208 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        mbus {
 
        ocp@f1000000 {
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
 
                i2c@11000 {
-                       pinctrl-0 = <&pmx_twsi0>;
-                       pinctrl-names = "default";
                        status = "okay";
 
                        eeprom@50 {
@@ -54,7 +51,7 @@
                        };
                };
 
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_usb_power_enable: pmx-usb-power-enable {
                                marvell,pins = "mpp14";
                                marvell,function = "gpio";
 &nand {
        /* Total size : 512MB */
        status = "okay";
-       pinctrl-0 = <&pmx_nand>;
 
        partition@0 {
                label = "u-boot";
index 1656653d339b55cebf1456d189f90b142bb6ec75..53484474df1f4672ee3b1110f87ed86cbadd613a 100644 (file)
@@ -4,10 +4,11 @@
 / {
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_power_hdd: pmx-power-hdd {
                                marvell,pins = "mpp10";
                                marvell,function = "gpo";
index 73722c06750182cd003bb67e264d574616415412..f3a991837515d4b97aec12aa2a21b9ddcefe8a2d 100644 (file)
                 reg = <0x00000000 0x20000000>;
         };
 
-        chosen {
-                bootargs = "console=ttyS0,115200n8 earlyprintk";
-        };
+       chosen {
+               bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
+       };
 
        mbus {
                pcie-controller {
@@ -27,7 +28,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_led_health: pmx-led-health {
                                marvell,pins = "mpp7";
                                marvell,function = "gpo";
 
                 };
 
-                serial@12000 {
-                        status = "ok";
-                        pinctrl-0 = <&pmx_uart0>;
-                        pinctrl-names = "default";
-                };
+               serial@12000 {
+                       status = "okay";
+               };
 
                rtc@10300 {
                        status = "disabled";
 };
 
 &nand {
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
        status = "okay";
 
        partition@0 {
index 32c6fb4a11624c05756e4e2fe24b05c62c799667..8f76d28759a30747d96014bfb8582622d049798b 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
+       mbus {
+               pcie-controller {
+                       status = "okay";
+
+                       pcie@1,0 {
+                               status = "okay";
+                       };
+               };
+        };
+
        ocp@f1000000 {
-               pinctrl@10000 {
+               pin-controller@10000 {
                        pmx_usb_led: pmx-usb-led {
                                marvell,pins = "mpp12";
                                marvell,function = "gpo";
@@ -49,8 +60,6 @@
                };
 
                spi@10600 {
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
                        status = "okay";
 
                        flash@0 {
                };
 
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
-                       clock-frequency = <200000000>;
-                       status = "ok";
-               };
-
-               ehci@50000 {
                        status = "okay";
                };
 
-               pcie-controller {
+               ehci@50000 {
                        status = "okay";
-
-                       pcie@1,0 {
-                               status = "okay";
-                       };
                };
        };
 
index 4838478019ccb94a88f6f4027f7e60125c42a6d9..fd733c63bc27da55aadb88b435fe8f2912aca8ad 100644 (file)
@@ -25,6 +25,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -38,7 +39,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_button_power: pmx-button-power {
                                marvell,pins = "mpp47";
                                marvell,function = "gpio";
                };
 
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
 
index 7c8a0d9d8d1fd02fc7dd6b02c2bb6986a7e04a42..b514d643fb6c5413abd3ad1c50bfeffe9d905a33 100644 (file)
@@ -25,6 +25,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -40,7 +41,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_button_power: pmx-button-power {
                                marvell,pins = "mpp47";
                                marvell,function = "gpio";
                };
 
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
 
index e6e5ec4fe6b9e005b9c37ced8fda18f31bb5fbe0..fe6c0246db1ab4749bf453b7e312dbd6ca5667ae 100644 (file)
@@ -4,10 +4,11 @@
 / {
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_ns2_sata0: pmx-ns2-sata0 {
                                marvell,pins = "mpp21";
                                marvell,function = "sata0";
                };
 
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
 
                spi@10600 {
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
                        status = "okay";
 
                        flash@0 {
@@ -45,8 +42,6 @@
                };
 
                i2c@11000 {
-                       pinctrl-0 = <&pmx_twsi0>;
-                       pinctrl-names = "default";
                        status = "okay";
 
                        eeprom@50 {
index 0a07af9d8e58d0c06938fe0284332f87a650503b..6139df0f376c911f078408761acd5f86df09f53b 100644 (file)
@@ -1,6 +1,6 @@
 /dts-v1/;
 
-#include "kirkwood-nsa310-common.dtsi"
+#include "kirkwood-nsa3x0-common.dtsi"
 
 / {
        compatible = "zyxel,nsa310", "marvell,kirkwood-88f6281", "marvell,kirkwood";
@@ -12,6 +12,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -25,7 +26,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = <&pmx_unknown>;
                        pinctrl-names = "default";
 
                                marvell,function = "gpio";
                        };
 
-                       pmx_btn_reset: pmx-btn-reset {
-                               marvell,pins = "mpp36";
-                               marvell,function = "gpio";
-                       };
-
-                       pmx_btn_copy: pmx-btn-copy {
-                               marvell,pins = "mpp37";
-                               marvell,function = "gpio";
-                       };
-
-                       pmx_led_copy_green: pmx-led-copy-green {
-                               marvell,pins = "mpp39";
-                               marvell,function = "gpio";
-                       };
-
-                       pmx_led_copy_red: pmx-led-copy-red {
-                               marvell,pins = "mpp40";
-                               marvell,function = "gpio";
-                       };
-
                        pmx_led_hdd_green: pmx-led-hdd-green {
                                marvell,pins = "mpp41";
                                marvell,function = "gpio";
                                marvell,function = "gpio";
                        };
 
-                       pmx_btn_power: pmx-btn-power {
-                               marvell,pins = "mpp46";
-                               marvell,function = "gpio";
-                       };
                };
 
                i2c@11000 {
                };
        };
 
-       gpio_keys {
-               compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               pinctrl-0 = <&pmx_btn_reset &pmx_btn_copy &pmx_btn_power>;
-               pinctrl-names = "default";
-
-               button@1 {
-                       label = "Power Button";
-                       linux,code = <KEY_POWER>;
-                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
-               };
-               button@2 {
-                       label = "Copy Button";
-                       linux,code = <KEY_COPY>;
-                       gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
-               };
-               button@3 {
-                       label = "Reset Button";
-                       linux,code = <KEY_RESTART>;
-                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-               };
-       };
-
        gpio-leds {
                compatible = "gpio-leds";
                pinctrl-0 = <&pmx_led_esata_green &pmx_led_esata_red
index 27ca6a79c48a473f15d082287e19a605ef98b651..3d2b3d494c1913eafb7e43c3034cac912f1f5591 100644 (file)
@@ -1,6 +1,6 @@
 /dts-v1/;
 
-#include "kirkwood-nsa310-common.dtsi"
+#include "kirkwood-nsa3x0-common.dtsi"
 
 /*
  * There are at least two different NSA310 designs. This variant does
 
        chosen {
                bootargs = "console=ttyS0,115200";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-names = "default";
 
                        pmx_led_esata_green: pmx-led-esata-green {
                                marvell,function = "gpio";
                        };
 
-                       pmx_usb_power_off: pmx-usb-power-off {
-                               marvell,pins = "mpp21";
-                               marvell,function = "gpio";
-                       };
-
                        pmx_led_sys_green: pmx-led-sys-green {
                                marvell,pins = "mpp28";
                                marvell,function = "gpio";
                                marvell,function = "gpio";
                        };
 
-                       pmx_btn_reset: pmx-btn-reset {
-                               marvell,pins = "mpp36";
-                               marvell,function = "gpio";
-                       };
-
-                       pmx_btn_copy: pmx-btn-copy {
-                               marvell,pins = "mpp37";
-                               marvell,function = "gpio";
-                       };
-
-                       pmx_led_copy_green: pmx-led-copy-green {
-                               marvell,pins = "mpp39";
-                               marvell,function = "gpio";
-                       };
-
-                       pmx_led_copy_red: pmx-led-copy-red {
-                               marvell,pins = "mpp40";
-                               marvell,function = "gpio";
-                       };
-
                        pmx_led_hdd_green: pmx-led-hdd-green {
                                marvell,pins = "mpp41";
                                marvell,function = "gpio";
                                marvell,function = "gpio";
                        };
 
-                       pmx_btn_power: pmx-btn-power {
-                               marvell,pins = "mpp46";
-                               marvell,function = "gpio";
-                       };
-
                };
 
                i2c@11000 {
                };
        };
 
-       gpio_keys {
-               compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               button@1 {
-                       label = "Power Button";
-                       linux,code = <KEY_POWER>;
-                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
-               };
-               button@2 {
-                       label = "Copy Button";
-                       linux,code = <KEY_COPY>;
-                       gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
-               };
-               button@3 {
-                       label = "Reset Button";
-                       linux,code = <KEY_RESTART>;
-                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-               };
-       };
-
        gpio-leds {
                compatible = "gpio-leds";
 
diff --git a/arch/arm/boot/dts/kirkwood-nsa320.dts b/arch/arm/boot/dts/kirkwood-nsa320.dts
new file mode 100644 (file)
index 0000000..24f686d
--- /dev/null
@@ -0,0 +1,215 @@
+/* Device tree file for the Zyxel NSA 320 NAS box.
+ *
+ * Copyright (c) 2014, Adam Baker <linux@baker-net.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based upon the board setup file created by Peter Schildmann */
+
+/dts-v1/;
+
+#include "kirkwood-nsa3x0-common.dtsi"
+
+/ {
+       model = "Zyxel NSA320";
+       compatible = "zyxel,nsa320", "marvell,kirkwood-88f6281", "marvell,kirkwood";
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x20000000>;
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200";
+               stdout-path = &uart0;
+       };
+
+       mbus {
+               pcie-controller {
+                       status = "okay";
+
+                       pcie@1,0 {
+                               status = "okay";
+                       };
+               };
+       };
+
+       ocp@f1000000 {
+               pinctrl: pin-controller@10000 {
+                       pinctrl-names = "default";
+
+                       /* SATA Activity and Present pins are not connected */
+                       pmx_sata0: pmx-sata0 {
+                               marvell,pins ;
+                               marvell,function = "sata0";
+                       };
+
+                       pmx_sata1: pmx-sata1 {
+                               marvell,pins ;
+                               marvell,function = "sata1";
+                       };
+
+                       pmx_led_hdd2_green: pmx-led-hdd2-green {
+                               marvell,pins = "mpp12";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_hdd2_red: pmx-led-hdd2-red {
+                               marvell,pins = "mpp13";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_mcu_data: pmx-mcu-data {
+                               marvell,pins = "mpp14";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_usb_green: pmx-led-usb-green {
+                               marvell,pins = "mpp15";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_mcu_clk: pmx-mcu-clk {
+                               marvell,pins = "mpp16";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_mcu_act: pmx-mcu-act {
+                               marvell,pins = "mpp17";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_sys_green: pmx-led-sys-green {
+                               marvell,pins = "mpp28";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_sys_orange: pmx-led-sys-orange {
+                               marvell,pins = "mpp29";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_hdd1_green: pmx-led-hdd1-green {
+                               marvell,pins = "mpp41";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_hdd1_red: pmx-led-hdd1-red {
+                               marvell,pins = "mpp42";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_htp: pmx-htp {
+                               marvell,pins = "mpp43";
+                               marvell,function = "gpio";
+                       };
+
+                       /* Buzzer needs to be switched at around 1kHz so is
+                          not compatible with the gpio-beeper driver. */
+                       pmx_buzzer: pmx-buzzer {
+                               marvell,pins = "mpp44";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_vid_b1: pmx-vid-b1 {
+                               marvell,pins = "mpp45";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_power_resume_data: pmx-power-resume-data {
+                               marvell,pins = "mpp47";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_power_resume_clk: pmx-power-resume-clk {
+                               marvell,pins = "mpp49";
+                               marvell,function = "gpio";
+                       };
+               };
+
+               i2c@11000 {
+                       status = "okay";
+
+                       pcf8563: pcf8563@51 {
+                               compatible = "nxp,pcf8563";
+                               reg = <0x51>;
+                       };
+               };
+       };
+
+       regulators {
+               usb0_power: regulator@1 {
+                       enable-active-high;
+               };
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-0 = <&pmx_led_hdd2_green &pmx_led_hdd2_red
+                            &pmx_led_usb_green
+                            &pmx_led_sys_green &pmx_led_sys_orange
+                            &pmx_led_copy_green &pmx_led_copy_red
+                            &pmx_led_hdd1_green &pmx_led_hdd1_red>;
+               pinctrl-names = "default";
+
+               green-sys {
+                       label = "nsa320:green:sys";
+                       gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
+               };
+               orange-sys {
+                       label = "nsa320:orange:sys";
+                       gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
+               };
+               green-hdd1 {
+                       label = "nsa320:green:hdd1";
+                       gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+               };
+               red-hdd1 {
+                       label = "nsa320:red:hdd1";
+                       gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+               };
+               green-hdd2 {
+                       label = "nsa320:green:hdd2";
+                       gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+               };
+               red-hdd2 {
+                       label = "nsa320:red:hdd2";
+                       gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
+               };
+               green-usb {
+                       label = "nsa320:green:usb";
+                       gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
+               };
+               green-copy {
+                       label = "nsa320:green:copy";
+                       gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+               };
+               red-copy {
+                       label = "nsa320:red:copy";
+                       gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       /* The following pins are currently not assigned to a driver,
+          some of them should be configured as inputs.
+       pinctrl-0 = <&pmx_mcu_data &pmx_mcu_clk &pmx_mcu_act
+                    &pmx_htp &pmx_vid_b1
+                    &pmx_power_resume_data &pmx_power_resume_clk>; */
+};
+
+&mdio {
+       status = "okay";
+       ethphy0: ethernet-phy@1 {
+               reg = <1>;
+       };
+};
+
+&eth0 {
+       status = "okay";
+       ethernet0-port@0 {
+               phy-handle = <&ethphy0>;
+       };
+};
similarity index 58%
rename from arch/arm/boot/dts/kirkwood-nsa310-common.dtsi
rename to arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi
index aa78c2d11fe738fc843f716bd1a6f98ff1054a5b..2075a2e828f17b6623c71855da85573807fd33f5 100644 (file)
@@ -4,18 +4,53 @@
 / {
        model = "ZyXEL NSA310";
 
+       mbus {
+               pcie-controller {
+                       status = "okay";
+
+                       pcie@1,0 {
+                               status = "okay";
+                       };
+               };
+       };
+
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
 
-                       pmx_usb_power_off: pmx-usb-power-off {
+                       pmx_usb_power: pmx-usb-power {
                                marvell,pins = "mpp21";
                                marvell,function = "gpio";
                        };
+
                        pmx_pwr_off: pmx-pwr-off {
                                marvell,pins = "mpp48";
                                marvell,function = "gpio";
                        };
 
+                       pmx_btn_reset: pmx-btn-reset {
+                               marvell,pins = "mpp36";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_btn_copy: pmx-btn-copy {
+                               marvell,pins = "mpp37";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_btn_power: pmx-btn-power {
+                               marvell,pins = "mpp46";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_copy_green: pmx-led-copy-green {
+                               marvell,pins = "mpp39";
+                               marvell,function = "gpio";
+                       };
+
+                       pmx_led_copy_red: pmx-led-copy-red {
+                               marvell,pins = "mpp40";
+                               marvell,function = "gpio";
+                       };
                };
 
                serial@12000 {
                        status = "okay";
                        nr-ports = <2>;
                };
-
-               pcie-controller {
-                       status = "okay";
-
-                       pcie@1,0 {
-                               status = "okay";
-                       };
-               };
        };
 
        gpio_poweroff {
                gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
        };
 
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               pinctrl-0 = <&pmx_btn_reset &pmx_btn_copy &pmx_btn_power>;
+               pinctrl-names = "default";
+
+               button@1 {
+                       label = "Power Button";
+                       linux,code = <KEY_POWER>;
+                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+               };
+               button@2 {
+                       label = "Copy Button";
+                       linux,code = <KEY_COPY>;
+                       gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
+               };
+               button@3 {
+                       label = "Reset Button";
+                       linux,code = <KEY_RESTART>;
+                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+
        regulators {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-0 = <&pmx_usb_power_off>;
+               pinctrl-0 = <&pmx_usb_power>;
                pinctrl-names = "default";
 
-               usb0_power_off: regulator@1 {
+               usb0_power: regulator@1 {
                        compatible = "regulator-fixed";
                        reg = <1>;
-                       regulator-name = "USB Power Off";
+                       regulator-name = "USB Power";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
                        regulator-always-on;
index 0650beafc1de0ac4a7e60fbc759ed7726982c22a..fb9dc227255d91a2a4bdb58a7adfac3072a80521 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
                serial@12000 {
-                       status = "ok";
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
+                       status = "okay";
                };
 
                serial@12100 {
-                       status = "ok";
-                       pinctrl-0 = <&pmx_uart1>;
-                       pinctrl-names = "default";
+                       status = "okay";
                };
 
                sata@80000 {
@@ -36,8 +33,6 @@
 
                i2c@11100 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_twsi1>;
-                       pinctrl-names = "default";
 
                        s35390a: s35390a@30 {
                                compatible = "sii,s35390a";
@@ -45,7 +40,7 @@
                        };
                };
 
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>;
                        pinctrl-names = "default";
 
 &nand {
        chip-delay = <25>;
        status = "okay";
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
 
        partition@0 {
                label = "uboot";
index 38520a2875146d565c8016f69cc4f324098ff1ee..d5e3bc518968b4acf5e4b811d2944a84d12b79b8 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
                serial@12000 {
-                       status = "ok";
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
+                       status = "okay";
                };
 
                serial@12100 {
-                       status = "ok";
-                       pinctrl-0 = <&pmx_uart1>;
-                       pinctrl-names = "default";
+                       status = "okay";
                };
 
                sata@80000 {
@@ -48,8 +45,6 @@
 
                i2c@11100 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_twsi1>;
-                       pinctrl-names = "default";
 
                        s24c02: s24c02@50 {
                                compatible = "atmel,24c02";
@@ -57,7 +52,7 @@
                        };
                };
 
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>;
                        pinctrl-names = "default";
 
                                marvell,pins = "mpp41", "mpp42", "mpp43";
                                marvell,function = "gpio";
                        };
-
-                       pmx_ge1: pmx-ge1 {
-                               marvell,pins = "mpp20", "mpp21", "mpp22", "mpp23",
-                                              "mpp24", "mpp25", "mpp26", "mpp27",
-                                              "mpp30", "mpp31", "mpp32", "mpp33";
-                               marvell,function = "ge1";
-                       };
                };
        };
 
 &nand {
        chip-delay = <25>;
        status = "okay";
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
 
        partition@0 {
                label = "uboot";
 
 &eth1 {
        status = "okay";
-       pinctrl-0 = <&pmx_ge1>;
-       pinctrl-names = "default";
        ethernet1-port@0 {
                phy-handle = <&ethphy1>;
        };
index e9dd850492976ca557d4545f8a18150751afed35..35a29dee8dd864f818c5cacd437a936eb2de0024 100644 (file)
@@ -26,6 +26,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -39,7 +40,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = <&pmx_usb_power>;
                        pinctrl-names = "default";
 
@@ -56,8 +57,6 @@
 
                spi@10600 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
 
                        m25p128@0 {
                                #address-cells = <1>;
index d6368c39102e743ef74465f94a032ef8d94f7e70..26cf0e0ccefd3772f6e194b8102ea751408d3f6f 100644 (file)
@@ -22,6 +22,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -35,7 +36,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = <&pmx_sdio_cd>;
                        pinctrl-names = "default";
 
index 93ec3d00c6ab90b17ee11bac2fe6bb4cea23312e..3b19f1fd4caca99e687474b92a3a0729a13a1537 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-3 {
index 311df4e5aa285e799d63fd06a10c45da1e24f309..921ca49e85a4dadf4cce6dc726e678c3044ef79b 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-150-15-18 {
index f90da850bb31bca5f28c20e9f47c8132fd28bceb..02852b0c809f00020c01a7252b3dcc84254ae4ba 100644 (file)
@@ -24,6 +24,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        gpio-fan-100-15-35-3 {
index 1ff848d570a9a02921122140fd78f02d8759fd86..7196c7f3e1096fc4c42beb74db5ec2160e447ef2 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
 
                        pmx_usb_power_enable: pmx-usb-power-enable {
                                marvell,pins = "mpp29";
@@ -44,8 +45,6 @@
                        };
                };
                serial@12000 {
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                        status = "okay";
                };
        };
@@ -72,8 +71,6 @@
 };
 
 &nand {
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
        status = "okay";
 
        partition@0 {
index 4227c974729d003b211f14658ba44e19e70cea6e..811e0971fc588a2cc9f59ddbd8f64d51e38acb14 100644 (file)
@@ -25,7 +25,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pmx_alarmled_12: pmx-alarmled-12 {
                                marvell,pins = "mpp12";
                                marvell,function = "gpio";
 
                spi@10600 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
 
                        m25p80@0 {
                                #address-cells = <1>;
                i2c@11000 {
                        status = "okay";
                        clock-frequency = <400000>;
-                       pinctrl-0 = <&pmx_twsi0>;
-                       pinctrl-names = "default";
 
                        rs5c372: rs5c372@32 {
                                status = "disabled";
 
                serial@12000 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                };
 
                serial@12100 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_uart1>;
-                       pinctrl-names = "default";
                };
 
                poweroff@12100 {
index 7d1c7677a18f18c3fb1cc00463420545a5b6cb78..610ec0f95858b4691f7c275d8a0d794a27d8863b 100644 (file)
@@ -27,6 +27,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -40,7 +41,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-0 = <&pmx_i2s &pmx_sysrst>;
                        pinctrl-names = "default";
 
                                marvell,function = "gpio";
                        };
 
-                       /*
-                        * Redefined from kirkwood-6281.dtsi, because
-                        * we don't use SPI CS on MPP0, but on MPP7.
-                        */
                        pmx_spi: pmx-spi {
                                marvell,pins = "mpp1", "mpp2", "mpp3", "mpp7";
                                marvell,function = "spi";
@@ -86,8 +83,6 @@
                };
 
                spi@10600 {
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
                        status = "okay";
 
                        flash@0 {
                        alc5621: alc5621@1a {
                                compatible = "realtek,alc5621";
                                reg = <0x1a>;
+                               #sound-dai-cells = <0>;
+                               add-ctrl = <0x3700>;
+                               jack-det-ctrl = <0x4810>;
                        };
                };
 
                gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
        };
 
+       sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,routing =
+                       "Headphone Jack", "HPL",
+                       "Headphone Jack", "HPR",
+                       "Speaker", "SPKOUT",
+                       "Speaker", "SPKOUTN",
+                       "MIC1", "Mic Jack",
+                       "MIC2", "Mic Jack";
+               simple-audio-card,widgets =
+                       "Headphone", "Headphone Jack",
+                       "Speaker", "Speaker",
+                       "Microphone", "Mic Jack";
+
+               simple-audio-card,mclk-fs = <256>;
+
+               simple-audio-card,cpu {
+                       sound-dai = <&audio>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&alc5621>;
+               };
+       };
 };
 
 &mdio {
index 5fc817c2cb87379dd3fbe9513dded60ae00c92e8..f5c8c0dd41dc82f7e7671f7713182186b250ec8e 100644 (file)
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               stdout-path = &uart0;
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        /*
                         * Switch positions
                         *
@@ -85,9 +86,7 @@
                };
 
                serial@12000 {
-                       status = "ok";
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
+                       status = "okay";
                };
 
                sata@80000 {
@@ -96,9 +95,7 @@
                };
 
                i2c@11000 {
-                       status = "ok";
-                       pinctrl-0 = <&pmx_twsi0>;
-                       pinctrl-names = "default";
+                       status = "okay";
                };
 
                mvsdio@90000 {
 
 &nand {
        status = "okay";
-       pinctrl-0 = <&pmx_nand>;
-       pinctrl-names = "default";
 
        partition@0 {
                label = "u-boot";
index c17ae45e19be3ffc33f500e172e3a6e04c439b10..9767d73f3857f972798f22047e93391290034581 100644 (file)
@@ -6,7 +6,7 @@
 
 / {
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
 
                        pinctrl-0 = <&pmx_ram_size &pmx_board_id>;
                        pinctrl-names = "default";
index 0713d072758a1e22a30b86bf3921cdc806cf6b61..bfc1a32d4e422d5ca25dc8e1def9d0f0f0209fce 100644 (file)
@@ -16,7 +16,7 @@
        };
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
 
                        pinctrl-0 = <&pmx_ram_size &pmx_board_id>;
                        pinctrl-names = "default";
index 911f3a8cee23ec0d5d28f07451338147eeb01893..df7f15276575ada26c356e224bb223c63e0b42f8 100644 (file)
@@ -9,6 +9,7 @@
 
        chosen {
                bootargs = "console=ttyS0,115200n8";
+               stdout-path = &uart0;
        };
 
        mbus {
@@ -25,8 +26,6 @@
                i2c@11000 {
                        status = "okay";
                        clock-frequency = <400000>;
-                       pinctrl-0 = <&pmx_twsi0>;
-                       pinctrl-names = "default";
 
                        s35390a: s35390a@30 {
                                compatible = "s35390a";
                        };
                };
                serial@12000 {
-                       clock-frequency = <200000000>;
                        status = "okay";
-                       pinctrl-0 = <&pmx_uart0>;
-                       pinctrl-names = "default";
                };
                serial@12100 {
-                       clock-frequency = <200000000>;
                        status = "okay";
-                       pinctrl-0 = <&pmx_uart1>;
-                       pinctrl-names = "default";
                };
                poweroff@12100 {
                        compatible = "qnap,power-off";
@@ -52,8 +45,6 @@
                };
                spi@10600 {
                        status = "okay";
-                       pinctrl-0 = <&pmx_spi>;
-                       pinctrl-names = "default";
 
                        m25p128@0 {
                                #address-cells = <1>;
index 1a9c624c7a928f9c67bd72e1bb372e61d4a911b0..30ab93bfb1e476d0722bdc17e1eb6b5ca43f353b 100644 (file)
@@ -14,7 +14,7 @@
        compatible = "qnap,ts419", "marvell,kirkwood";
 
        ocp@f1000000 {
-               pinctrl: pinctrl@10000 {
+               pinctrl: pin-controller@10000 {
                        pinctrl-names = "default";
 
                        pmx_USB_copy_button: pmx-USB-copy-button {
index 90384587c27843c563d2c4328ce9411f4c26458b..afc640cd80c5f6c6cf561550e3fb9133beb3d523 100644 (file)
@@ -40,7 +40,7 @@
                pcie-mem-aperture = <0xe0000000 0x10000000>; /* 256 MiB memory space */
                pcie-io-aperture  = <0xf2000000 0x100000>;   /*   1 MiB    I/O space */
 
-               crypto@0301 {
+               cesa: crypto@0301 {
                        compatible = "marvell,orion-crypto";
                        reg = <MBUS_ID(0xf0, 0x01) 0x30000 0x10000>,
                              <MBUS_ID(0x03, 0x01) 0 0x800>;
@@ -61,6 +61,8 @@
                        chip-delay = <25>;
                        /* set partition map and/or chip-delay in board dts */
                        clocks = <&gate_clk 7>;
+                       pinctrl-0 = <&pmx_nand>;
+                       pinctrl-names = "default";
                        status = "disabled";
                };
        };
                #address-cells = <1>;
                #size-cells = <1>;
 
+               pinctrl: pin-controller@10000 {
+                       /* set compatible property in SoC file */
+                       reg = <0x10000 0x20>;
+
+                       pmx_ge1: pmx-ge1 {
+                               marvell,pins = "mpp20", "mpp21", "mpp22", "mpp23",
+                                              "mpp24", "mpp25", "mpp26", "mpp27",
+                                              "mpp30", "mpp31", "mpp32", "mpp33";
+                               marvell,function = "ge1";
+                       };
+
+                       pmx_nand: pmx-nand {
+                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3",
+                                              "mpp4", "mpp5", "mpp18", "mpp19";
+                               marvell,function = "nand";
+                       };
+
+                       /*
+                        * Default SPI0 pinctrl setting with CSn on mpp0,
+                        * overwrite marvell,pins on board level if required.
+                        */
+                       pmx_spi: pmx-spi {
+                               marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3";
+                               marvell,function = "spi";
+                       };
+
+                       pmx_twsi0: pmx-twsi0 {
+                               marvell,pins = "mpp8", "mpp9";
+                               marvell,function = "twsi0";
+                       };
+
+                       /*
+                        * Default UART pinctrl setting without RTS/CTS,
+                        * overwrite marvell,pins on board level if required.
+                        */
+                       pmx_uart0: pmx-uart0 {
+                               marvell,pins = "mpp10", "mpp11";
+                               marvell,function = "uart0";
+                       };
+
+                       pmx_uart1: pmx-uart1 {
+                               marvell,pins = "mpp13", "mpp14";
+                               marvell,function = "uart1";
+                       };
+               };
+
                core_clk: core-clocks@10030 {
                        compatible = "marvell,kirkwood-core-clock";
                        reg = <0x10030 0x4>;
                        #clock-cells = <1>;
                };
 
-               spi@10600 {
+               spi0: spi@10600 {
                        compatible = "marvell,orion-spi";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        interrupts = <23>;
                        reg = <0x10600 0x28>;
                        clocks = <&gate_clk 7>;
+                       pinctrl-0 = <&pmx_spi>;
+                       pinctrl-names = "default";
                        status = "disabled";
                };
 
                        interrupts = <29>;
                        clock-frequency = <100000>;
                        clocks = <&gate_clk 7>;
+                       pinctrl-0 = <&pmx_twsi0>;
+                       pinctrl-names = "default";
                        status = "disabled";
                };
 
-               serial@12000 {
+               uart0: serial@12000 {
                        compatible = "ns16550a";
                        reg = <0x12000 0x100>;
                        reg-shift = <2>;
                        interrupts = <33>;
                        clocks = <&gate_clk 7>;
+                       pinctrl-0 = <&pmx_uart0>;
+                       pinctrl-names = "default";
                        status = "disabled";
                };
 
-               serial@12100 {
+               uart1: serial@12100 {
                        compatible = "ns16550a";
                        reg = <0x12100 0x100>;
                        reg-shift = <2>;
                        interrupts = <34>;
                        clocks = <&gate_clk 7>;
+                       pinctrl-0 = <&pmx_uart1>;
+                       pinctrl-names = "default";
                        status = "disabled";
                };
 
                        reg = <0x20000 0x80>, <0x1500 0x20>;
                };
 
-               system-controller@20000 {
+               sysc: system-controller@20000 {
                        compatible = "marvell,orion-system-controller";
                        reg = <0x20000 0x120>;
                };
                        status = "okay";
                };
 
-               ehci@50000 {
+               usb0: ehci@50000 {
                        compatible = "marvell,orion-ehci";
                        reg = <0x50000 0x1000>;
                        interrupts = <19>;
                        status = "okay";
                };
 
-               xor@60800 {
+               dma0: xor@60800 {
                        compatible = "marvell,orion-xor";
                        reg = <0x60800 0x100
                               0x60A00 0x100>;
                        };
                };
 
-               xor@60900 {
+               dma1: xor@60900 {
                        compatible = "marvell,orion-xor";
                        reg = <0x60900 0x100
                               0x60B00 0x100>;
                        reg = <0x76000 0x4000>;
                        clocks = <&gate_clk 19>;
                        marvell,tx-checksum-limit = <1600>;
+                       pinctrl-0 = <&pmx_ge1>;
+                       pinctrl-names = "default";
                        status = "disabled";
 
                        ethernet1-port@0 {
 
                audio0: audio-controller@a0000 {
                        compatible = "marvell,kirkwood-audio";
+                       #sound-dai-cells = <0>;
                        reg = <0xa0000 0x2210>;
                        interrupts = <24>;
                        clocks = <&gate_clk 9>;
index f577b7df9a29e4f5f4e74ca86aef4b4ba61ceb87..521c587acaee9f679ab6f9200c5f8be8eee240e9 100644 (file)
                compatible = "smsc,lan9221", "smsc,lan9115";
                bank-width = <2>;
                gpmc,mux-add-data;
-               gpmc,cs-on-ns = <0>;
-               gpmc,cs-rd-off-ns = <186>;
-               gpmc,cs-wr-off-ns = <186>;
-               gpmc,adv-on-ns = <12>;
-               gpmc,adv-rd-off-ns = <48>;
+               gpmc,cs-on-ns = <1>;
+               gpmc,cs-rd-off-ns = <180>;
+               gpmc,cs-wr-off-ns = <180>;
+               gpmc,adv-rd-off-ns = <18>;
                gpmc,adv-wr-off-ns = <48>;
                gpmc,oe-on-ns = <54>;
                gpmc,oe-off-ns = <168>;
                gpmc,we-off-ns = <168>;
                gpmc,rd-cycle-ns = <186>;
                gpmc,wr-cycle-ns = <186>;
-               gpmc,access-ns = <114>;
-               gpmc,page-burst-access-ns = <6>;
-               gpmc,bus-turnaround-ns = <12>;
-               gpmc,cycle2cycle-delay-ns = <18>;
-               gpmc,wr-data-mux-bus-ns = <90>;
-               gpmc,wr-access-ns = <186>;
+               gpmc,access-ns = <144>;
+               gpmc,page-burst-access-ns = <24>;
+               gpmc,bus-turnaround-ns = <90>;
+               gpmc,cycle2cycle-delay-ns = <90>;
                gpmc,cycle2cycle-samecsen;
                gpmc,cycle2cycle-diffcsen;
                vddvario-supply = <&vddvario>;
index 22f35ea142c199082afdd8ba626bd7c5e0b6cd54..8f8c07da4ac148d550ae45cd3501d4a992f4e7c8 100644 (file)
                        interrupts = <58>;
                };
 
-               mailbox: mailbox@48094000 {
-                       compatible = "ti,omap2-mailbox";
-                       ti,hwmods = "mailbox";
-                       reg = <0x48094000 0x200>;
-                       interrupts = <26>;
-               };
-
                intc: interrupt-controller@1 {
                        compatible = "ti,omap2-intc";
                        interrupt-controller;
index 85b1fb014c4314efe82eca9fcb7dfa7e482cb8d2..2d9979835f241f2153cd3d0b52c5c8b0b6c49559 100644 (file)
                        dma-names = "tx", "rx";
                };
 
+               mailbox: mailbox@48094000 {
+                       compatible = "ti,omap2-mailbox";
+                       reg = <0x48094000 0x200>;
+                       interrupts = <26>, <34>;
+                       interrupt-names = "dsp", "iva";
+                       ti,hwmods = "mailbox";
+               };
+
                timer1: timer@48028000 {
                        compatible = "ti,omap2420-timer";
                        reg = <0x48028000 0x400>;
index d09697dab55e80063a737361c65138822bbdf828..42d2c61c9e2d7dc1851054a45ec305820cc8a9f4 100644 (file)
                        dma-names = "tx", "rx";
                };
 
+               mailbox: mailbox@48094000 {
+                       compatible = "ti,omap2-mailbox";
+                       reg = <0x48094000 0x200>;
+                       interrupts = <26>;
+                       ti,hwmods = "mailbox";
+               };
+
                timer1: timer@49018000 {
                        compatible = "ti,omap2420-timer";
                        reg = <0x49018000 0x400>;
index d00055809e31d79b9d1730c06efe02c7e2e6f747..25ba08331d8852e6701c96a4b9e8e54def19f0d8 100644 (file)
                        cpu0-supply = <&vcc>;
                };
        };
-
-       vddvario: regulator-vddvario {
-               compatible = "regulator-fixed";
-               regulator-name = "vddvario";
-               regulator-always-on;
-       };
-
-       vdd33a: regulator-vdd33a {
-               compatible = "regulator-fixed";
-               regulator-name = "vdd33a";
-               regulator-always-on;
-       };
 };
 
 &omap3_pmx_core {
 
        hsusb0_pins: pinmux_hsusb0_pins {
                pinctrl-single,pins = <
-                       OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0)               /* hsusb0_clk.hsusb0_clk */
-                       OMAP3_CORE1_IOPAD(0x21a2, PIN_OUTPUT | MUX_MODE0)               /* hsusb0_stp.hsusb0_stp */
-                       OMAP3_CORE1_IOPAD(0x21a4, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_dir.hsusb0_dir */
-                       OMAP3_CORE1_IOPAD(0x21a6, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_nxt.hsusb0_nxt */
-                       OMAP3_CORE1_IOPAD(0x21a8, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data0.hsusb2_data0 */
-                       OMAP3_CORE1_IOPAD(0x21aa, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data1.hsusb0_data1 */
-                       OMAP3_CORE1_IOPAD(0x21ac, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data2.hsusb0_data2 */
-                       OMAP3_CORE1_IOPAD(0x21ae, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data3 */
-                       OMAP3_CORE1_IOPAD(0x21b0, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data4 */
-                       OMAP3_CORE1_IOPAD(0x21b2, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data5 */
-                       OMAP3_CORE1_IOPAD(0x21b4, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data6 */
-                       OMAP3_CORE1_IOPAD(0x21b6, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data7 */
+                       OMAP3_CORE1_IOPAD(0x21a2, PIN_OUTPUT | MUX_MODE0)               /* hsusb0_clk.hsusb0_clk */
+                       OMAP3_CORE1_IOPAD(0x21a4, PIN_OUTPUT | MUX_MODE0)               /* hsusb0_stp.hsusb0_stp */
+                       OMAP3_CORE1_IOPAD(0x21a6, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_dir.hsusb0_dir */
+                       OMAP3_CORE1_IOPAD(0x21a8, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_nxt.hsusb0_nxt */
+                       OMAP3_CORE1_IOPAD(0x21aa, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data0.hsusb2_data0 */
+                       OMAP3_CORE1_IOPAD(0x21ac, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data1.hsusb0_data1 */
+                       OMAP3_CORE1_IOPAD(0x21ae, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data2.hsusb0_data2 */
+                       OMAP3_CORE1_IOPAD(0x21b0, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data3 */
+                       OMAP3_CORE1_IOPAD(0x21b2, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data4 */
+                       OMAP3_CORE1_IOPAD(0x21b4, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data5 */
+                       OMAP3_CORE1_IOPAD(0x21b6, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data6 */
+                       OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT_PULLDOWN | MUX_MODE0)       /* hsusb0_data7.hsusb0_data7 */
                >;
        };
 };
 
+#include "omap-gpmc-smsc911x.dtsi"
+
 &gpmc {
        ranges = <5 0 0x2c000000 0x01000000>;
 
-       smsc1: ethernet@5,0 {
+       smsc1: ethernet@gpmc {
                compatible = "smsc,lan9221", "smsc,lan9115";
                pinctrl-names = "default";
                pinctrl-0 = <&smsc1_pins>;
                interrupt-parent = <&gpio6>;
                interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
                reg = <5 0 0xff>;
-               bank-width = <2>;
-               gpmc,mux-add-data;
-               gpmc,cs-on-ns = <0>;
-               gpmc,cs-rd-off-ns = <186>;
-               gpmc,cs-wr-off-ns = <186>;
-               gpmc,adv-on-ns = <12>;
-               gpmc,adv-rd-off-ns = <48>;
-               gpmc,adv-wr-off-ns = <48>;
-               gpmc,oe-on-ns = <54>;
-               gpmc,oe-off-ns = <168>;
-               gpmc,we-on-ns = <54>;
-               gpmc,we-off-ns = <168>;
-               gpmc,rd-cycle-ns = <186>;
-               gpmc,wr-cycle-ns = <186>;
-               gpmc,access-ns = <114>;
-               gpmc,page-burst-access-ns = <6>;
-               gpmc,bus-turnaround-ns = <12>;
-               gpmc,cycle2cycle-delay-ns = <18>;
-               gpmc,wr-data-mux-bus-ns = <90>;
-               gpmc,wr-access-ns = <186>;
-               gpmc,cycle2cycle-samecsen;
-               gpmc,cycle2cycle-diffcsen;
-               vddvario-supply = <&vddvario>;
-               vdd33a-supply = <&vdd33a>;
-               reg-io-width = <4>;
-               smsc,save-mac-address;
        };
 };
 
index b97736d98a6427f087c11bd510909b1007f8c152..e2d163bf061975bff9ac5a6e83ecf6bf4ef98ed3 100644 (file)
                >;
        };
 
-       smsc911x_pins: pinmux_smsc911x_pins {
+       smsc9221_pins: pinmux_smsc9221_pins {
                pinctrl-single,pins = <
                        0x1a2 (PIN_INPUT | MUX_MODE4)           /* mcspi1_cs2.gpio_176 */
                >;
index 7abd64f6ae21465c9ac74b22563f8f828a5d684b..b22caaaf774ba710461fcabf395c121c0ccc0482 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "omap3-igep.dtsi"
-#include "omap-gpmc-smsc911x.dtsi"
+#include "omap-gpmc-smsc9221.dtsi"
 
 / {
        model = "IGEPv2 (TI OMAP AM/DM37x)";
 
        ethernet@gpmc {
                pinctrl-names = "default";
-               pinctrl-0 = <&smsc911x_pins>;
+               pinctrl-0 = <&smsc9221_pins>;
                reg = <5 0 0xff>;
                interrupt-parent = <&gpio6>;
                interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
index 7909c51b05a5643563b4ed74405066e1a222a995..d59e3de1441e2f7dc5e0fb9b4bc29f49ee04cbc1 100644 (file)
@@ -2,20 +2,6 @@
  * Common support for CompuLab SB-T35 used on SBC-T3530, SBC-T3517 and SBC-T3730
  */
 
-/ {
-       vddvario_sb_t35: regulator-vddvario-sb-t35 {
-               compatible = "regulator-fixed";
-               regulator-name = "vddvario";
-               regulator-always-on;
-       };
-
-       vdd33a_sb_t35: regulator-vdd33a-sb-t35 {
-               compatible = "regulator-fixed";
-               regulator-name = "vdd33a";
-               regulator-always-on;
-       };
-};
-
 &omap3_pmx_core {
        smsc2_pins: pinmux_smsc2_pins {
                pinctrl-single,pins = <
                reg = <4 0 0xff>;
                bank-width = <2>;
                gpmc,mux-add-data;
-               gpmc,cs-on-ns = <0>;
-               gpmc,cs-rd-off-ns = <186>;
-               gpmc,cs-wr-off-ns = <186>;
-               gpmc,adv-on-ns = <12>;
-               gpmc,adv-rd-off-ns = <48>;
+               gpmc,cs-on-ns = <1>;
+               gpmc,cs-rd-off-ns = <180>;
+               gpmc,cs-wr-off-ns = <180>;
+               gpmc,adv-rd-off-ns = <18>;
                gpmc,adv-wr-off-ns = <48>;
                gpmc,oe-on-ns = <54>;
                gpmc,oe-off-ns = <168>;
                gpmc,we-off-ns = <168>;
                gpmc,rd-cycle-ns = <186>;
                gpmc,wr-cycle-ns = <186>;
-               gpmc,access-ns = <114>;
-               gpmc,page-burst-access-ns = <6>;
-               gpmc,bus-turnaround-ns = <12>;
-               gpmc,cycle2cycle-delay-ns = <18>;
-               gpmc,wr-data-mux-bus-ns = <90>;
-               gpmc,wr-access-ns = <186>;
+               gpmc,access-ns = <144>;
+               gpmc,page-burst-access-ns = <24>;
+               gpmc,bus-turnaround-ns = <90>;
+               gpmc,cycle2cycle-delay-ns = <90>;
                gpmc,cycle2cycle-samecsen;
                gpmc,cycle2cycle-diffcsen;
-               vddvario-supply = <&vddvario_sb_t35>;
-               vdd33a-supply = <&vdd33a_sb_t35>;
+               vddvario-supply = <&vddvario>;
+               vdd33a-supply = <&vdd33a>;
                reg-io-width = <4>;
                smsc,save-mac-address;
        };
index 024c9c6c682d7eb4b421a559c7c4b5f95e0511f9..42189b65d393d29d2cf467ddbc5df4eb0661a471 100644 (file)
@@ -8,6 +8,19 @@
 / {
        model = "CompuLab SBC-T3517 with CM-T3517";
        compatible = "compulab,omap3-sbc-t3517", "compulab,omap3-cm-t3517", "ti,am3517", "ti,omap3";
+
+       /* Only one GPMC smsc9220 on SBC-T3517, CM-T3517 uses am35x Ethernet */
+       vddvario: regulator-vddvario-sb-t35 {
+               compatible = "regulator-fixed";
+               regulator-name = "vddvario";
+               regulator-always-on;
+       };
+
+       vdd33a: regulator-vdd33a-sb-t35 {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd33a";
+               regulator-always-on;
+       };
 };
 
 &omap3_pmx_core {
index acb9019dc437b66321ec7995dc16456678a2e42c..4231191ade06acf8c7a02938a0fcfcbdeb318fbc 100644 (file)
@@ -61,7 +61,7 @@
                        ti,hwmods = "mpu";
                };
 
-               iva {
+               iva: iva {
                        compatible = "ti,iva2.2";
                        ti,hwmods = "iva";
 
index f8c9855ce587c15790f79a2f04e0ff02933f463f..36b4312a5e0d82fb20fb6a7eb9b1d59942b0ec18 100644 (file)
                        status = "disabled";
                };
 
+               mailbox: mailbox@4a0f4000 {
+                       compatible = "ti,omap4-mailbox";
+                       reg = <0x4a0f4000 0x200>;
+                       interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+                       ti,hwmods = "mailbox";
+               };
+
                timer1: timer@4ae18000 {
                        compatible = "ti,omap5430-timer";
                        reg = <0x4ae18000 0x80>;
diff --git a/arch/arm/boot/dts/orion5x-lacie-d2-network.dts b/arch/arm/boot/dts/orion5x-lacie-d2-network.dts
new file mode 100644 (file)
index 0000000..c701e8d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2014 Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ * Copyright (C) 2009 Simon Guinot <sguinot@lacie.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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "orion5x-mv88f5182.dtsi"
+
+/ {
+       model = "LaCie d2 Network";
+       compatible = "lacie,d2-network", "marvell,orion5x-88f5182", "marvell,orion5x";
+
+       memory {
+               reg = <0x00000000 0x4000000>; /* 64 MB */
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 earlyprintk";
+               linux,stdout-path = &uart0;
+       };
+
+       soc {
+               ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000>,
+                        <MBUS_ID(0x09, 0x00) 0 0xf2200000 0x800>,
+                        <MBUS_ID(0x01, 0x0f) 0 0xfff80000 0x80000>;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-0 = <&pmx_buttons>;
+               pinctrl-names = "default";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               front_button {
+                       label = "Front Push Button";
+                       linux,code = <KEY_POWER>;
+                       gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;
+               };
+
+               power_rocker_sw_on {
+                       label = "Power rocker switch (on|auto)";
+                       linux,input-type = <5>; /* EV_SW */
+                       linux,code = <1>; /* D2NET_SWITCH_POWER_ON */
+                       gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
+               };
+
+               power_rocker_sw_off {
+                       label = "Power rocker switch (auto|off)";
+                       linux,input-type = <5>; /* EV_SW */
+                       linux,code = <2>; /* D2NET_SWITCH_POWER_OFF */
+                       gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               pinctrl-0 = <&pmx_sata0_power &pmx_sata1_power>;
+               pinctrl-names = "default";
+
+               sata0_power: regulator@0 {
+                       compatible = "regulator-fixed";
+                       reg = <0>;
+                       regulator-name = "SATA0 Power";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       enable-active-high;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       gpio = <&gpio0 3 GPIO_ACTIVE_HIGH>;
+               };
+
+               sata1_power: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "SATA1 Power";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       enable-active-high;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&devbus_bootcs {
+       status = "okay";
+
+       devbus,keep-config;
+
+       /*
+        * Currently the MTD code does not recognize the MX29LV400CBCT
+        * as a bottom-type device. This could cause risks of
+        * accidentally erasing critical flash sectors. We thus define
+        * a single, write-protected partition covering the whole
+        * flash.  TODO: once the flash part TOP/BOTTOM detection
+        * issue is sorted out in the MTD code, break this into at
+        * least three partitions: 'u-boot code', 'u-boot environment'
+        * and 'whatever is left'.
+        */
+       flash@0 {
+               compatible = "cfi-flash";
+               reg = <0 0x80000>;
+               bank-width = <1>;
+                #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "Full512Kb";
+                       reg = <0 0x80000>;
+                       read-only;
+               };
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       ethphy: ethernet-phy {
+               reg = <8>;
+       };
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&eth {
+       status = "okay";
+
+       ethernet-port@0 {
+               phy-handle = <&ethphy>;
+       };
+};
+
+&i2c {
+       status = "okay";
+       clock-frequency = <100000>;
+       #address-cells = <1>;
+
+       rtc@32 {
+               compatible = "ricoh,rs5c372b";
+               reg = <0x32>;
+       };
+
+       fan@3e {
+               compatible = "gmt,g762";
+               reg = <0x3e>;
+
+               /* Not enough HW info */
+               status = "disabled";
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c08";
+               reg = <0x50>;
+       };
+};
+
+&pinctrl {
+       pinctrl-0 = <&pmx_leds &pmx_board_id &pmx_fan_fail>;
+       pinctrl-names = "default";
+
+       pmx_board_id: pmx-board-id {
+               marvell,pins = "mpp0", "mpp1", "mpp2";
+               marvell,function = "gpio";
+       };
+
+       pmx_buttons: pmx-buttons {
+               marvell,pins = "mpp8", "mpp9", "mpp18";
+               marvell,function = "gpio";
+       };
+
+       pmx_fan_fail: pmx-fan-fail {
+               marvell,pins = "mpp5";
+               marvell,function = "gpio";
+       };
+
+       /*
+        * MPP6: Red front LED
+        * MPP16: Blue front LED blink control
+        */
+       pmx_leds: pmx-leds {
+               marvell,pins = "mpp6", "mpp16";
+               marvell,function = "gpio";
+       };
+
+       pmx_sata0_led_active: pmx-sata0-led-active {
+               marvell,pins = "mpp14";
+               marvell,function = "sata0";
+       };
+
+       pmx_sata0_power: pmx-sata0-power {
+               marvell,pins = "mpp3";
+               marvell,function = "gpio";
+       };
+
+       pmx_sata1_led_active: pmx-sata1-led-active {
+               marvell,pins = "mpp15";
+               marvell,function = "sata1";
+       };
+
+       pmx_sata1_power: pmx-sata1-power {
+               marvell,pins = "mpp12";
+               marvell,function = "gpio";
+       };
+
+       /*
+        * Non MPP GPIOs:
+        *  GPIO 22: USB port 1 fuse (0 = Fail, 1 = Ok)
+        *  GPIO 23: Blue front LED off
+        *  GPIO 24: Inhibit board power off (0 = Disabled, 1 = Enabled)
+        */
+};
+
+&sata {
+       pinctrl-0 = <&pmx_sata0_led_active
+                    &pmx_sata1_led_active>;
+       pinctrl-names = "default";
+       status = "okay";
+       nr-ports = <2>;
+};
+
+&uart0 {
+       status = "okay";
+};
index 5ed6c137690183c4586e6bdb7f00baa19f7b7054..89ff404a528c74f3869c6afcfcfdb34cdc7cde46 100644 (file)
@@ -6,8 +6,19 @@
  * warranty of any kind, whether express or implied.
  */
 
+/*
+ * TODO: add Orion USB device port init when kernel.org support is added.
+ * TODO: add flash write support: see below.
+ * TODO: add power-off support.
+ * TODO: add I2C EEPROM support.
+ */
+
 /dts-v1/;
-/include/ "orion5x.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "orion5x-mv88f5182.dtsi"
 
 / {
        model = "LaCie Ethernet Disk mini V2";
 
        chosen {
                bootargs = "console=ttyS0,115200n8 earlyprintk";
+               linux,stdout-path = &uart0;
        };
 
-       ocp@f1000000 {
-               serial@12000 {
-                       clock-frequency = <166666667>;
-                       status = "okay";
-               };
-
-               sata@80000 {
-                       status = "okay";
-                       nr-ports = <2>;
-               };
+       soc {
+               ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000>,
+                        <MBUS_ID(0x09, 0x00) 0 0xf2200000 0x800>,
+                        <MBUS_ID(0x01, 0x0f) 0 0xfff80000 0x80000>;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
+               pinctrl-0 = <&pmx_power_button>;
+               pinctrl-names = "default";
                #address-cells = <1>;
                #size-cells = <0>;
                button@1 {
                        label = "Power-on Switch";
-                       linux,code = <116>; /* KEY_POWER */
-                       gpios = <&gpio0 18 0>;
+                       linux,code = <KEY_POWER>;
+                       gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;
                };
        };
 
-       gpio_leds {
+       gpio-leds {
                compatible = "gpio-leds";
+               pinctrl-0 = <&pmx_power_led>;
+               pinctrl-names = "default";
 
                led@1 {
                        label = "power:blue";
-                       gpios = <&gpio0 16 1>;
+                       gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
                };
        };
 };
 
-&mdio {
+&devbus_bootcs {
        status = "okay";
 
-       ethphy: ethernet-phy {
-               reg = <8>;
+       /* Read parameters */
+       devbus,bus-width    = <8>;
+       devbus,turn-off-ps  = <90000>;
+       devbus,badr-skew-ps = <0>;
+       devbus,acc-first-ps = <186000>;
+       devbus,acc-next-ps  = <186000>;
+
+       /* Write parameters */
+       devbus,wr-high-ps  = <90000>;
+       devbus,wr-low-ps   = <90000>;
+       devbus,ale-wr-ps   = <90000>;
+
+       /*
+        * Currently the MTD code does not recognize the MX29LV400CBCT
+        * as a bottom-type device. This could cause risks of
+        * accidentally erasing critical flash sectors. We thus define
+        * a single, write-protected partition covering the whole
+        * flash.  TODO: once the flash part TOP/BOTTOM detection
+        * issue is sorted out in the MTD code, break this into at
+        * least three partitions: 'u-boot code', 'u-boot environment'
+        * and 'whatever is left'.
+        */
+       flash@0 {
+               compatible = "cfi-flash";
+               reg = <0 0x80000>;
+               bank-width = <1>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "Full512Kb";
+                       reg = <0 0x80000>;
+                       read-only;
+               };
        };
 };
 
+&ehci0 {
+       status = "okay";
+};
+
 &eth {
        status = "okay";
 
                phy-handle = <&ethphy>;
        };
 };
+
+&i2c {
+       status = "okay";
+       clock-frequency = <100000>;
+       #address-cells = <1>;
+
+       rtc@32 {
+               compatible = "ricoh,rs5c372a";
+               reg = <0x32>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       ethphy: ethernet-phy {
+               reg = <8>;
+       };
+};
+
+&pinctrl {
+       pinctrl-0 = <&pmx_rtc &pmx_power_led_ctrl>;
+       pinctrl-names = "default";
+
+       pmx_power_button: pmx-power-button {
+               marvell,pins = "mpp18";
+               marvell,function = "gpio";
+       };
+
+       pmx_power_led: pmx-power-led {
+               marvell,pins = "mpp16";
+               marvell,function = "gpio";
+       };
+
+       pmx_power_led_ctrl: pmx-power-led-ctrl {
+               marvell,pins = "mpp17";
+               marvell,function = "gpio";
+       };
+
+       pmx_rtc: pmx-rtc {
+               marvell,pins = "mpp3";
+               marvell,function = "gpio";
+       };
+};
+
+&sata {
+       pinctrl-0 = <&pmx_sata0 &pmx_sata1>;
+       pinctrl-names = "default";
+       status = "okay";
+       nr-ports = <2>;
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts b/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts
new file mode 100644 (file)
index 0000000..ff34849
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014 Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ * Copyright (C) Sylver Bruneau <sylver.bruneau@googlemail.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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "orion5x-mv88f5182.dtsi"
+
+/ {
+       model = "Maxtor Shared Storage II";
+       compatible = "maxtor,shared-storage-2", "marvell,orion5x-88f5182", "marvell,orion5x";
+
+       memory {
+               reg = <0x00000000 0x4000000>; /* 64 MB */
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 earlyprintk";
+               linux,stdout-path = &uart0;
+       };
+
+       soc {
+               ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000>,
+                        <MBUS_ID(0x09, 0x00) 0 0xf2200000 0x800>,
+                        <MBUS_ID(0x01, 0x0f) 0 0xff800000 0x40000>;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-0 = <&pmx_buttons>;
+               pinctrl-names = "default";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               power {
+                       label = "Power";
+                       linux,code = <KEY_POWER>;
+                       gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
+               };
+
+               reset {
+                       label = "Reset";
+                       linux,code = <KEY_RESTART>;
+                       gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&devbus_bootcs {
+       status = "okay";
+
+       devbus,keep-config;
+
+       /*
+        * Currently the MTD code does not recognize the MX29LV400CBCT
+        * as a bottom-type device. This could cause risks of
+        * accidentally erasing critical flash sectors. We thus define
+        * a single, write-protected partition covering the whole
+        * flash.  TODO: once the flash part TOP/BOTTOM detection
+        * issue is sorted out in the MTD code, break this into at
+        * least three partitions: 'u-boot code', 'u-boot environment'
+        * and 'whatever is left'.
+        */
+       flash@0 {
+               compatible = "cfi-flash";
+               reg = <0 0x40000>;
+               bank-width = <1>;
+                #address-cells = <1>;
+               #size-cells = <1>;
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       ethphy: ethernet-phy {
+               reg = <8>;
+       };
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&eth {
+       status = "okay";
+
+       ethernet-port@0 {
+               phy-handle = <&ethphy>;
+       };
+};
+
+&i2c {
+       status = "okay";
+       clock-frequency = <100000>;
+       #address-cells = <1>;
+
+       rtc@68 {
+               compatible = "st,m41t81";
+               reg = <0x68>;
+               pinctrl-0 = <&pmx_rtc>;
+               pinctrl-names = "default";
+               interrupt-parent = <&gpio0>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
+&pinctrl {
+       pinctrl-0 = <&pmx_leds &pmx_misc>;
+       pinctrl-names = "default";
+
+       pmx_buttons: pmx-buttons {
+               marvell,pins = "mpp11", "mpp12";
+               marvell,function = "gpio";
+       };
+
+       /*
+        * MPP0: Power LED
+        * MPP1: Error LED
+        */
+       pmx_leds: pmx-leds {
+               marvell,pins = "mpp0", "mpp1";
+               marvell,function = "gpio";
+       };
+
+       /*
+        * MPP4: HDD ind. (Single/Dual)
+        * MPP5: HD0 5V control
+        * MPP6: HD0 12V control
+        * MPP7: HD1 5V control
+        * MPP8: HD1 12V control
+        */
+       pmx_misc: pmx-misc {
+               marvell,pins = "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", "mpp10";
+               marvell,function = "gpio";
+       };
+
+       pmx_rtc: pmx-rtc {
+               marvell,pins = "mpp3";
+               marvell,function = "gpio";
+       };
+
+       pmx_sata0_led_active: pmx-sata0-led-active {
+               marvell,pins = "mpp14";
+               marvell,function = "sata0";
+       };
+
+       pmx_sata1_led_active: pmx-sata1-led-active {
+               marvell,pins = "mpp15";
+               marvell,function = "sata1";
+       };
+
+       /*
+        * Non MPP GPIOs:
+        *  GPIO 22: USB port 1 fuse (0 = Fail, 1 = Ok)
+        *  GPIO 23: Blue front LED off
+        *  GPIO 24: Inhibit board power off (0 = Disabled, 1 = Enabled)
+        */
+};
+
+&sata {
+       pinctrl-0 = <&pmx_sata0_led_active
+                    &pmx_sata1_led_active>;
+       pinctrl-names = "default";
+       status = "okay";
+       nr-ports = <2>;
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/orion5x-mv88f5182.dtsi b/arch/arm/boot/dts/orion5x-mv88f5182.dtsi
new file mode 100644 (file)
index 0000000..d1ed71c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Thomas Petazzoni <thomas.petazzoni@free-electrons.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 "orion5x.dtsi"
+
+/ {
+       compatible = "marvell,orion5x-88f5182", "marvell,orion5x";
+
+       soc {
+               compatible = "marvell,orion5x-88f5182-mbus", "simple-bus";
+
+               internal-regs {
+                       pinctrl: pinctrl@10000 {
+                               compatible = "marvell,88f5182-pinctrl";
+                               reg = <0x10000 0x8>, <0x10050 0x4>;
+
+                               pmx_sata0: pmx-sata0 {
+                                       marvell,pins = "mpp12", "mpp14";
+                                       marvell,function = "sata0";
+                               };
+
+                               pmx_sata1: pmx-sata1 {
+                                       marvell,pins = "mpp13", "mpp15";
+                                       marvell,function = "sata1";
+                               };
+                       };
+
+                       core_clk: core-clocks@10030 {
+                               compatible = "marvell,mv88f5182-core-clock";
+                               reg = <0x10010 0x4>;
+                               #clock-cells = <1>;
+                       };
+
+                       mbusc: mbus-controller@20000 {
+                               compatible = "marvell,mbus-controller";
+                               reg = <0x20000 0x100>, <0x1500 0x20>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts b/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts
new file mode 100644 (file)
index 0000000..6fb0525
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2014 Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "orion5x-mv88f5182.dtsi"
+
+/ {
+       model = "Marvell Reference Design 88F5182 NAS";
+       compatible = "marvell,rd-88f5182-nas", "marvell,orion5x-88f5182", "marvell,orion5x";
+
+       memory {
+               reg = <0x00000000 0x4000000>; /* 64 MB */
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 earlyprintk";
+               linux,stdout-path = &uart0;
+       };
+
+       soc {
+               ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000>,
+                        <MBUS_ID(0x09, 0x00) 0 0xf2200000 0x800>,
+                        <MBUS_ID(0x01, 0x0f) 0 0xf4000000 0x80000>,
+                        <MBUS_ID(0x01, 0x1d) 0 0xfc000000 0x1000000>;
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-0 = <&pmx_debug_led>;
+               pinctrl-names = "default";
+
+               led@0 {
+                       label = "rd88f5182:cpu";
+                       linux,default-trigger = "heartbeat";
+                       gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&devbus_bootcs {
+       status = "okay";
+
+       /* Read parameters */
+       devbus,bus-width    = <8>;
+       devbus,turn-off-ps  = <90000>;
+       devbus,badr-skew-ps = <0>;
+       devbus,acc-first-ps = <186000>;
+       devbus,acc-next-ps  = <186000>;
+
+       /* Write parameters */
+       devbus,wr-high-ps  = <90000>;
+       devbus,wr-low-ps   = <90000>;
+       devbus,ale-wr-ps   = <90000>;
+
+       flash@0 {
+               compatible = "cfi-flash";
+               reg = <0 0x80000>;
+               bank-width = <1>;
+       };
+};
+
+&devbus_cs1 {
+       status = "okay";
+
+       /* Read parameters */
+       devbus,bus-width    = <8>;
+       devbus,turn-off-ps  = <90000>;
+       devbus,badr-skew-ps = <0>;
+       devbus,acc-first-ps = <186000>;
+       devbus,acc-next-ps  = <186000>;
+
+       /* Write parameters */
+       devbus,wr-high-ps  = <90000>;
+       devbus,wr-low-ps   = <90000>;
+       devbus,ale-wr-ps   = <90000>;
+
+       flash@0 {
+               compatible = "cfi-flash";
+               reg = <0 0x1000000>;
+               bank-width = <1>;
+       };
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&eth {
+       status = "okay";
+
+       ethernet-port@0 {
+               phy-handle = <&ethphy>;
+       };
+};
+
+&i2c {
+       status = "okay";
+       clock-frequency = <100000>;
+       #address-cells = <1>;
+
+       rtc@68 {
+               pinctrl-0 = <&pmx_rtc>;
+               pinctrl-names = "default";
+               compatible = "dallas,ds1338";
+               reg = <0x68>;
+       };
+};
+
+&mdio {
+       status = "okay";
+
+       ethphy: ethernet-phy {
+               reg = <8>;
+       };
+};
+
+&pinctrl {
+       pinctrl-0 = <&pmx_reset_switch &pmx_misc_gpios
+               &pmx_pci_gpios>;
+       pinctrl-names = "default";
+
+       /*
+        * MPP[20] PCI Clock to MV88F5182
+        * MPP[21] PCI Clock to mini PCI CON11
+        * MPP[22] USB 0 over current indication
+        * MPP[23] USB 1 over current indication
+        * MPP[24] USB 1 over current enable
+        * MPP[25] USB 0 over current enable
+        */
+
+       pmx_debug_led: pmx-debug_led {
+               marvell,pins = "mpp0";
+               marvell,function = "gpio";
+       };
+
+       pmx_reset_switch: pmx-reset-switch {
+               marvell,pins = "mpp1";
+               marvell,function = "gpio";
+       };
+
+       pmx_rtc: pmx-rtc {
+               marvell,pins = "mpp3";
+               marvell,function = "gpio";
+       };
+
+       pmx_misc_gpios: pmx-misc-gpios {
+               marvell,pins = "mpp4", "mpp5";
+               marvell,function = "gpio";
+       };
+
+       pmx_pci_gpios: pmx-pci-gpios {
+               marvell,pins = "mpp6", "mpp7";
+               marvell,function = "gpio";
+       };
+};
+
+&sata {
+       pinctrl-0 = <&pmx_sata0 &pmx_sata1>;
+       pinctrl-names = "default";
+       status = "okay";
+       nr-ports = <2>;
+};
+
+&uart0 {
+       status = "okay";
+};
index 174d89241f7002ffb9b12e4f3db1997bf13d7611..75cd01bd60241d0e0f06f2a390941c63a925e7bf 100644 (file)
@@ -6,7 +6,9 @@
  * warranty of any kind, whether express or implied.
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16))
 
 / {
        model = "Marvell Orion5x SoC";
                gpio0 = &gpio0;
        };
 
-       intc: interrupt-controller {
-               compatible = "marvell,orion-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               reg = <0xf1020200 0x08>;
-       };
-
-       ocp@f1000000 {
-               compatible = "simple-bus";
-               ranges = <0x00000000 0xf1000000 0x4000000
-                         0xf2200000 0xf2200000 0x0000800>;
-               #address-cells = <1>;
+       soc {
+               #address-cells = <2>;
                #size-cells = <1>;
+               controller = <&mbusc>;
 
-               gpio0: gpio@10100 {
-                       compatible = "marvell,orion-gpio";
-                       #gpio-cells = <2>;
-                       gpio-controller;
-                       reg = <0x10100 0x40>;
-                       ngpios = <32>;
-                       interrupt-controller;
-                       #interrupt-cells = <2>;
-                       interrupts = <6>, <7>, <8>, <9>;
-               };
-
-               spi@10600 {
-                       compatible = "marvell,orion-spi";
+               devbus_bootcs: devbus-bootcs {
+                       compatible = "marvell,orion-devbus";
+                       reg = <MBUS_ID(0xf0, 0x01) 0x1046C 0x4>;
+                       ranges = <0 MBUS_ID(0x01, 0x0f) 0 0xffffffff>;
                        #address-cells = <1>;
-                       #size-cells = <0>;
-                       cell-index = <0>;
-                       reg = <0x10600 0x28>;
+                       #size-cells = <1>;
+                       clocks = <&core_clk 0>;
                        status = "disabled";
                };
 
-               i2c@11000 {
-                       compatible = "marvell,mv64xxx-i2c";
-                       reg = <0x11000 0x20>;
+               devbus_cs0: devbus-cs0 {
+                       compatible = "marvell,orion-devbus";
+                       reg = <MBUS_ID(0xf0, 0x01) 0x1045C 0x4>;
+                       ranges = <0 MBUS_ID(0x01, 0x1e) 0 0xffffffff>;
                        #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupts = <5>;
-                       clock-frequency = <100000>;
+                       #size-cells = <1>;
+                       clocks = <&core_clk 0>;
                        status = "disabled";
                };
 
-               serial@12000 {
-                       compatible = "ns16550a";
-                       reg = <0x12000 0x100>;
-                       reg-shift = <2>;
-                       interrupts = <3>;
-                       /* set clock-frequency in board dts */
+               devbus_cs1: devbus-cs1 {
+                       compatible = "marvell,orion-devbus";
+                       reg = <MBUS_ID(0xf0, 0x01) 0x10460 0x4>;
+                       ranges = <0 MBUS_ID(0x01, 0x1d) 0 0xffffffff>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       clocks = <&core_clk 0>;
                        status = "disabled";
                };
 
-               serial@12100 {
-                       compatible = "ns16550a";
-                       reg = <0x12100 0x100>;
-                       reg-shift = <2>;
-                       interrupts = <4>;
-                       /* set clock-frequency in board dts */
+               devbus_cs2: devbus-cs2 {
+                       compatible = "marvell,orion-devbus";
+                       reg = <MBUS_ID(0xf0, 0x01) 0x10464 0x4>;
+                       ranges = <0 MBUS_ID(0x01, 0x1b) 0 0xffffffff>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       clocks = <&core_clk 0>;
                        status = "disabled";
                };
 
-               wdt@20300 {
-                       compatible = "marvell,orion-wdt";
-                       reg = <0x20300 0x28>;
-                       status = "okay";
-               };
+               internal-regs {
+                       compatible = "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
+
+                       gpio0: gpio@10100 {
+                               compatible = "marvell,orion-gpio";
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               reg = <0x10100 0x40>;
+                               ngpios = <32>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <6>, <7>, <8>, <9>;
+                       };
 
-               ehci@50000 {
-                       compatible = "marvell,orion-ehci";
-                       reg = <0x50000 0x1000>;
-                       interrupts = <17>;
-                       status = "disabled";
-               };
+                       spi: spi@10600 {
+                               compatible = "marvell,orion-spi";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               cell-index = <0>;
+                               reg = <0x10600 0x28>;
+                               status = "disabled";
+                       };
 
-               xor@60900 {
-                       compatible = "marvell,orion-xor";
-                       reg = <0x60900 0x100
-                              0x60b00 0x100>;
-                       status = "okay";
+                       i2c: i2c@11000 {
+                               compatible = "marvell,mv64xxx-i2c";
+                               reg = <0x11000 0x20>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               interrupts = <5>;
+                               clocks = <&core_clk 0>;
+                               status = "disabled";
+                       };
 
-                       xor00 {
-                             interrupts = <30>;
-                             dmacap,memcpy;
-                             dmacap,xor;
+                       uart0: serial@12000 {
+                               compatible = "ns16550a";
+                               reg = <0x12000 0x100>;
+                               reg-shift = <2>;
+                               interrupts = <3>;
+                               clocks = <&core_clk 0>;
+                               status = "disabled";
                        };
-                       xor01 {
-                             interrupts = <31>;
-                             dmacap,memcpy;
-                             dmacap,xor;
-                             dmacap,memset;
+
+                       uart1: serial@12100 {
+                               compatible = "ns16550a";
+                               reg = <0x12100 0x100>;
+                               reg-shift = <2>;
+                               interrupts = <4>;
+                               clocks = <&core_clk 0>;
+                               status = "disabled";
                        };
-               };
 
-               eth: ethernet-controller@72000 {
-                       compatible = "marvell,orion-eth";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <0x72000 0x4000>;
-                       marvell,tx-checksum-limit = <1600>;
-                       status = "disabled";
+                       bridge_intc: bridge-interrupt-ctrl@20110 {
+                               compatible = "marvell,orion-bridge-intc";
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x20110 0x8>;
+                               interrupts = <0>;
+                               marvell,#interrupts = <4>;
+                       };
 
-                       ethernet-port@0 {
-                               compatible = "marvell,orion-eth-port";
-                               reg = <0>;
-                               /* overwrite MAC address in bootloader */
-                               local-mac-address = [00 00 00 00 00 00];
-                               /* set phy-handle property in board file */
+                       intc: interrupt-controller@20200 {
+                               compatible = "marvell,orion-intc";
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               reg = <0x20200 0x08>;
                        };
-               };
 
-               mdio: mdio-bus@72004 {
-                       compatible = "marvell,orion-mdio";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <0x72004 0x84>;
-                       interrupts = <22>;
-                       status = "disabled";
+                       timer: timer@20300 {
+                               compatible = "marvell,orion-timer";
+                               reg = <0x20300 0x20>;
+                               interrupt-parent = <&bridge_intc>;
+                               interrupts = <1>, <2>;
+                               clocks = <&core_clk 0>;
+                       };
 
-                       /* add phy nodes in board file */
-               };
+                       wdt: wdt@20300 {
+                               compatible = "marvell,orion-wdt";
+                               reg = <0x20300 0x28>;
+                               interrupt-parent = <&bridge_intc>;
+                               interrupts = <3>;
+                               status = "okay";
+                       };
 
-               sata@80000 {
-                       compatible = "marvell,orion-sata";
-                       reg = <0x80000 0x5000>;
-                       interrupts = <29>;
-                       status = "disabled";
+                       ehci0: ehci@50000 {
+                               compatible = "marvell,orion-ehci";
+                               reg = <0x50000 0x1000>;
+                               interrupts = <17>;
+                               status = "disabled";
+                       };
+
+                       xor: dma-controller@60900 {
+                               compatible = "marvell,orion-xor";
+                               reg = <0x60900 0x100
+                                      0x60b00 0x100>;
+                               status = "okay";
+
+                               xor00 {
+                                     interrupts = <30>;
+                                     dmacap,memcpy;
+                                     dmacap,xor;
+                               };
+                               xor01 {
+                                     interrupts = <31>;
+                                     dmacap,memcpy;
+                                     dmacap,xor;
+                                     dmacap,memset;
+                               };
+                       };
+
+                       eth: ethernet-controller@72000 {
+                               compatible = "marvell,orion-eth";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x72000 0x4000>;
+                               marvell,tx-checksum-limit = <1600>;
+                               status = "disabled";
+
+                               ethport: ethernet-port@0 {
+                                       compatible = "marvell,orion-eth-port";
+                                       reg = <0>;
+                                       interrupts = <21>;
+                                       /* overwrite MAC address in bootloader */
+                                       local-mac-address = [00 00 00 00 00 00];
+                                       /* set phy-handle property in board file */
+                               };
+                       };
+
+                       mdio: mdio-bus@72004 {
+                               compatible = "marvell,orion-mdio";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x72004 0x84>;
+                               interrupts = <22>;
+                               status = "disabled";
+
+                               /* add phy nodes in board file */
+                       };
+
+                       sata: sata@80000 {
+                               compatible = "marvell,orion-sata";
+                               reg = <0x80000 0x5000>;
+                               interrupts = <29>;
+                               status = "disabled";
+                       };
+
+                       ehci1: ehci@a0000 {
+                               compatible = "marvell,orion-ehci";
+                               reg = <0xa0000 0x1000>;
+                               interrupts = <12>;
+                               status = "disabled";
+                       };
                };
 
-               crypto@90000 {
+               cesa: crypto@90000 {
                        compatible = "marvell,orion-crypto";
-                       reg = <0x90000 0x10000>,
-                             <0xf2200000 0x800>;
+                       reg = <MBUS_ID(0xf0, 0x01) 0x90000 0x10000>,
+                             <MBUS_ID(0x09, 0x00) 0x0 0x800>;
                        reg-names = "regs", "sram";
                        interrupts = <28>;
                        status = "okay";
                };
-
-               ehci@a0000 {
-                       compatible = "marvell,orion-ehci";
-                       reg = <0xa0000 0x1000>;
-                       interrupts = <12>;
-                       status = "disabled";
-               };
        };
 };
index 95a849bf921f464fa4e59bcada97d7a048dcd876..10344e6edd20a396d653969fac4de365953784ff 100644 (file)
@@ -11,6 +11,7 @@
 /dts-v1/;
 #include "r8a7740.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pwm/pwm.h>
 
 
                power-key {
                        gpios = <&pfc 99 GPIO_ACTIVE_LOW>;
-                       linux,code = <116>;
+                       linux,code = <KEY_POWER>;
                        label = "SW3";
                        gpio-key,wakeup;
                };
 
                back-key {
                        gpios = <&pfc 100 GPIO_ACTIVE_LOW>;
-                       linux,code = <158>;
+                       linux,code = <KEY_BACK>;
                        label = "SW4";
                };
 
                menu-key {
                        gpios = <&pfc 97 GPIO_ACTIVE_LOW>;
-                       linux,code = <139>;
+                       linux,code = <KEY_MENU>;
                        label = "SW5";
                };
 
                home-key {
                        gpios = <&pfc 98 GPIO_ACTIVE_LOW>;
-                       linux,code = <102>;
+                       linux,code = <KEY_HOME>;
                        label = "SW6";
                };
        };
                };
        };
 
+       i2c2: i2c@2 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "i2c-gpio";
+               gpios = <&pfc 208 GPIO_ACTIVE_HIGH /* sda */
+                        &pfc 91 GPIO_ACTIVE_HIGH /* scl */
+                       >;
+               i2c-gpio,delay-us = <5>;
+       };
+
        backlight {
                compatible = "pwm-backlight";
                pwms = <&tpu 2 33333 PWM_POLARITY_INVERTED>;
        };
 };
 
+&i2c2 {
+       status = "okay";
+       rtc@30 {
+               compatible = "sii,s35390a";
+               reg = <0x30>;
+       };
+};
+
 &pfc {
        pinctrl-0 = <&scifa1_pins>;
        pinctrl-names = "default";
index 2551e9438d358a55e8e4edb7c494ea231ee46810..3834b94dc02ae25dddac5661e12d49627a30a77a 100644 (file)
        i2c0: i2c@fff20000 {
                #address-cells = <1>;
                #size-cells = <0>;
-               compatible = "renesas,rmobile-iic";
+               compatible = "renesas,iic-r8a7740", "renesas,rmobile-iic";
                reg = <0xfff20000 0x425>;
                interrupt-parent = <&gic>;
                interrupts = <0 201 IRQ_TYPE_LEVEL_HIGH
        i2c1: i2c@e6c20000 {
                #address-cells = <1>;
                #size-cells = <0>;
-               compatible = "renesas,rmobile-iic";
+               compatible = "renesas,iic-r8a7740", "renesas,rmobile-iic";
                reg = <0xe6c20000 0x425>;
                interrupt-parent = <&gic>;
                interrupts = <0 70 IRQ_TYPE_LEVEL_HIGH
        };
 
        mmcif0: mmc@e6bd0000 {
-               compatible = "renesas,sh-mmcif";
+               compatible = "renesas,mmcif-r8a7740", "renesas,sh-mmcif";
                reg = <0xe6bd0000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH
 
        sh_fsi2: sound@fe1f0000 {
                #sound-dai-cells = <1>;
-               compatible = "renesas,sh_fsi2";
+               compatible = "renesas,fsi2-r8a7740", "renesas,sh_fsi2";
                reg = <0xfe1f0000 0x400>;
                interrupt-parent = <&gic>;
                interrupts = <0 9 0x4>;
index 06cda19dac6a6dccef649109ca17eb4528327dc7..f76f6ec01e194c669ef0bcc055e78b20d602086a 100644 (file)
        pinctrl-0 = <&hspi0_pins>;
        pinctrl-names = "default";
        status = "okay";
+
+       flash: flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spansion,s25fl008k";
+               reg = <0>;
+               spi-max-frequency = <104000000>;
+               m25p,fast-read;
+
+               partition@0 {
+                       label = "data(spi)";
+                       reg = <0x00000000 0x00100000>;
+               };
+       };
 };
index 85c5b3b99f5e3b87485f193750e8150815ff9e17..3c6fab5c9702e437aebe18e622b8358b675c806b 100644 (file)
        };
 
        hspi0: spi@fffc7000 {
-               compatible = "renesas,hspi";
+               compatible = "renesas,hspi-r8a7778", "renesas,hspi";
                reg = <0xfffc7000 0x18>;
-               interrupt-controller = <&gic>;
+               interrupt-parent = <&gic>;
                interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
        };
 
        hspi1: spi@fffc8000 {
-               compatible = "renesas,hspi";
+               compatible = "renesas,hspi-r8a7778", "renesas,hspi";
                reg = <0xfffc8000 0x18>;
-               interrupt-controller = <&gic>;
+               interrupt-parent = <&gic>;
                interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
        };
 
        hspi2: spi@fffc6000 {
-               compatible = "renesas,hspi";
+               compatible = "renesas,hspi-r8a7778", "renesas,hspi";
                reg = <0xfffc6000 0x18>;
-               interrupt-controller = <&gic>;
+               interrupt-parent = <&gic>;
                interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
        };
 };
index d0561d4c7c466056096969331d467f6196b9ff63..8b1a336ee401bebb40bf4158338a125434c6f1f2 100644 (file)
        };
 
        hspi0: spi@fffc7000 {
-               compatible = "renesas,hspi";
+               compatible = "renesas,hspi-r8a7779", "renesas,hspi";
                reg = <0xfffc7000 0x18>;
-               interrupt-controller = <&gic>;
+               interrupt-parent = <&gic>;
                interrupts = <0 73 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
        };
 
        hspi1: spi@fffc8000 {
-               compatible = "renesas,hspi";
+               compatible = "renesas,hspi-r8a7779", "renesas,hspi";
                reg = <0xfffc8000 0x18>;
-               interrupt-controller = <&gic>;
+               interrupt-parent = <&gic>;
                interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
        };
 
        hspi2: spi@fffc6000 {
-               compatible = "renesas,hspi";
+               compatible = "renesas,hspi-r8a7779", "renesas,hspi";
                reg = <0xfffc6000 0x18>;
-               interrupt-controller = <&gic>;
+               interrupt-parent = <&gic>;
                interrupts = <0 75 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
                status = "disabled";
        };
 };
index d01048ab3e777534e224eb9a9395ba0a83cd56b7..86d676f629429ab3c304111fcdd987e91fca0c9a 100644 (file)
@@ -12,6 +12,7 @@
 /dts-v1/;
 #include "r8a7790.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
        model = "Lager";
                #size-cells = <1>;
        };
 
+       gpio_keys {
+               compatible = "gpio-keys";
+
+               button@1 {
+                       linux,code = <KEY_1>;
+                       label = "SW2-1";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+                       gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+               };
+               button@2 {
+                       linux,code = <KEY_2>;
+                       label = "SW2-2";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+                       gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
+               };
+               button@3 {
+                       linux,code = <KEY_3>;
+                       label = "SW2-3";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+                       gpios = <&gpio1 26 GPIO_ACTIVE_LOW>;
+               };
+               button@4 {
+                       linux,code = <KEY_4>;
+                       label = "SW2-4";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+                       gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
                led6 {
                renesas,function = "mmc1";
        };
 
-       qspi_pins: spi {
+       qspi_pins: spi0 {
                renesas,groups = "qspi_ctrl", "qspi_data4";
                renesas,function = "qspi";
        };
+
+       msiof1_pins: spi2 {
+               renesas,groups = "msiof1_clk", "msiof1_sync", "msiof1_rx",
+                                "msiof1_tx";
+               renesas,function = "msiof1";
+       };
 };
 
 &ether {
                reg = <1>;
                interrupt-parent = <&irqc0>;
                interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               micrel,led-mode = <1>;
        };
 };
 
        status = "okay";
 };
 
-&spi {
+&qspi {
        pinctrl-0 = <&qspi_pins>;
        pinctrl-names = "default";
 
                compatible = "spansion,s25fl512s";
                reg = <0>;
                spi-max-frequency = <30000000>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
                m25p,fast-read;
 
                partition@0 {
        };
 };
 
+&msiof1 {
+       pinctrl-0 = <&msiof1_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       pmic: pmic@0 {
+               compatible = "renesas,r2a11302ft";
+               reg = <0>;
+               spi-max-frequency = <6000000>;
+               spi-cpol;
+               spi-cpha;
+       };
+
+};
+
 &sdhi0 {
        pinctrl-0 = <&sdhi0_pins>;
        pinctrl-names = "default";
index 618e5b537eaf9deb5efbe34ee7f917f8ea95990b..d38d703391490b400e1628052079a9d3f72cc253 100644 (file)
                i2c1 = &i2c1;
                i2c2 = &i2c2;
                i2c3 = &i2c3;
+               i2c4 = &iic0;
+               i2c5 = &iic1;
+               i2c6 = &iic2;
+               i2c7 = &iic3;
+               spi0 = &qspi;
+               spi1 = &msiof0;
+               spi2 = &msiof1;
+               spi3 = &msiof2;
+               spi4 = &msiof3;
        };
 
        cpus {
                status = "disabled";
        };
 
+       iic0: i2c@e6500000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic";
+               reg = <0 0xe6500000 0 0x425>;
+               interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp3_clks R8A7790_CLK_IIC0>;
+               status = "disabled";
+       };
+
+       iic1: i2c@e6510000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic";
+               reg = <0 0xe6510000 0 0x425>;
+               interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp3_clks R8A7790_CLK_IIC1>;
+               status = "disabled";
+       };
+
+       iic2: i2c@e6520000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic";
+               reg = <0 0xe6520000 0 0x425>;
+               interrupts = <0 176 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp3_clks R8A7790_CLK_IIC2>;
+               status = "disabled";
+       };
+
+       iic3: i2c@e60b0000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic";
+               reg = <0 0xe60b0000 0 0x425>;
+               interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp9_clks R8A7790_CLK_IICDVFS>;
+               status = "disabled";
+       };
+
        mmcif0: mmcif@ee200000 {
                compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif";
                reg = <0 0xee200000 0 0x80>;
                        renesas,clock-indices = <
                                R8A7790_CLK_TMU1 R8A7790_CLK_TMU3 R8A7790_CLK_TMU2
                                R8A7790_CLK_CMT0 R8A7790_CLK_TMU0 R8A7790_CLK_VSP1_DU1
-                               R8A7790_CLK_VSP1_DU0 R8A7790_CLK_VSP1_RT R8A7790_CLK_VSP1_SY
+                               R8A7790_CLK_VSP1_DU0 R8A7790_CLK_VSP1_R R8A7790_CLK_VSP1_S
                        >;
                        clock-output-names =
                                "tmu1", "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1",
                mstp3_clks: mstp3_clks@e615013c {
                        compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
-                       clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>,
-                                <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>,
-                                <&mmc0_clk>, <&rclk_clk>;
+                       clocks = <&hp_clk>, <&cp_clk>, <&mmc1_clk>, <&sd3_clk>,
+                                <&sd2_clk>, <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, <&mmc0_clk>,
+                                <&hp_clk>, <&hp_clk>, <&rclk_clk>;
                        #clock-cells = <1>;
                        renesas,clock-indices = <
-                               R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
-                               R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0
-                               R8A7790_CLK_MMCIF0 R8A7790_CLK_CMT1
+                               R8A7790_CLK_IIC2 R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
+                               R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 R8A7790_CLK_MMCIF0
+                               R8A7790_CLK_IIC0 R8A7790_CLK_IIC1 R8A7790_CLK_CMT1
                        >;
                        clock-output-names =
-                               "tpu0", "mmcif1", "sdhi3", "sdhi2",
-                               "sdhi1", "sdhi0", "mmcif0", "cmt1";
+                               "iic2", "tpu0", "mmcif1", "sdhi3",
+                               "sdhi2", "sdhi1", "sdhi0", "mmcif0",
+                               "iic0", "iic1", "cmt1";
                };
                mstp5_clks: mstp5_clks@e6150144 {
                        compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
                mstp9_clks: mstp9_clks@e6150994 {
                        compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>;
-                       clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7790_CLK_QSPI>,
-                                <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>;
+                       clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7790_CLK_QSPI>, <&cp_clk>,
+                                <&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>;
                        #clock-cells = <1>;
                        renesas,clock-indices = <
-                               R8A7790_CLK_RCAN1 R8A7790_CLK_RCAN0 R8A7790_CLK_QSPI_MOD
-                               R8A7790_CLK_I2C3 R8A7790_CLK_I2C2 R8A7790_CLK_I2C1
-                               R8A7790_CLK_I2C0
+                               R8A7790_CLK_RCAN1 R8A7790_CLK_RCAN0 R8A7790_CLK_QSPI_MOD R8A7790_CLK_IICDVFS
+                               R8A7790_CLK_I2C3 R8A7790_CLK_I2C2 R8A7790_CLK_I2C1 R8A7790_CLK_I2C0
                        >;
                        clock-output-names =
-                               "rcan1", "rcan0", "qspi_mod", "i2c3", "i2c2", "i2c1", "i2c0";
+                               "rcan1", "rcan0", "qspi_mod", "iic3",
+                               "i2c3", "i2c2", "i2c1", "i2c0";
                };
        };
 
-       spi: spi@e6b10000 {
+       qspi: spi@e6b10000 {
                compatible = "renesas,qspi-r8a7790", "renesas,qspi";
                reg = <0 0xe6b10000 0 0x2c>;
                interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
                #size-cells = <0>;
                status = "disabled";
        };
+
+       msiof0: spi@e6e20000 {
+               compatible = "renesas,msiof-r8a7790";
+               reg = <0 0xe6e20000 0 0x0064>;
+               interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp0_clks R8A7790_CLK_MSIOF0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       msiof1: spi@e6e10000 {
+               compatible = "renesas,msiof-r8a7790";
+               reg = <0 0xe6e10000 0 0x0064>;
+               interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp2_clks R8A7790_CLK_MSIOF1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       msiof2: spi@e6e00000 {
+               compatible = "renesas,msiof-r8a7790";
+               reg = <0 0xe6e00000 0 0x0064>;
+               interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp2_clks R8A7790_CLK_MSIOF2>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       msiof3: spi@e6c90000 {
+               compatible = "renesas,msiof-r8a7790";
+               reg = <0 0xe6c90000 0 0x0064>;
+               interrupts = <0 159 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp2_clks R8A7790_CLK_MSIOF3>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
 };
diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts
new file mode 100644 (file)
index 0000000..0a65523
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Device Tree Source for the Henninger board
+ *
+ * Copyright (C) 2014 Renesas Solutions Corp.
+ * Copyright (C) 2014 Cogent Embedded, Inc.
+ *
+ * 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 "r8a7791.dtsi"
+
+/ {
+       model = "Henninger";
+       compatible = "renesas,henninger", "renesas,r8a7791";
+
+       aliases {
+               serial0 = &scif0;
+       };
+
+       chosen {
+               bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0 0x40000000>;
+       };
+
+       memory@200000000 {
+               device_type = "memory";
+               reg = <2 0x00000000 0 0x40000000>;
+       };
+};
+
+&extal_clk {
+       clock-frequency = <20000000>;
+};
+
+&pfc {
+       scif0_pins: serial0 {
+               renesas,groups = "scif0_data_d";
+               renesas,function = "scif0";
+       };
+
+       ether_pins: ether {
+               renesas,groups = "eth_link", "eth_mdio", "eth_rmii";
+               renesas,function = "eth";
+       };
+
+       phy1_pins: phy1 {
+               renesas,groups = "intc_irq0";
+               renesas,function = "intc";
+       };
+};
+
+&scif0 {
+       pinctrl-0 = <&scif0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&ether {
+       pinctrl-0 = <&ether_pins &phy1_pins>;
+       pinctrl-names = "default";
+
+       phy-handle = <&phy1>;
+       renesas,ether-link-active-low;
+       status = "ok";
+
+       phy1: ethernet-phy@1 {
+               reg = <1>;
+               interrupt-parent = <&irqc0>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               micrel,led-mode = <1>;
+       };
+};
+
+&sata0 {
+       status = "okay";
+};
index de1b6977c69a4b009d3e658b8d9790b373278d49..0d69813def859eb1d235576acc565e9269a8e5d6 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 #include "r8a7791.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
        model = "Koelsch";
        gpio-keys {
                compatible = "gpio-keys";
 
+               key-1 {
+                       gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_1>;
+                       label = "SW2-1";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+               };
+               key-2 {
+                       gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_2>;
+                       label = "SW2-2";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+               };
+               key-3 {
+                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_3>;
+                       label = "SW2-3";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+               };
+               key-4 {
+                       gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_4>;
+                       label = "SW2-4";
+                       gpio-key,wakeup;
+                       debounce-interval = <20>;
+               };
                key-a {
                        gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
-                       linux,code = <30>;
+                       linux,code = <KEY_A>;
                        label = "SW30";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
                };
                key-b {
                        gpios = <&gpio7 1 GPIO_ACTIVE_LOW>;
-                       linux,code = <48>;
+                       linux,code = <KEY_B>;
                        label = "SW31";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
                };
                key-c {
                        gpios = <&gpio7 2 GPIO_ACTIVE_LOW>;
-                       linux,code = <46>;
+                       linux,code = <KEY_C>;
                        label = "SW32";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
                };
                key-d {
                        gpios = <&gpio7 3 GPIO_ACTIVE_LOW>;
-                       linux,code = <32>;
+                       linux,code = <KEY_D>;
                        label = "SW33";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
                };
                key-e {
                        gpios = <&gpio7 4 GPIO_ACTIVE_LOW>;
-                       linux,code = <18>;
+                       linux,code = <KEY_E>;
                        label = "SW34";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
                };
                key-f {
                        gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
-                       linux,code = <33>;
+                       linux,code = <KEY_F>;
                        label = "SW35";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
                };
                key-g {
                        gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
-                       linux,code = <34>;
+                       linux,code = <KEY_G>;
                        label = "SW36";
                        gpio-key,wakeup;
                        debounce-interval = <20>;
        };
 };
 
+&i2c6 {
+       status = "okay";
+       clock-frequency = <100000>;
+};
+
 &pfc {
        pinctrl-0 = <&du_pins &scif0_pins &scif1_pins>;
        pinctrl-names = "default";
 
-       i2c2_pins: i2c {
+       i2c2_pins: i2c2 {
                renesas,groups = "i2c2";
                renesas,function = "i2c2";
        };
                renesas,function = "sdhi2";
        };
 
-       qspi_pins: spi {
+       qspi_pins: spi0 {
                renesas,groups = "qspi_ctrl", "qspi_data4";
                renesas,function = "qspi";
        };
+
+       msiof0_pins: spi1 {
+               renesas,groups = "msiof0_clk", "msiof0_sync", "msiof0_rx",
+                                "msiof0_tx";
+               renesas,function = "msiof0";
+       };
 };
 
 &ether {
                reg = <1>;
                interrupt-parent = <&irqc0>;
                interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               micrel,led-mode = <1>;
        };
 };
 
        status = "okay";
 };
 
-&spi {
+&qspi {
        pinctrl-0 = <&qspi_pins>;
        pinctrl-names = "default";
 
                compatible = "spansion,s25fl512s";
                reg = <0>;
                spi-max-frequency = <30000000>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
                m25p,fast-read;
 
                partition@0 {
                };
        };
 };
+
+&msiof0 {
+       pinctrl-0 = <&msiof0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       pmic: pmic@0 {
+               compatible = "renesas,r2a11302ft";
+               reg = <0>;
+               spi-max-frequency = <6000000>;
+               spi-cpol;
+               spi-cpha;
+       };
+};
index 46181708e59c5c7d7e558743983a88efa9622e13..44f03444ef74e62e0e0b50b6db919ed039d8c300 100644 (file)
                i2c3 = &i2c3;
                i2c4 = &i2c4;
                i2c5 = &i2c5;
+               i2c6 = &i2c6;
+               i2c7 = &i2c7;
+               i2c8 = &i2c8;
+               spi0 = &qspi;
+               spi1 = &msiof0;
+               spi2 = &msiof1;
+               spi3 = &msiof2;
        };
 
        cpus {
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0>;
-                       clock-frequency = <1300000000>;
+                       clock-frequency = <1500000000>;
                };
 
                cpu1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <1>;
-                       clock-frequency = <1300000000>;
+                       clock-frequency = <1500000000>;
                };
        };
 
                             <0 17 IRQ_TYPE_LEVEL_HIGH>;
        };
 
+       /* The memory map in the User's Manual maps the cores to bus numbers */
        i2c0: i2c@e6508000 {
                #address-cells = <1>;
                #size-cells = <0>;
        };
 
        i2c5: i2c@e6528000 {
+               /* doesn't need pinmux */
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "renesas,i2c-r8a7791";
                status = "disabled";
        };
 
+       i2c6: i2c@e60b0000 {
+               /* doesn't need pinmux */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7791", "renesas,rmobile-iic";
+               reg = <0 0xe60b0000 0 0x425>;
+               interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp9_clks R8A7791_CLK_IICDVFS>;
+               status = "disabled";
+       };
+
+       i2c7: i2c@e6500000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7791", "renesas,rmobile-iic";
+               reg = <0 0xe6500000 0 0x425>;
+               interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp3_clks R8A7791_CLK_IIC0>;
+               status = "disabled";
+       };
+
+       i2c8: i2c@e6510000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "renesas,iic-r8a7791", "renesas,rmobile-iic";
+               reg = <0 0xe6510000 0 0x425>;
+               interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp3_clks R8A7791_CLK_IIC1>;
+               status = "disabled";
+       };
+
        pfc: pfc@e6060000 {
                compatible = "renesas,pfc-r8a7791";
                reg = <0 0xe6060000 0 0x250>;
                        renesas,clock-indices = <
                                R8A7791_CLK_TMU1 R8A7791_CLK_TMU3 R8A7791_CLK_TMU2
                                R8A7791_CLK_CMT0 R8A7791_CLK_TMU0 R8A7791_CLK_VSP1_DU1
-                               R8A7791_CLK_VSP1_DU0 R8A7791_CLK_VSP1_SY
+                               R8A7791_CLK_VSP1_DU0 R8A7791_CLK_VSP1_S
                        >;
                        clock-output-names =
                                "tmu1", "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1",
                mstp3_clks: mstp3_clks@e615013c {
                        compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
-                       clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>,
-                               <&cpg_clocks R8A7791_CLK_SD0>, <&mmc0_clk>, <&rclk_clk>;
+                       clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>, <&cpg_clocks R8A7791_CLK_SD0>,
+                                <&mmc0_clk>, <&hp_clk>, <&hp_clk>, <&rclk_clk>;
                        #clock-cells = <1>;
                        renesas,clock-indices = <
-                               R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1
-                               R8A7791_CLK_SDHI0 R8A7791_CLK_MMCIF0 R8A7791_CLK_CMT1
+                               R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1 R8A7791_CLK_SDHI0
+                               R8A7791_CLK_MMCIF0 R8A7791_CLK_IIC0 R8A7791_CLK_IIC1 R8A7791_CLK_CMT1
                        >;
                        clock-output-names =
-                               "tpu0", "sdhi2", "sdhi1", "sdhi0", "mmcif0", "cmt1";
+                               "tpu0", "sdhi2", "sdhi1", "sdhi0",
+                               "mmcif0", "i2c7", "i2c8", "cmt1";
                };
                mstp5_clks: mstp5_clks@e6150144 {
                        compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
                mstp7_clks: mstp7_clks@e615014c {
                        compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
-                       clocks = <&mp_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>,
+                       clocks = <&mp_clk>,  <&mp_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>,
                                 <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
                                 <&zx_clk>, <&zx_clk>, <&zx_clk>;
                        #clock-cells = <1>;
                        renesas,clock-indices = <
-                               R8A7791_CLK_HSUSB R8A7791_CLK_HSCIF2 R8A7791_CLK_SCIF5
+                               R8A7791_CLK_EHCI R8A7791_CLK_HSUSB R8A7791_CLK_HSCIF2 R8A7791_CLK_SCIF5
                                R8A7791_CLK_SCIF4 R8A7791_CLK_HSCIF1 R8A7791_CLK_HSCIF0
                                R8A7791_CLK_SCIF3 R8A7791_CLK_SCIF2 R8A7791_CLK_SCIF1
                                R8A7791_CLK_SCIF0 R8A7791_CLK_DU1 R8A7791_CLK_DU0
                                R8A7791_CLK_LVDS0
                        >;
                        clock-output-names =
-                               "hsusb", "hscif2", "scif5", "scif4", "hscif1", "hscif0",
+                               "ehci", "hsusb", "hscif2", "scif5", "scif4", "hscif1", "hscif0",
                                "scif3", "scif2", "scif1", "scif0", "du1", "du0", "lvds0";
                };
                mstp8_clks: mstp8_clks@e6150990 {
                mstp9_clks: mstp9_clks@e6150994 {
                        compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>;
-                       clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7791_CLK_QSPI>,
-                                <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
-                                <&p_clk>;
+                       clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7791_CLK_QSPI>, <&hp_clk>,
+                                <&cp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>,
+                                <&hp_clk>, <&hp_clk>;
                        #clock-cells = <1>;
                        renesas,clock-indices = <
-                               R8A7791_CLK_RCAN1 R8A7791_CLK_RCAN0 R8A7791_CLK_QSPI_MOD
-                               R8A7791_CLK_I2C5 R8A7791_CLK_I2C4 R8A7791_CLK_I2C3
-                               R8A7791_CLK_I2C2 R8A7791_CLK_I2C1 R8A7791_CLK_I2C0
+                               R8A7791_CLK_RCAN1 R8A7791_CLK_RCAN0 R8A7791_CLK_QSPI_MOD R8A7791_CLK_I2C5
+                               R8A7791_CLK_IICDVFS R8A7791_CLK_I2C4 R8A7791_CLK_I2C3 R8A7791_CLK_I2C2
+                               R8A7791_CLK_I2C1 R8A7791_CLK_I2C0
                        >;
                        clock-output-names =
-                               "rcan1", "rcan0", "qspi_mod", "i2c5", "i2c4", "i2c3",
+                               "rcan1", "rcan0", "qspi_mod", "i2c5", "i2c6", "i2c4", "i2c3",
                                "i2c2", "i2c1", "i2c0";
                };
                mstp11_clks: mstp11_clks@e615099c {
                };
        };
 
-       spi: spi@e6b10000 {
+       qspi: spi@e6b10000 {
                compatible = "renesas,qspi-r8a7791", "renesas,qspi";
                reg = <0 0xe6b10000 0 0x2c>;
                interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
                #size-cells = <0>;
                status = "disabled";
        };
+
+       msiof0: spi@e6e20000 {
+               compatible = "renesas,msiof-r8a7791";
+               reg = <0 0xe6e20000 0 0x0064>;
+               interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       msiof1: spi@e6e10000 {
+               compatible = "renesas,msiof-r8a7791";
+               reg = <0 0xe6e10000 0 0x0064>;
+               interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp2_clks R8A7791_CLK_MSIOF1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       msiof2: spi@e6e00000 {
+               compatible = "renesas,msiof-r8a7791";
+               reg = <0 0xe6e00000 0 0x0064>;
+               interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp2_clks R8A7791_CLK_MSIOF2>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
 };
index 59594cf15998bc43d46442faa9e7c964952b75d7..ea92fd69529a5be3573a07a028aad7e87e02be9c 100644 (file)
                reg =  <0x30000000 0x4000000>;
        };
 
+       clocks {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               xti: xti {
+                       compatible = "fixed-clock";
+                       clock-frequency = <12000000>;
+                       clock-output-names = "xti";
+                       #clock-cells = <0>;
+               };
+       };
+
        serial@50000000 {
                status = "okay";
                pinctrl-names = "default";
index e6555bdd81b8876a66743ecc117ee777416dd32a..955e4a4f8c31ccb8a1bfe367d7511402e5e730e8 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <dt-bindings/clock/s3c2443.h>
 #include "s3c24xx.dtsi"
 #include "s3c2416-pinctrl.dtsi"
 
                compatible = "samsung,s3c2416-irq";
        };
 
+       clocks: clock-controller@0x4c000000 {
+               compatible = "samsung,s3c2416-clock";
+               reg = <0x4c000000 0x40>;
+               #clock-cells = <1>;
+       };
+
        pinctrl@56000000 {
                compatible = "samsung,s3c2416-pinctrl";
        };
 
+       timer@51000000 {
+               clocks = <&clocks PCLK_PWM>;
+               clock-names = "timers";
+       };
+
        serial@50000000 {
                compatible = "samsung,s3c2440-uart";
+               clock-names = "uart", "clk_uart_baud2",
+                               "clk_uart_baud3";
+               clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>,
+                               <&clocks SCLK_UART>;
        };
 
        serial@50004000 {
                compatible = "samsung,s3c2440-uart";
+               clock-names = "uart", "clk_uart_baud2",
+                               "clk_uart_baud3";
+               clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>,
+                               <&clocks SCLK_UART>;
        };
 
        serial@50008000 {
                compatible = "samsung,s3c2440-uart";
+               clock-names = "uart", "clk_uart_baud2",
+                               "clk_uart_baud3";
+               clocks = <&clocks PCLK_UART2>, <&clocks PCLK_UART2>,
+                               <&clocks SCLK_UART>;
        };
 
        serial@5000C000 {
                compatible = "samsung,s3c2440-uart";
                reg = <0x5000C000 0x4000>;
                interrupts = <1 18 24 4>, <1 18 25 4>;
+               clock-names = "uart", "clk_uart_baud2",
+                               "clk_uart_baud3";
+               clocks = <&clocks PCLK_UART3>, <&clocks PCLK_UART3>,
+                               <&clocks SCLK_UART>;
                status = "disabled";
        };
 
                compatible = "samsung,s3c6410-sdhci";
                reg = <0x4AC00000 0x100>;
                interrupts = <0 0 21 3>;
+               clock-names = "hsmmc", "mmc_busclk.0",
+                               "mmc_busclk.2";
+               clocks = <&clocks HCLK_HSMMC0>, <&clocks HCLK_HSMMC0>,
+                               <&clocks MUX_HSMMC0>;
                status = "disabled";
        };
 
                compatible = "samsung,s3c6410-sdhci";
                reg = <0x4A800000 0x100>;
                interrupts = <0 0 20 3>;
+               clock-names = "hsmmc", "mmc_busclk.0",
+                               "mmc_busclk.2";
+               clocks = <&clocks HCLK_HSMMC1>, <&clocks HCLK_HSMMC1>,
+                               <&clocks MUX_HSMMC1>;
                status = "disabled";
        };
 
        watchdog@53000000 {
                interrupts = <1 9 27 3>;
+               clocks = <&clocks PCLK_WDT>;
+               clock-names = "watchdog";
        };
 
        rtc@57000000 {
                compatible = "samsung,s3c2416-rtc";
+               clocks = <&clocks PCLK_RTC>;
+               clock-names = "rtc";
        };
 
        i2c@54000000 {
                compatible = "samsung,s3c2440-i2c";
+               clocks = <&clocks PCLK_I2C0>;
+               clock-names = "i2c";
        };
 };
index eabcfdbb403acc7ff40b409617a53c9831414c04..1c7caeb87a9518b5916fb4c8b0bfce46ff7f0361 100644 (file)
@@ -13,7 +13,7 @@
 #include <dt-bindings/pinctrl/at91.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/clk/at91.h>
+#include <dt-bindings/clock/at91.h>
 
 / {
        model = "Atmel SAMA5D3 family SoC";
                                compatible = "atmel,at91sam9g45-ssc";
                                reg = <0xf0008000 0x4000>;
                                interrupts = <38 IRQ_TYPE_LEVEL_HIGH 4>;
+                               dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(13)>,
+                                      <&dma0 2 AT91_DMA_CFG_PER_ID(14)>;
+                               dma-names = "tx", "rx";
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
                                clocks = <&ssc0_clk>;
                                compatible = "atmel,at91sam9g45-ssc";
                                reg = <0xf800c000 0x4000>;
                                interrupts = <39 IRQ_TYPE_LEVEL_HIGH 4>;
+                               dmas = <&dma1 2 AT91_DMA_CFG_PER_ID(3)>,
+                                      <&dma1 2 AT91_DMA_CFG_PER_ID(4)>;
+                               dma-names = "tx", "rx";
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>;
                                clocks = <&ssc1_clk>;
index b029fe7ef17a657946de4d2fe71168b4b03210d8..1b02208ea6ff2b70aab43ddd416b37ef0b9a2a1f 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <dt-bindings/pinctrl/at91.h>
 #include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/clk/at91.h>
+#include <dt-bindings/clock/at91.h>
 
 / {
        ahb {
index 382b04431f66b621e01a9f2fe7a9e488ac4c171b..02848453ca0cf5447de27aaca6b233611173da4e 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <dt-bindings/pinctrl/at91.h>
 #include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/clk/at91.h>
+#include <dt-bindings/clock/at91.h>
 
 / {
        aliases {
index a9fa75e4165205f9a1259f9a0821519faee54070..7a8d4c6115f72fdab533980a0f0d96eb6cb1469a 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <dt-bindings/pinctrl/at91.h>
 #include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/clk/at91.h>
+#include <dt-bindings/clock/at91.h>
 
 / {
        aliases {
index dba739b6ef36faa57fc630708f7deb8903c1c4d5..306eef0f97ef21fc51a0410d2e2a6d59186986b8 100644 (file)
                                };
                        };
 
+                       ssc0: ssc@f0008000 {
+                               atmel,clk-from-rk-pin;
+                       };
+
                        /*
                         * i2c0 conflicts with ISI:
                         * disable it to allow the use of ISI
        };
 
        sound {
-               compatible = "atmel,sama5d3ek-wm8904";
+               compatible = "atmel,asoc-wm8904";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_pck0_as_audio_mck>;
 
                        "Headphone Jack", "HPOUTR",
                        "IN2L", "Line In Jack",
                        "IN2R", "Line In Jack",
+                       "MICBIAS", "IN1L",
                        "IN1L", "Mic";
 
                atmel,ssc-controller = <&ssc0>;
                atmel,audio-codec = <&wm8904>;
+
+               status = "disabled";
        };
 };
index eb8886b535e4a28345ac5ae848ce85de47fcbbe4..a99171c8a78222f97497b4d1de6f3897e2e5fca1 100644 (file)
@@ -14,6 +14,7 @@
 /dts-v1/;
 #include "sh73a0.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 / {
 
                back-key {
                        gpios = <&pcf8575 8 GPIO_ACTIVE_LOW>;
-                       linux,code = <158>;
+                       linux,code = <KEY_BACK>;
                        label = "SW3";
                };
 
                right-key {
                        gpios = <&pcf8575 9 GPIO_ACTIVE_LOW>;
-                       linux,code = <106>;
+                       linux,code = <KEY_RIGHT>;
                        label = "SW2-R";
                };
 
                left-key {
                        gpios = <&pcf8575 10 GPIO_ACTIVE_LOW>;
-                       linux,code = <105>;
+                       linux,code = <KEY_LEFT>;
                        label = "SW2-L";
                };
 
                enter-key {
                        gpios = <&pcf8575 11 GPIO_ACTIVE_LOW>;
-                       linux,code = <28>;
+                       linux,code = <KEY_ENTER>;
                        label = "SW2-P";
                };
 
                up-key {
                        gpios = <&pcf8575 12 GPIO_ACTIVE_LOW>;
-                       linux,code = <103>;
+                       linux,code = <KEY_UP>;
                        label = "SW2-U";
                };
 
                down-key {
                        gpios = <&pcf8575 13 GPIO_ACTIVE_LOW>;
-                       linux,code = <108>;
+                       linux,code = <KEY_DOWN>;
                        label = "SW2-D";
                };
 
                home-key {
                        gpios = <&pcf8575 14 GPIO_ACTIVE_LOW>;
-                       linux,code = <102>;
+                       linux,code = <KEY_HOME>;
                        label = "SW1";
                };
        };
index f09fb10a3791a7e4fc238f4e47548fc7f86da705..81df870e5ee6791530b3902aab65ea6576bf47f8 100644 (file)
@@ -49,7 +49,7 @@
                        reg             = <0xfe61f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfe610000 0x5000>;
 
                        PIO0: gpio@fe610000 {
                        reg             = <0xfee0f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfee00000 0x8000>;
 
                        PIO5: gpio@fee00000 {
                        reg             = <0xfe82f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfe820000 0x8000>;
 
                        PIO13: gpio@fe820000 {
                        reg             = <0xfd6bf080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfd6b0000 0x3000>;
 
                        PIO100: gpio@fd6b0000 {
                        reg             = <0xfd33f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfd330000 0x5000>;
 
                        PIO103: gpio@fd330000 {
index aeea304086eb3b57c5682539643f0d6ca4540c0d..250d5ecc951ea0e3e5c7f071fb4e38b6312840d7 100644 (file)
@@ -53,7 +53,7 @@
                        reg             = <0xfe61f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfe610000 0x6000>;
 
                        PIO0: gpio@fe610000 {
                        reg             = <0xfee0f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfee00000 0x10000>;
 
                        PIO5: gpio@fee00000 {
                        reg             = <0xfe82f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfe820000 0x6000>;
 
                        PIO13: gpio@fe820000 {
                        reg             = <0xfd6bf080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges          = <0 0xfd6b0000 0x3000>;
 
                        PIO100: gpio@fd6b0000 {
                        reg             = <0xfd33f080 0x4>;
                        reg-names       = "irqmux";
                        interrupts      = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupts-names = "irqmux";
+                       interrupt-names = "irqmux";
                        ranges                  = <0 0xfd330000 0x5000>;
 
                        PIO103: gpio@fd330000 {
index a288a12823ed84a1ba42ffae2a1a4e9bd0cd61b6..5c21d216515a3d5a06b76a4b449cc72ef208b6af 100644 (file)
@@ -25,6 +25,7 @@
                hdmi@54280000 {
                        status = "okay";
 
+                       hdmi-supply = <&vdd_5v0_hdmi>;
                        vdd-supply = <&vdd_hdmi_reg>;
                        pll-supply = <&palmas_smps3_reg>;
 
@@ -36,6 +37,8 @@
                dsi@54300000 {
                        status = "okay";
 
+                       avdd-dsi-csi-supply = <&avdd_1v2_reg>;
+
                        panel@0 {
                                compatible = "panasonic,vvx10f004b00",
                                             "simple-panel";
                                                regulator-max-microvolt = <2800000>;
                                        };
 
-                                       ldo3 {
+                                       avdd_1v2_reg: ldo3 {
                                                regulator-name = "avdd-dsi-csi";
                                                regulator-min-microvolt = <1200000>;
                                                regulator-max-microvolt = <1200000>;
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
                                        ldo4 {
 
        sdhci@78000400 {
                cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
+               wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>;
                bus-width = <4>;
                status = "okay";
        };
                        regulator-name = "vdd_hdmi_5v0";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
-                       enable-active-high;
-                       gpio = <&gpio TEGRA_GPIO(K, 1) GPIO_ACTIVE_HIGH>;
                        vin-supply = <&tps65090_dcdc1_reg>;
                };
 
                        enable-active-high;
                        gpio = <&palmas_gpio 6 0>;
                };
+
+               vdd_5v0_hdmi: regulator@7 {
+                       compatible = "regulator-fixed";
+                       reg = <7>;
+                       regulator-name = "VDD_5V0_HDMI_CON";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio TEGRA_GPIO(K, 1) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&tps65090_dcdc1_reg>;
+               };
        };
 
        sound {
diff --git a/arch/arm/boot/dts/tegra114-tn7.dts b/arch/arm/boot/dts/tegra114-tn7.dts
new file mode 100644 (file)
index 0000000..9636621
--- /dev/null
@@ -0,0 +1,348 @@
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "tegra114.dtsi"
+
+/ {
+       model = "Tegra Note 7";
+       compatible = "nvidia,tn7", "nvidia,tegra114";
+
+       chosen {
+               /* TN7's bootloader's arguments need to be overridden */
+               bootargs = "console=ttyS0,115200n8 console=tty1 gpt fbcon=rotate:2";
+               /* TN7's bootloader will place initrd at this address */
+               linux,initrd-start = <0x82000000>;
+               linux,initrd-end = <0x82800000>;
+       };
+
+       firmware {
+               trusted-foundations {
+                       compatible = "tlm,trusted-foundations";
+                       tlm,version-major = <2>;
+                       tlm,version-minor = <8>;
+               };
+       };
+
+       memory {
+               /* memory >= 0x37e00000 is reserved for firmware usage */
+               reg = <0x80000000 0x37e00000>;
+       };
+
+       host1x@50000000 {
+               dsi@54300000 {
+                       status = "okay";
+
+                       vdd-supply = <&vdd_1v2_ap>;
+
+                       panel@0 {
+                               compatible = "lg,ld070wx3-sl01";
+                               reg = <0>;
+
+                               power-supply = <&vdd_lcd>;
+                               backlight = <&backlight>;
+                       };
+               };
+       };
+
+       serial@70006300 {
+               status = "okay";
+       };
+
+       pwm@7000a000 {
+               status = "okay";
+       };
+
+       i2c@7000d000 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               palmas: pmic@58 {
+                       compatible = "ti,palmas";
+                       reg = <0x58>;
+                       interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_LOW>;
+
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+
+                       ti,system-power-controller;
+
+                       palmas_gpio: gpio {
+                               compatible = "ti,palmas-gpio";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                       };
+
+                       pmic {
+                               compatible = "ti,tps65913-pmic", "ti,palmas-pmic";
+
+                               ldoln-in-supply = <&vdd_smps10_out2>;
+
+                               regulators {
+                                       smps123 {
+                                               regulator-name = "vd-cpu";
+                                               regulator-min-microvolt = <1000000>;
+                                               regulator-max-microvolt = <1000000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       smps45 {
+                                               regulator-name = "vd-soc";
+                                               regulator-min-microvolt = <1100000>;
+                                               regulator-max-microvolt = <1100000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       smps6 {
+                                               regulator-name = "va-lcd-hv";
+                                               regulator-min-microvolt = <3000000>;
+                                               regulator-max-microvolt = <3000000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       smps7 {
+                                               regulator-name = "vd-ddr";
+                                               regulator-min-microvolt = <1350000>;
+                                               regulator-max-microvolt = <1350000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       vdd_1v8: smps8 {
+                                               regulator-name = "vs-pmu-1v8";
+                                               regulator-min-microvolt = <1800000>;
+                                               regulator-max-microvolt = <1800000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       vdd_2v9_sys: smps9 {
+                                               regulator-name = "vs-sys-2v9";
+                                               regulator-min-microvolt = <2900000>;
+                                               regulator-max-microvolt = <2900000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       vdd_smps10_out1: smps10_out1 {
+                                               regulator-name = "vd-smps10-out1";
+                                               regulator-min-microvolt = <5000000>;
+                                               regulator-max-microvolt = <5000000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       vdd_smps10_out2: smps10_out2 {
+                                               regulator-name = "vd-smps10-out2";
+                                               regulator-min-microvolt = <5000000>;
+                                               regulator-max-microvolt = <5000000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       ldo1 {
+                                               regulator-name = "va-pllx";
+                                               regulator-min-microvolt = <1050000>;
+                                               regulator-max-microvolt = <1050000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       vdd_1v2_ap: ldo2 {
+                                               regulator-name = "va-ap-1v2";
+                                               regulator-min-microvolt = <1200000>;
+                                               regulator-max-microvolt = <1200000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       ldo3 {
+                                               regulator-name = "vd-fuse";
+                                               regulator-min-microvolt = <1800000>;
+                                               regulator-max-microvolt = <1800000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       ldo4 {
+                                               regulator-name = "vd-ts-hv";
+                                               regulator-min-microvolt = <3200000>;
+                                               regulator-max-microvolt = <3200000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       ldo5 {
+                                               regulator-name = "va-cam2-hv";
+                                               regulator-min-microvolt = <2700000>;
+                                               regulator-max-microvolt = <2700000>;
+                                       };
+
+                                       ldo6 {
+                                               regulator-name = "va-sns-hv";
+                                               regulator-min-microvolt = <2850000>;
+                                               regulator-max-microvolt = <2850000>;
+                                       };
+
+                                       ldo7 {
+                                               regulator-name = "va-cam1-hv";
+                                               regulator-min-microvolt = <2700000>;
+                                               regulator-max-microvolt = <2700000>;
+                                       };
+
+                                       ldo8 {
+                                               regulator-name = "va-ap-rtc";
+                                               regulator-min-microvolt = <1100000>;
+                                               regulator-max-microvolt = <1100000>;
+                                               ti,enable-ldo8-tracking;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       ldo9 {
+                                               regulator-name = "vi-sdcard";
+                                               regulator-min-microvolt = <2900000>;
+                                               regulator-max-microvolt = <2900000>;
+                                       };
+
+                                       ldousb {
+                                               regulator-name = "avdd-usb";
+                                               regulator-min-microvolt = <3300000>;
+                                               regulator-max-microvolt = <3300000>;
+                                               regulator-always-on;
+                                               regulator-boot-on;
+                                       };
+
+                                       ldoln {
+                                               regulator-name = "va-hdmi";
+                                               regulator-min-microvolt = <3300000>;
+                                               regulator-max-microvolt = <3300000>;
+                                       };
+                               };
+                       };
+
+                       rtc {
+                               compatible = "ti,palmas-rtc";
+                               interrupt-parent = <&palmas>;
+                               interrupts = <8 0>;
+                       };
+
+               };
+       };
+
+       pmc@7000e400 {
+               nvidia,invert-interrupt;
+       };
+
+       /* eMMC */
+       sdhci@78000600 {
+               status = "okay";
+               bus-width = <8>;
+               vmmc-supply = <&vdd_1v8>;
+               non-removable;
+       };
+
+       usb@7d000000 {
+               status = "okay";
+       };
+
+       usb-phy@7d000000 {
+               status = "okay";
+               nvidia,xcvr-setup = <7>;
+               nvidia,xcvr-lsfslew = <2>;
+               nvidia,xcvr-lsrslew = <2>;
+               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+               /* Should be changed to "otg" once we have vbus_supply */
+               /* As of now, USB devices need to be powered externally */
+               dr_mode = "host";
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 1 40000>;
+
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+
+               power-supply = <&lcd_bl_en>;
+       };
+
+       clocks {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               clk32k_in: clock {
+                       compatible = "fixed-clock";
+                       reg = <0>;
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               power {
+                       label = "Power";
+                       gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+                       gpio-key,wakeup;
+               };
+
+               volume_down {
+                       label = "Volume Down";
+                       gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEDOWN>;
+               };
+
+               volume_up {
+                       label = "Volume Up";
+                       gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* FIXME: output of BQ24192 */
+               vs_sys: regulator@0 {
+                       compatible = "regulator-fixed";
+                       reg = <0>;
+                       regulator-name = "VS_SYS";
+                       regulator-min-microvolt = <4200000>;
+                       regulator-max-microvolt = <4200000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+               };
+
+               lcd_bl_en: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "VDD_LCD_BL";
+                       regulator-min-microvolt = <16500000>;
+                       regulator-max-microvolt = <16500000>;
+                       gpio = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vs_sys>;
+                       regulator-boot-on;
+               };
+
+               vdd_lcd: regulator@2 {
+                       compatible = "regulator-fixed";
+                       reg = <2>;
+                       regulator-name = "VD_LCD_1V8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       gpio = <&palmas_gpio 4 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vdd_1v8>;
+                       regulator-boot-on;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
new file mode 100644 (file)
index 0000000..e31fb61
--- /dev/null
@@ -0,0 +1,1827 @@
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "tegra124.dtsi"
+
+/ {
+       model = "NVIDIA Tegra124 Jetson TK1";
+       compatible = "nvidia,jetson-tk1", "nvidia,tegra124";
+
+       aliases {
+               rtc0 = "/i2c@0,7000d000/pmic@40";
+               rtc1 = "/rtc@0,7000e000";
+       };
+
+       memory {
+               reg = <0x0 0x80000000 0x0 0x80000000>;
+       };
+
+       host1x@0,50000000 {
+               hdmi@0,54280000 {
+                       status = "okay";
+
+                       hdmi-supply = <&vdd_5v0_hdmi>;
+                       pll-supply = <&vdd_hdmi_pll>;
+                       vdd-supply = <&vdd_3v3_hdmi>;
+
+                       nvidia,ddc-i2c-bus = <&hdmi_ddc>;
+                       nvidia,hpd-gpio =
+                               <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       pinmux: pinmux@0,70000868 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&state_default>;
+
+               state_default: pinmux {
+                       clk_32k_out_pa0 {
+                               nvidia,pins = "clk_32k_out_pa0";
+                               nvidia,function = "soc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uart3_cts_n_pa1 {
+                               nvidia,pins = "uart3_cts_n_pa1";
+                               nvidia,function = "uartc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap2_fs_pa2 {
+                               nvidia,pins = "dap2_fs_pa2";
+                               nvidia,function = "i2s1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap2_sclk_pa3 {
+                               nvidia,pins = "dap2_sclk_pa3";
+                               nvidia,function = "i2s1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap2_din_pa4 {
+                               nvidia,pins = "dap2_din_pa4";
+                               nvidia,function = "i2s1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap2_dout_pa5 {
+                               nvidia,pins = "dap2_dout_pa5";
+                               nvidia,function = "i2s1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_clk_pa6 {
+                               nvidia,pins = "sdmmc3_clk_pa6";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       sdmmc3_cmd_pa7 {
+                               nvidia,pins = "sdmmc3_cmd_pa7";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pb0 {
+                               nvidia,pins = "pb0";
+                               nvidia,function = "uartd";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pb1 {
+                               nvidia,pins = "pb1";
+                               nvidia,function = "uartd";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_dat3_pb4 {
+                               nvidia,pins = "sdmmc3_dat3_pb4";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_dat2_pb5 {
+                               nvidia,pins = "sdmmc3_dat2_pb5";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_dat1_pb6 {
+                               nvidia,pins = "sdmmc3_dat1_pb6";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_dat0_pb7 {
+                               nvidia,pins = "sdmmc3_dat0_pb7";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uart3_rts_n_pc0 {
+                               nvidia,pins = "uart3_rts_n_pc0";
+                               nvidia,function = "uartc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       uart2_txd_pc2 {
+                               nvidia,pins = "uart2_txd_pc2";
+                               nvidia,function = "irda";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       uart2_rxd_pc3 {
+                               nvidia,pins = "uart2_rxd_pc3";
+                               nvidia,function = "irda";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       gen1_i2c_scl_pc4 {
+                               nvidia,pins = "gen1_i2c_scl_pc4";
+                               nvidia,function = "i2c1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       gen1_i2c_sda_pc5 {
+                               nvidia,pins = "gen1_i2c_sda_pc5";
+                               nvidia,function = "i2c1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       pc7 {
+                               nvidia,pins = "pc7";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pg0 {
+                               nvidia,pins = "pg0";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pg1 {
+                               nvidia,pins = "pg1";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pg2 {
+                               nvidia,pins = "pg2";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pg3 {
+                               nvidia,pins = "pg3";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pg4 {
+                               nvidia,pins = "pg4";
+                               nvidia,function = "spi4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pg5 {
+                               nvidia,pins = "pg5";
+                               nvidia,function = "spi4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pg6 {
+                               nvidia,pins = "pg6";
+                               nvidia,function = "spi4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pg7 {
+                               nvidia,pins = "pg7";
+                               nvidia,function = "spi4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ph0 {
+                               nvidia,pins = "ph0";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ph1 {
+                               nvidia,pins = "ph1";
+                               nvidia,function = "pwm1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ph2 {
+                               nvidia,pins = "ph2";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ph3 {
+                               nvidia,pins = "ph3";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ph4 {
+                               nvidia,pins = "ph4";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ph5 {
+                               nvidia,pins = "ph5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ph6 {
+                               nvidia,pins = "ph6";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ph7 {
+                               nvidia,pins = "ph7";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pi0 {
+                               nvidia,pins = "pi0";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pi1 {
+                               nvidia,pins = "pi1";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pi2 {
+                               nvidia,pins = "pi2";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pi3 {
+                               nvidia,pins = "pi3";
+                               nvidia,function = "spi4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pi4 {
+                               nvidia,pins = "pi4";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pi5 {
+                               nvidia,pins = "pi5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pi6 {
+                               nvidia,pins = "pi6";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pi7 {
+                               nvidia,pins = "pi7";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pj0 {
+                               nvidia,pins = "pj0";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pj2 {
+                               nvidia,pins = "pj2";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uart2_cts_n_pj5 {
+                               nvidia,pins = "uart2_cts_n_pj5";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uart2_rts_n_pj6 {
+                               nvidia,pins = "uart2_rts_n_pj6";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pj7 {
+                               nvidia,pins = "pj7";
+                               nvidia,function = "uartd";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pk0 {
+                               nvidia,pins = "pk0";
+                               nvidia,function = "soc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pk1 {
+                               nvidia,pins = "pk1";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pk2 {
+                               nvidia,pins = "pk2";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pk3 {
+                               nvidia,pins = "pk3";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pk4 {
+                               nvidia,pins = "pk4";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       spdif_out_pk5 {
+                               nvidia,pins = "spdif_out_pk5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       spdif_in_pk6 {
+                               nvidia,pins = "spdif_in_pk6";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pk7 {
+                               nvidia,pins = "pk7";
+                               nvidia,function = "uartd";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap1_fs_pn0 {
+                               nvidia,pins = "dap1_fs_pn0";
+                               nvidia,function = "i2s0";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap1_din_pn1 {
+                               nvidia,pins = "dap1_din_pn1";
+                               nvidia,function = "i2s0";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap1_dout_pn2 {
+                               nvidia,pins = "dap1_dout_pn2";
+                               nvidia,function = "sata";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap1_sclk_pn3 {
+                               nvidia,pins = "dap1_sclk_pn3";
+                               nvidia,function = "i2s0";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       usb_vbus_en0_pn4 {
+                               nvidia,pins = "usb_vbus_en0_pn4";
+                               nvidia,function = "usb";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       usb_vbus_en1_pn5 {
+                               nvidia,pins = "usb_vbus_en1_pn5";
+                               nvidia,function = "usb";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       hdmi_int_pn7 {
+                               nvidia,pins = "hdmi_int_pn7";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,rcv-sel = <TEGRA_PIN_DISABLE>;
+                       };
+                       ulpi_data7_po0 {
+                               nvidia,pins = "ulpi_data7_po0";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_data0_po1 {
+                               nvidia,pins = "ulpi_data0_po1";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_data1_po2 {
+                               nvidia,pins = "ulpi_data1_po2";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_data2_po3 {
+                               nvidia,pins = "ulpi_data2_po3";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_data3_po4 {
+                               nvidia,pins = "ulpi_data3_po4";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_data4_po5 {
+                               nvidia,pins = "ulpi_data4_po5";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_data5_po6 {
+                               nvidia,pins = "ulpi_data5_po6";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ulpi_data6_po7 {
+                               nvidia,pins = "ulpi_data6_po7";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap3_fs_pp0 {
+                               nvidia,pins = "dap3_fs_pp0";
+                               nvidia,function = "i2s2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap3_din_pp1 {
+                               nvidia,pins = "dap3_din_pp1";
+                               nvidia,function = "i2s2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap3_dout_pp2 {
+                               nvidia,pins = "dap3_dout_pp2";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap3_sclk_pp3 {
+                               nvidia,pins = "dap3_sclk_pp3";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap4_fs_pp4 {
+                               nvidia,pins = "dap4_fs_pp4";
+                               nvidia,function = "i2s3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap4_din_pp5 {
+                               nvidia,pins = "dap4_din_pp5";
+                               nvidia,function = "i2s3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap4_dout_pp6 {
+                               nvidia,pins = "dap4_dout_pp6";
+                               nvidia,function = "i2s3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap4_sclk_pp7 {
+                               nvidia,pins = "dap4_sclk_pp7";
+                               nvidia,function = "i2s3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col0_pq0 {
+                               nvidia,pins = "kb_col0_pq0";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col1_pq1 {
+                               nvidia,pins = "kb_col1_pq1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col2_pq2 {
+                               nvidia,pins = "kb_col2_pq2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col3_pq3 {
+                               nvidia,pins = "kb_col3_pq3";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_col4_pq4 {
+                               nvidia,pins = "kb_col4_pq4";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col5_pq5 {
+                               nvidia,pins = "kb_col5_pq5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col6_pq6 {
+                               nvidia,pins = "kb_col6_pq6";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_col7_pq7 {
+                               nvidia,pins = "kb_col7_pq7";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row0_pr0 {
+                               nvidia,pins = "kb_row0_pr0";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row1_pr1 {
+                               nvidia,pins = "kb_row1_pr1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row2_pr2 {
+                               nvidia,pins = "kb_row2_pr2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row3_pr3 {
+                               nvidia,pins = "kb_row3_pr3";
+                               nvidia,function = "sys";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row4_pr4 {
+                               nvidia,pins = "kb_row4_pr4";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row5_pr5 {
+                               nvidia,pins = "kb_row5_pr5";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row6_pr6 {
+                               nvidia,pins = "kb_row6_pr6";
+                               nvidia,function = "displaya_alt";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row7_pr7 {
+                               nvidia,pins = "kb_row7_pr7";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row8_ps0 {
+                               nvidia,pins = "kb_row8_ps0";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row9_ps1 {
+                               nvidia,pins = "kb_row9_ps1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row10_ps2 {
+                               nvidia,pins = "kb_row10_ps2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row11_ps3 {
+                               nvidia,pins = "kb_row11_ps3";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row12_ps4 {
+                               nvidia,pins = "kb_row12_ps4";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row13_ps5 {
+                               nvidia,pins = "kb_row13_ps5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row14_ps6 {
+                               nvidia,pins = "kb_row14_ps6";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row15_ps7 {
+                               nvidia,pins = "kb_row15_ps7";
+                               nvidia,function = "soc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       kb_row16_pt0 {
+                               nvidia,pins = "kb_row16_pt0";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       kb_row17_pt1 {
+                               nvidia,pins = "kb_row17_pt1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gen2_i2c_scl_pt5 {
+                               nvidia,pins = "gen2_i2c_scl_pt5";
+                               nvidia,function = "i2c2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       gen2_i2c_sda_pt6 {
+                               nvidia,pins = "gen2_i2c_sda_pt6";
+                               nvidia,function = "i2c2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_cmd_pt7 {
+                               nvidia,pins = "sdmmc4_cmd_pt7";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pu0 {
+                               nvidia,pins = "pu0";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pu1 {
+                               nvidia,pins = "pu1";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pu2 {
+                               nvidia,pins = "pu2";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pu3 {
+                               nvidia,pins = "pu3";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pu4 {
+                               nvidia,pins = "pu4";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pu5 {
+                               nvidia,pins = "pu5";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pu6 {
+                               nvidia,pins = "pu6";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pv0 {
+                               nvidia,pins = "pv0";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pv1 {
+                               nvidia,pins = "pv1";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_cd_n_pv2 {
+                               nvidia,pins = "sdmmc3_cd_n_pv2";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1_wp_n_pv3 {
+                               nvidia,pins = "sdmmc1_wp_n_pv3";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ddc_scl_pv4 {
+                               nvidia,pins = "ddc_scl_pv4";
+                               nvidia,function = "i2c4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,rcv-sel = <TEGRA_PIN_DISABLE>;
+                       };
+                       ddc_sda_pv5 {
+                               nvidia,pins = "ddc_sda_pv5";
+                               nvidia,function = "i2c4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,rcv-sel = <TEGRA_PIN_DISABLE>;
+                       };
+                       gpio_w2_aud_pw2 {
+                               nvidia,pins = "gpio_w2_aud_pw2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       gpio_w3_aud_pw3 {
+                               nvidia,pins = "gpio_w3_aud_pw3";
+                               nvidia,function = "spi6";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap_mclk1_pw4 {
+                               nvidia,pins = "dap_mclk1_pw4";
+                               nvidia,function = "extperiph1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       clk2_out_pw5 {
+                               nvidia,pins = "clk2_out_pw5";
+                               nvidia,function = "extperiph2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       uart3_txd_pw6 {
+                               nvidia,pins = "uart3_txd_pw6";
+                               nvidia,function = "uartc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       uart3_rxd_pw7 {
+                               nvidia,pins = "uart3_rxd_pw7";
+                               nvidia,function = "uartc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dvfs_pwm_px0 {
+                               nvidia,pins = "dvfs_pwm_px0";
+                               nvidia,function = "cldvfs";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gpio_x1_aud_px1 {
+                               nvidia,pins = "gpio_x1_aud_px1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dvfs_clk_px2 {
+                               nvidia,pins = "dvfs_clk_px2";
+                               nvidia,function = "cldvfs";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gpio_x3_aud_px3 {
+                               nvidia,pins = "gpio_x3_aud_px3";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       gpio_x4_aud_px4 {
+                               nvidia,pins = "gpio_x4_aud_px4";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gpio_x5_aud_px5 {
+                               nvidia,pins = "gpio_x5_aud_px5";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       gpio_x6_aud_px6 {
+                               nvidia,pins = "gpio_x6_aud_px6";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       gpio_x7_aud_px7 {
+                               nvidia,pins = "gpio_x7_aud_px7";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ulpi_clk_py0 {
+                               nvidia,pins = "ulpi_clk_py0";
+                               nvidia,function = "spi1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ulpi_dir_py1 {
+                               nvidia,pins = "ulpi_dir_py1";
+                               nvidia,function = "spi1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ulpi_nxt_py2 {
+                               nvidia,pins = "ulpi_nxt_py2";
+                               nvidia,function = "spi1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ulpi_stp_py3 {
+                               nvidia,pins = "ulpi_stp_py3";
+                               nvidia,function = "spi1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       sdmmc1_dat3_py4 {
+                               nvidia,pins = "sdmmc1_dat3_py4";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1_dat2_py5 {
+                               nvidia,pins = "sdmmc1_dat2_py5";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1_dat1_py6 {
+                               nvidia,pins = "sdmmc1_dat1_py6";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1_dat0_py7 {
+                               nvidia,pins = "sdmmc1_dat0_py7";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1_clk_pz0 {
+                               nvidia,pins = "sdmmc1_clk_pz0";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1_cmd_pz1 {
+                               nvidia,pins = "sdmmc1_cmd_pz1";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pwr_i2c_scl_pz6 {
+                               nvidia,pins = "pwr_i2c_scl_pz6";
+                               nvidia,function = "i2cpwr";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       pwr_i2c_sda_pz7 {
+                               nvidia,pins = "pwr_i2c_sda_pz7";
+                               nvidia,function = "i2cpwr";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat0_paa0 {
+                               nvidia,pins = "sdmmc4_dat0_paa0";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat1_paa1 {
+                               nvidia,pins = "sdmmc4_dat1_paa1";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat2_paa2 {
+                               nvidia,pins = "sdmmc4_dat2_paa2";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat3_paa3 {
+                               nvidia,pins = "sdmmc4_dat3_paa3";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat4_paa4 {
+                               nvidia,pins = "sdmmc4_dat4_paa4";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat5_paa5 {
+                               nvidia,pins = "sdmmc4_dat5_paa5";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat6_paa6 {
+                               nvidia,pins = "sdmmc4_dat6_paa6";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_dat7_paa7 {
+                               nvidia,pins = "sdmmc4_dat7_paa7";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pbb0 {
+                               nvidia,pins = "pbb0";
+                               nvidia,function = "vimclk2_alt";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       cam_i2c_scl_pbb1 {
+                               nvidia,pins = "cam_i2c_scl_pbb1";
+                               nvidia,function = "i2c3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       cam_i2c_sda_pbb2 {
+                               nvidia,pins = "cam_i2c_sda_pbb2";
+                               nvidia,function = "i2c3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       pbb3 {
+                               nvidia,pins = "pbb3";
+                               nvidia,function = "vgp3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pbb4 {
+                               nvidia,pins = "pbb4";
+                               nvidia,function = "vgp4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pbb5 {
+                               nvidia,pins = "pbb5";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pbb6 {
+                               nvidia,pins = "pbb6";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pbb7 {
+                               nvidia,pins = "pbb7";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       cam_mclk_pcc0 {
+                               nvidia,pins = "cam_mclk_pcc0";
+                               nvidia,function = "vi_alt3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pcc1 {
+                               nvidia,pins = "pcc1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       pcc2 {
+                               nvidia,pins = "pcc2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4_clk_pcc4 {
+                               nvidia,pins = "sdmmc4_clk_pcc4";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       clk2_req_pcc5 {
+                               nvidia,pins = "clk2_req_pcc5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       clk3_out_pee0 {
+                               nvidia,pins = "clk3_out_pee0";
+                               nvidia,function = "extperiph3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       clk3_req_pee1 {
+                               nvidia,pins = "clk3_req_pee1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap_mclk1_req_pee2 {
+                               nvidia,pins = "dap_mclk1_req_pee2";
+                               nvidia,function = "sata";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       hdmi_cec_pee3 {
+                               nvidia,pins = "hdmi_cec_pee3";
+                               nvidia,function = "cec";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_clk_lb_out_pee4 {
+                               nvidia,pins = "sdmmc3_clk_lb_out_pee4";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3_clk_lb_in_pee5 {
+                               nvidia,pins = "sdmmc3_clk_lb_in_pee5";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dp_hpd_pff0 {
+                               nvidia,pins = "dp_hpd_pff0";
+                               nvidia,function = "dp";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       usb_vbus_en2_pff1 {
+                               nvidia,pins = "usb_vbus_en2_pff1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_DISABLE>;
+                       };
+                       pff2 {
+                               nvidia,pins = "pff2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_DISABLE>;
+                       };
+                       core_pwr_req {
+                               nvidia,pins = "core_pwr_req";
+                               nvidia,function = "pwron";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       cpu_pwr_req {
+                               nvidia,pins = "cpu_pwr_req";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pwr_int_n {
+                               nvidia,pins = "pwr_int_n";
+                               nvidia,function = "pmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       reset_out_n {
+                               nvidia,pins = "reset_out_n";
+                               nvidia,function = "reset_out_n";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       owr {
+                               nvidia,pins = "owr";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                               nvidia,rcv-sel = <TEGRA_PIN_DISABLE>;
+                       };
+                       clk_32k_in {
+                               nvidia,pins = "clk_32k_in";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       jtag_rtck {
+                               nvidia,pins = "jtag_rtck";
+                               nvidia,function = "rtck";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+               };
+       };
+
+       /* DB9 serial port */
+       serial@0,70006300 {
+               status = "okay";
+       };
+
+       /* Expansion GEN1_I2C_*, mini-PCIe I2C, on-board components */
+       i2c@0,7000c000 {
+               status = "okay";
+               clock-frequency = <100000>;
+
+               rt5639: audio-codec@1c {
+                       compatible = "realtek,rt5639";
+                       reg = <0x1c>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
+                       realtek,ldo1-en-gpios =
+                               <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
+               };
+
+               temperature-sensor@4c {
+                       compatible = "ti,tmp451";
+                       reg = <0x4c>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(I, 6) IRQ_TYPE_LEVEL_LOW>;
+               };
+
+               eeprom@56 {
+                       compatible = "atmel,24c02";
+                       reg = <0x56>;
+                       pagesize = <8>;
+               };
+       };
+
+       /* Expansion GEN2_I2C_* */
+       i2c@0,7000c400 {
+               status = "okay";
+               clock-frequency = <100000>;
+       };
+
+       /* Expansion CAM_I2C_* */
+       i2c@0,7000c500 {
+               status = "okay";
+               clock-frequency = <100000>;
+       };
+
+       /* HDMI DDC */
+       hdmi_ddc: i2c@0,7000c700 {
+               status = "okay";
+               clock-frequency = <100000>;
+       };
+
+       /* Expansion PWR_I2C_*, on-board components */
+       i2c@0,7000d000 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               pmic: pmic@40 {
+                       compatible = "ams,as3722";
+                       reg = <0x40>;
+                       interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
+
+                       ams,system-power-controller;
+
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&as3722_default>;
+
+                       as3722_default: pinmux {
+                               gpio0 {
+                                       pins = "gpio0";
+                                       function = "gpio";
+                                       bias-pull-down;
+                               };
+
+                               gpio1_2_4_7 {
+                                       pins = "gpio1", "gpio2", "gpio4", "gpio7";
+                                       function = "gpio";
+                                       bias-pull-up;
+                               };
+
+                               gpio3_5_6 {
+                                       pins = "gpio3", "gpio5", "gpio6";
+                                       bias-high-impedance;
+                               };
+                       };
+
+                       regulators {
+                               vsup-sd2-supply = <&vdd_5v0_sys>;
+                               vsup-sd3-supply = <&vdd_5v0_sys>;
+                               vsup-sd4-supply = <&vdd_5v0_sys>;
+                               vsup-sd5-supply = <&vdd_5v0_sys>;
+                               vin-ldo0-supply = <&vdd_1v35_lp0>;
+                               vin-ldo1-6-supply = <&vdd_3v3_run>;
+                               vin-ldo2-5-7-supply = <&vddio_1v8>;
+                               vin-ldo3-4-supply = <&vdd_3v3_sys>;
+                               vin-ldo9-10-supply = <&vdd_5v0_sys>;
+                               vin-ldo11-supply = <&vdd_3v3_run>;
+
+                               sd0 {
+                                       regulator-name = "+VDD_CPU_AP";
+                                       regulator-min-microvolt = <700000>;
+                                       regulator-max-microvolt = <1400000>;
+                                       regulator-min-microamp = <3500000>;
+                                       regulator-max-microamp = <3500000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+                                       ams,external-control = <2>;
+                               };
+
+                               sd1 {
+                                       regulator-name = "+VDD_CORE";
+                                       regulator-min-microvolt = <700000>;
+                                       regulator-max-microvolt = <1350000>;
+                                       regulator-min-microamp = <2500000>;
+                                       regulator-max-microamp = <2500000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+                                       ams,external-control = <1>;
+                               };
+
+                               vdd_1v35_lp0: sd2 {
+                                       regulator-name = "+1.35V_LP0(sd2)";
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+                               };
+
+                               sd3 {
+                                       regulator-name = "+1.35V_LP0(sd3)";
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+                               };
+
+                               vdd_1v05_run: sd4 {
+                                       regulator-name = "+1.05V_RUN";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1050000>;
+                               };
+
+                               vddio_1v8: sd5 {
+                                       regulator-name = "+1.8V_VDDIO";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                                       regulator-boot-on;
+                                       regulator-always-on;
+                               };
+
+                               sd6 {
+                                       regulator-name = "+VDD_GPU_AP";
+                                       regulator-min-microvolt = <650000>;
+                                       regulator-max-microvolt = <1200000>;
+                                       regulator-min-microamp = <3500000>;
+                                       regulator-max-microamp = <3500000>;
+                                       regulator-boot-on;
+                                       regulator-always-on;
+                               };
+
+                               ldo0 {
+                                       regulator-name = "+1.05V_RUN_AVDD";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1050000>;
+                                       regulator-boot-on;
+                                       regulator-always-on;
+                                       ams,external-control = <1>;
+                               };
+
+                               ldo1 {
+                                       regulator-name = "+1.8V_RUN_CAM";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                               };
+
+                               ldo2 {
+                                       regulator-name = "+1.2V_GEN_AVDD";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+                                       regulator-boot-on;
+                                       regulator-always-on;
+                               };
+
+                               ldo3 {
+                                       regulator-name = "+1.05V_LP0_VDD_RTC";
+                                       regulator-min-microvolt = <1000000>;
+                                       regulator-max-microvolt = <1000000>;
+                                       regulator-boot-on;
+                                       regulator-always-on;
+                                       ams,enable-tracking;
+                               };
+
+                               ldo4 {
+                                       regulator-name = "+2.8V_RUN_CAM";
+                                       regulator-min-microvolt = <2800000>;
+                                       regulator-max-microvolt = <2800000>;
+                               };
+
+                               ldo5 {
+                                       regulator-name = "+1.2V_RUN_CAM_FRONT";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+                               };
+
+                               vddio_sdmmc3: ldo6 {
+                                       regulator-name = "+VDDIO_SDMMC3";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <3300000>;
+                               };
+
+                               ldo7 {
+                                       regulator-name = "+1.05V_RUN_CAM_REAR";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1050000>;
+                               };
+
+                               ldo9 {
+                                       regulator-name = "+3.3V_RUN_TOUCH";
+                                       regulator-min-microvolt = <2800000>;
+                                       regulator-max-microvolt = <2800000>;
+                               };
+
+                               ldo10 {
+                                       regulator-name = "+2.8V_RUN_CAM_AF";
+                                       regulator-min-microvolt = <2800000>;
+                                       regulator-max-microvolt = <2800000>;
+                               };
+
+                               ldo11 {
+                                       regulator-name = "+1.8V_RUN_VPP_FUSE";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                               };
+                       };
+               };
+       };
+
+       /* Expansion TS_SPI_* */
+       spi@0,7000d400 {
+               status = "okay";
+       };
+
+       /* Internal SPI */
+       spi@0,7000da00 {
+               status = "okay";
+               spi-max-frequency = <25000000>;
+               spi-flash@0 {
+                       compatible = "winbond,w25q32dw";
+                       reg = <0>;
+                       spi-max-frequency = <20000000>;
+               };
+       };
+
+       pmc@0,7000e400 {
+               nvidia,invert-interrupt;
+               nvidia,suspend-mode = <1>;
+               nvidia,cpu-pwr-good-time = <500>;
+               nvidia,cpu-pwr-off-time = <300>;
+               nvidia,core-pwr-good-time = <641 3845>;
+               nvidia,core-pwr-off-time = <61036>;
+               nvidia,core-power-req-active-high;
+               nvidia,sys-clock-req-active-high;
+       };
+
+       /* SD card */
+       sdhci@0,700b0400 {
+               status = "okay";
+               cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
+               power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
+               wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>;
+               bus-width = <4>;
+               vqmmc-supply = <&vddio_sdmmc3>;
+       };
+
+       /* eMMC */
+       sdhci@0,700b0600 {
+               status = "okay";
+               bus-width = <8>;
+       };
+
+       ahub@0,70300000 {
+               i2s@0,70301100 {
+                       status = "okay";
+               };
+       };
+
+       /* mini-PCIe USB */
+       usb@0,7d004000 {
+               status = "okay";
+       };
+
+       usb-phy@0,7d004000 {
+               status = "okay";
+       };
+
+       /* USB A connector */
+       usb@0,7d008000 {
+               status = "okay";
+       };
+
+       usb-phy@0,7d008000 {
+               status = "okay";
+               vbus-supply = <&vdd_usb3_vbus>;
+       };
+
+       clocks {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               clk32k_in: clock@0 {
+                       compatible = "fixed-clock";
+                       reg = <0>;
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               power {
+                       label = "Power";
+                       gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+                       debounce-interval = <10>;
+                       gpio-key,wakeup;
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               vdd_mux: regulator@0 {
+                       compatible = "regulator-fixed";
+                       reg = <0>;
+                       regulator-name = "+VDD_MUX";
+                       regulator-min-microvolt = <12000000>;
+                       regulator-max-microvolt = <12000000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+               };
+
+               vdd_5v0_sys: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "+5V_SYS";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       vin-supply = <&vdd_mux>;
+               };
+
+               vdd_3v3_sys: regulator@2 {
+                       compatible = "regulator-fixed";
+                       reg = <2>;
+                       regulator-name = "+3.3V_SYS";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       vin-supply = <&vdd_mux>;
+               };
+
+               vdd_3v3_run: regulator@3 {
+                       compatible = "regulator-fixed";
+                       reg = <3>;
+                       regulator-name = "+3.3V_RUN";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       gpio = <&pmic 1 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vdd_3v3_sys>;
+               };
+
+               vdd_3v3_hdmi: regulator@4 {
+                       compatible = "regulator-fixed";
+                       reg = <4>;
+                       regulator-name = "+3.3V_AVDD_HDMI_AP_GATED";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       vin-supply = <&vdd_3v3_run>;
+               };
+
+               vdd_usb1_vbus: regulator@7 {
+                       compatible = "regulator-fixed";
+                       reg = <7>;
+                       regulator-name = "+USB0_VBUS_SW";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio TEGRA_GPIO(N, 4) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       gpio-open-drain;
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_usb3_vbus: regulator@8 {
+                       compatible = "regulator-fixed";
+                       reg = <8>;
+                       regulator-name = "+5V_USB_HS";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio TEGRA_GPIO(N, 5) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       gpio-open-drain;
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_3v3_lp0: regulator@10 {
+                       compatible = "regulator-fixed";
+                       reg = <10>;
+                       regulator-name = "+3.3V_LP0";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       gpio = <&pmic 2 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vdd_3v3_sys>;
+               };
+
+               vdd_hdmi_pll: regulator@11 {
+                       compatible = "regulator-fixed";
+                       reg = <11>;
+                       regulator-name = "+1.05V_RUN_AVDD_HDMI_PLL";
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1050000>;
+                       gpio = <&gpio TEGRA_GPIO(H, 7) GPIO_ACTIVE_LOW>;
+                       vin-supply = <&vdd_1v05_run>;
+               };
+
+               vdd_5v0_hdmi: regulator@12 {
+                       compatible = "regulator-fixed";
+                       reg = <12>;
+                       regulator-name = "+5V_HDMI_CON";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-rt5640-jetson-tk1",
+                            "nvidia,tegra-audio-rt5640";
+               nvidia,model = "NVIDIA Tegra Jetson TK1";
+
+               nvidia,audio-routing =
+                       "Headphones", "HPOR",
+                       "Headphones", "HPOL",
+                       "Mic Jack", "MICBIAS1",
+                       "IN2P", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&rt5639>;
+
+               nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_LOW>;
+
+               clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
+                        <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
+                        <&tegra_car TEGRA124_CLK_EXTERN1>;
+               clock-names = "pll_a", "pll_a_out0", "mclk";
+       };
+};
index c17283c0459807f1906080deca248f4fb638b192..84a6ec039e1d409cfe28be737052206ff6ee5ab7 100644 (file)
        };
 
        host1x@0,50000000 {
+               hdmi@0,54280000 {
+                       status = "okay";
+
+                       vdd-supply = <&vdd_3v3_hdmi>;
+                       pll-supply = <&vdd_hdmi_pll>;
+                       hdmi-supply = <&vdd_5v0_hdmi>;
+
+                       nvidia,ddc-i2c-bus = <&hdmi_ddc>;
+                       nvidia,hpd-gpio =
+                               <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>;
+               };
+
                sor@0,54540000 {
                        status = "okay";
 
                clock-frequency = <100000>;
        };
 
-       i2c@0,7000c700 {
+       hdmi_ddc: i2c@0,7000c700 {
                status = "okay";
                clock-frequency = <100000>;
        };
                                        regulator-boot-on;
                                };
 
-                               sd4 {
+                               vdd_1v05_run: sd4 {
                                        regulator-name = "+1.05V_RUN";
                                        regulator-min-microvolt = <1050000>;
                                        regulator-max-microvolt = <1050000>;
                power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
                status = "okay";
                bus-width = <4>;
-               vmmc-supply = <&vddio_sdmmc3>;
+               vqmmc-supply = <&vddio_sdmmc3>;
        };
 
        sdhci@0,700b0600 {
                        regulator-name = "+3.3V_RUN";
                        regulator-min-microvolt = <3300000>;
                        regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+                       regulator-boot-on;
                        gpio = <&pmic 1 GPIO_ACTIVE_HIGH>;
                        enable-active-high;
                        vin-supply = <&vdd_3v3_sys>;
                        enable-active-high;
                        vin-supply = <&vdd_3v3_sys>;
                };
+
+               vdd_hdmi_pll: regulator@11 {
+                       compatible = "regulator-fixed";
+                       reg = <11>;
+                       regulator-name = "+1.05V_RUN_AVDD_HDMI_PLL";
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1050000>;
+                       gpio = <&gpio TEGRA_GPIO(H, 7) GPIO_ACTIVE_LOW>;
+                       vin-supply = <&vdd_1v05_run>;
+               };
+
+               vdd_5v0_hdmi: regulator@12 {
+                       compatible = "regulator-fixed";
+                       reg = <12>;
+                       regulator-name = "+5V_HDMI_CON";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vdd_5v0_sys>;
+               };
        };
 
        sound {
index 6d540a02514886d37e095a7e47909457db9ef0e5..6e6bc4e8185c3e836b8a09b0ce5c90f135f9f118 100644 (file)
                        nvidia,head = <1>;
                };
 
+               hdmi@0,54280000 {
+                       compatible = "nvidia,tegra124-hdmi";
+                       reg = <0x0 0x54280000 0x0 0x00040000>;
+                       interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&tegra_car TEGRA124_CLK_HDMI>,
+                                <&tegra_car TEGRA124_CLK_PLL_D2_OUT0>;
+                       clock-names = "hdmi", "parent";
+                       resets = <&tegra_car 51>;
+                       reset-names = "hdmi";
+                       status = "disabled";
+               };
+
                sor@0,54540000 {
                        compatible = "nvidia,tegra124-sor";
                        reg = <0x0 0x54540000 0x0 0x00040000>;
index 3fb1f50f6d4628a3bdc42214450e03ace2a41e2d..f45aad688d9b5296239795860231de5d3340eab1 100644 (file)
@@ -28,6 +28,7 @@
                hdmi@54280000 {
                        status = "okay";
 
+                       hdmi-supply = <&vdd_5v0_hdmi>;
                        vdd-supply = <&hdmi_vdd_reg>;
                        pll-supply = <&hdmi_pll_reg>;
 
                        gpio = <&gpio TEGRA_GPIO(W, 0) GPIO_ACTIVE_HIGH>;
                        enable-active-high;
                };
+
+               vdd_5v0_hdmi: regulator@6 {
+                       compatible = "regulator-fixed";
+                       reg = <6>;
+                       regulator-name = "VDDIO_HDMI";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio TEGRA_GPIO(T, 2) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+                       vin-supply = <&vdd_5v0_reg>;
+               };
        };
 
        sound {
index e93fe45b7803e7030d1dbb114ea7db12da8b6026..3189791a92897654701118ed2733432dceba57dd 100644 (file)
@@ -40,6 +40,7 @@
                hdmi@54280000 {
                        status = "okay";
 
+                       hdmi-supply = <&vdd_5v0_hdmi>;
                        vdd-supply = <&sys_3v3_reg>;
                        pll-supply = <&vio_reg>;
 
                        gpio = <&gpio TEGRA_GPIO(L, 7) GPIO_ACTIVE_HIGH>;
                        vin-supply = <&sys_3v3_reg>;
                };
+
+               vdd_5v0_hdmi: regulator@8 {
+                       compatible = "regulator-fixed";
+                       reg = <8>;
+                       regulator-name = "+VDD_5V_HDMI";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       vin-supply = <&sys_3v3_reg>;
+               };
        };
 
        sound {
diff --git a/arch/arm/boot/dts/vf610-colibri.dts b/arch/arm/boot/dts/vf610-colibri.dts
new file mode 100644 (file)
index 0000000..aecc7db
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/dts-v1/;
+#include "vf610.dtsi"
+
+/ {
+       model = "Toradex Colibri VF61 COM";
+       compatible = "toradex,vf610-colibri", "fsl,vf610";
+
+       chosen {
+               bootargs = "console=ttyLP0,115200";
+       };
+
+       memory {
+               reg = <0x80000000 0x10000000>;
+       };
+
+       clocks {
+               enet_ext {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <50000000>;
+               };
+       };
+
+};
+
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       bus-width = <4>;
+       status = "okay";
+};
+
+&fec1 {
+       phy-mode = "rmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+       status = "okay";
+};
+
+&L2 {
+       arm,data-latency = <2 1 2>;
+       arm,tag-latency = <3 2 3>;
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart0>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&iomuxc {
+       vf610-colibri {
+               pinctrl_esdhc1: esdhc1grp {
+                       fsl,fsl,pins = <
+                               VF610_PAD_PTA24__ESDHC1_CLK     0x31ef
+                               VF610_PAD_PTA25__ESDHC1_CMD     0x31ef
+                               VF610_PAD_PTA26__ESDHC1_DAT0    0x31ef
+                               VF610_PAD_PTA27__ESDHC1_DAT1    0x31ef
+                               VF610_PAD_PTA28__ESDHC1_DATA2   0x31ef
+                               VF610_PAD_PTA29__ESDHC1_DAT3    0x31ef
+                               VF610_PAD_PTB20__GPIO_42        0x219d
+                       >;
+               };
+
+               pinctrl_fec1: fec1grp {
+                       fsl,pins = <
+                               VF610_PAD_PTC9__ENET_RMII1_MDC          0x30d2
+                               VF610_PAD_PTC10__ENET_RMII1_MDIO        0x30d3
+                               VF610_PAD_PTC11__ENET_RMII1_CRS         0x30d1
+                               VF610_PAD_PTC12__ENET_RMII_RXD1         0x30d1
+                               VF610_PAD_PTC13__ENET_RMII1_RXD0        0x30d1
+                               VF610_PAD_PTC14__ENET_RMII1_RXER        0x30d1
+                               VF610_PAD_PTC15__ENET_RMII1_TXD1        0x30d2
+                               VF610_PAD_PTC16__ENET_RMII1_TXD0        0x30d2
+                               VF610_PAD_PTC17__ENET_RMII1_TXEN        0x30d2
+                       >;
+               };
+
+               pinctrl_uart0: uart0grp {
+                       fsl,pins = <
+                               VF610_PAD_PTB10__UART0_TX               0x21a2
+                               VF610_PAD_PTB11__UART0_RX               0x21a1
+                       >;
+               };
+
+               pinctrl_uart1: uart1grp {
+                       fsl,pins = <
+                               VF610_PAD_PTB4__UART1_TX                0x21a2
+                               VF610_PAD_PTB5__UART1_RX                0x21a1
+                       >;
+               };
+
+               pinctrl_uart2: uart2grp {
+                       fsl,pins = <
+                               VF610_PAD_PTD0__UART2_TX                0x21a2
+                               VF610_PAD_PTD1__UART2_RX                0x21a1
+                               VF610_PAD_PTD2__UART2_RTS               0x21a2
+                               VF610_PAD_PTD3__UART2_CTS               0x21a1
+                       >;
+               };
+       };
+};
index ded361075aab7a1504eadc460defc992d5402161..11d733406c7ed5f1078228b93a1837b3102eedb7 100644 (file)
        };
 };
 
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       bus-width = <4>;
+       status = "okay";
+};
+
 &fec0 {
        phy-mode = "rmii";
        pinctrl-names = "default";
                        >;
                };
 
+               pinctrl_esdhc1: esdhc1grp {
+                       fsl,fsl,pins = <
+                               VF610_PAD_PTA24__ESDHC1_CLK     0x31ef
+                               VF610_PAD_PTA25__ESDHC1_CMD     0x31ef
+                               VF610_PAD_PTA26__ESDHC1_DAT0    0x31ef
+                               VF610_PAD_PTA27__ESDHC1_DAT1    0x31ef
+                               VF610_PAD_PTA28__ESDHC1_DATA2   0x31ef
+                               VF610_PAD_PTA29__ESDHC1_DAT3    0x31ef
+                               VF610_PAD_PTA7__GPIO_134        0x219d
+                       >;
+               };
+
                pinctrl_fec0: fec0grp {
                        fsl,pins = <
                                VF610_PAD_PTA6__RMII_CLKIN              0x30d1
                        >;
                };
 
+               pinctrl_pwm0: pwm0grp {
+                       fsl,pins = <
+                               VF610_PAD_PTB0__FTM0_CH0                0x1582
+                               VF610_PAD_PTB1__FTM0_CH1                0x1582
+                               VF610_PAD_PTB2__FTM0_CH2                0x1582
+                               VF610_PAD_PTB3__FTM0_CH3                0x1582
+                               VF610_PAD_PTB6__FTM0_CH6                0x1582
+                               VF610_PAD_PTB7__FTM0_CH7                0x1582
+                       >;
+               };
+
                pinctrl_sai2: sai2grp {
                        fsl,pins = <
                                VF610_PAD_PTA16__SAI2_TX_BCLK           0x02ed
        };
 };
 
+&pwm0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm0>;
+       status = "okay";
+};
+
 &sai2 {
        #sound-dai-cells = <0>;
        pinctrl-names = "default";
index b8ce0aa7b1579064980edee427fa0cd41f7c710d..73355ddc51861ced14a605a1f24e08834598e11c 100644 (file)
                                clock-names = "pit";
                        };
 
+                       pwm0: pwm@40038000 {
+                               compatible = "fsl,vf610-ftm-pwm";
+                               #pwm-cells = <3>;
+                               reg = <0x40038000 0x1000>;
+                               clock-names = "ftm_sys", "ftm_ext",
+                                             "ftm_fix", "ftm_cnt_clk_en";
+                               clocks = <&clks VF610_CLK_FTM0>,
+                                       <&clks VF610_CLK_FTM0_EXT_SEL>,
+                                       <&clks VF610_CLK_FTM0_FIX_SEL>,
+                                       <&clks VF610_CLK_FTM0_EXT_FIX_EN>;
+                               status = "disabled";
+                       };
+
                        adc0: adc@4003b000 {
                                compatible = "fsl,vf610-adc";
                                reg = <0x4003b000 0x1000>;
                                status = "disabled";
                        };
 
+                       esdhc1: esdhc@400b2000 {
+                               compatible = "fsl,imx53-esdhc";
+                               reg = <0x400b2000 0x4000>;
+                               interrupts = <0 28 0x04>;
+                               clocks = <&clks VF610_CLK_IPG_BUS>,
+                                       <&clks VF610_CLK_PLATFORM_BUS>,
+                                       <&clks VF610_CLK_ESDHC1>;
+                               clock-names = "ipg", "ahb", "per";
+                               status = "disabled";
+                       };
+
                        fec0: ethernet@400d0000 {
                                compatible = "fsl,mvf600-fec";
                                reg = <0x400d0000 0x1000>;
index 51d0e912c8f585b1acb51edc9f47fc4270a1a988..1929ad390d88feb0ec42bce29ad1b174823ed55b 100644 (file)
                        reg = <0xd8100000 0x10000>;
                        interrupts = <48>;
                };
+
+               ethernet@d8004000 {
+                       compatible = "via,vt8500-rhine";
+                       reg = <0xd8004000 0x100>;
+                       interrupts = <10>;
+               };
        };
 };
index 7525982262ac9896285031462e45b23b4020d9c7..b1c59a766a13381a693d897eb3349db4ac9d3c16 100644 (file)
                        reg = <0xd8100000 0x10000>;
                        interrupts = <48>;
                };
+
+               ethernet@d8004000 {
+                       compatible = "via,vt8500-rhine";
+                       reg = <0xd8004000 0x100>;
+                       interrupts = <10>;
+               };
        };
 };
index d98386dd2882500bd71ecf726d8ac9bb26b777a7..8fbccfbe75f33df7be79ea7be37c15b9f5bf2535 100644 (file)
                        bus-width = <4>;
                        sdon-inverted;
                };
+
+               ethernet@d8004000 {
+                       compatible = "via,vt8500-rhine";
+                       reg = <0xd8004000 0x100>;
+                       interrupts = <10>;
+                };
        };
 };
index 41bca32409fce81358c3b5c35bc081bcc28e7c76..25fa735abc6cb35816e3f1efc6b69cec0aa08b72 100644 (file)
@@ -994,29 +994,23 @@ void edma_set_dest(unsigned slot, dma_addr_t dest_port,
 EXPORT_SYMBOL(edma_set_dest);
 
 /**
- * edma_get_position - returns the current transfer points
+ * edma_get_position - returns the current transfer point
  * @slot: parameter RAM slot being examined
- * @src: pointer to source port position
- * @dst: pointer to destination port position
+ * @dst:  true selects the dest position, false the source
  *
- * Returns current source and destination addresses for a particular
- * parameter RAM slot.  Its channel should not be active when this is called.
+ * Returns the position of the current active slot
  */
-void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst)
+dma_addr_t edma_get_position(unsigned slot, bool dst)
 {
-       struct edmacc_param temp;
-       unsigned ctlr;
+       u32 offs, ctlr = EDMA_CTLR(slot);
 
-       ctlr = EDMA_CTLR(slot);
        slot = EDMA_CHAN_SLOT(slot);
 
-       edma_read_slot(EDMA_CTLR_CHAN(ctlr, slot), &temp);
-       if (src != NULL)
-               *src = temp.src;
-       if (dst != NULL)
-               *dst = temp.dst;
+       offs = PARM_OFFSET(slot);
+       offs += dst ? PARM_DST : PARM_SRC;
+
+       return edma_read(ctlr, offs);
 }
-EXPORT_SYMBOL(edma_get_position);
 
 /**
  * edma_set_src_index - configure DMA source address indexing
@@ -1574,6 +1568,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
                return ERR_PTR(ret);
 
        dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap);
+       dma_cap_set(DMA_CYCLIC, edma_filter_info.dma_cap);
        of_dma_controller_register(dev->of_node, of_dma_simple_xlate,
                                   &edma_filter_info);
 
@@ -1768,6 +1763,9 @@ static int edma_probe(struct platform_device *pdev)
                        map_queue_tc(j, queue_tc_mapping[i][0],
                                        queue_tc_mapping[i][1]);
 
+               /* Save the number of TCs */
+               edma_cc[j]->num_tc = i;
+
                /* Event queue priority mapping */
                for (i = 0; queue_priority_mapping[i][0] != -1; i++)
                        assign_priority_to_queue(j,
index f1595514417560858f3fb517b561aab6b2553a1a..701677f9248c2f493d14f1b984a05dc0fa8ae260 100644 (file)
@@ -37,7 +37,6 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
@@ -48,6 +47,7 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=1
index f1aeb7d727125a7d11925b50ac4358cb6f328349..bada59d93b675310637efa063035c0d23ec6b066 100644 (file)
@@ -80,6 +80,7 @@ CONFIG_MTD_UBI=y
 CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=y
 CONFIG_ATA=y
+CONFIG_BLK_DEV_SD=y
 CONFIG_PATA_IMX=y
 CONFIG_NETDEVICES=y
 CONFIG_CS89x0=y
@@ -153,8 +154,12 @@ CONFIG_USB_HID=m
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_MXC=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_NOP_USB_XCEIV=y
 CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_ESDHC_IMX=y
@@ -177,7 +182,6 @@ CONFIG_RTC_DRV_MXC=y
 CONFIG_DMADEVICES=y
 CONFIG_IMX_SDMA=y
 CONFIG_IMX_DMA=y
-CONFIG_COMMON_CLK_DEBUG=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
index 09e974392fa119f09ef2790e63d58410b5367e4a..9fc30243ecfe65d901b39582bc77312e96f69dea 100644 (file)
@@ -1,4 +1,3 @@
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_KERNEL_LZO=y
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
@@ -46,7 +45,11 @@ CONFIG_VMSPLIT_2G=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_CMA=y
 CONFIG_CMDLINE="noinitrd console=ttymxc0,115200"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_ARM_IMX6Q_CPUFREQ=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_BINFMT_MISC=m
@@ -72,6 +75,7 @@ CONFIG_RFKILL_INPUT=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
+CONFIG_DMA_CMA=y
 CONFIG_IMX_WEIM=y
 CONFIG_CONNECTOR=y
 CONFIG_MTD=y
@@ -183,6 +187,7 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_CODA=y
 CONFIG_SOC_CAMERA_OV2640=y
 CONFIG_DRM=y
+CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_L4F00242T03=y
@@ -209,13 +214,14 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_OTG_FSM=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_MXS_PHY=y
+CONFIG_USB_ULPI=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_USB_MASS_STORAGE=m
 CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_ESDHC_IMX=y
@@ -245,7 +251,7 @@ CONFIG_DRM_IMX_TVE=y
 CONFIG_DRM_IMX_LDB=y
 CONFIG_DRM_IMX_IPUV3_CORE=y
 CONFIG_DRM_IMX_IPUV3=y
-CONFIG_COMMON_CLK_DEBUG=y
+CONFIG_DRM_IMX_HDMI=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_PWM=y
 CONFIG_PWM_IMX=y
index 2e762d94e94b31501c1e7e3ea16965c72d3d9b9c..b9e480c10b10880bb64d2d5f2ec8ac872ced5890 100644 (file)
@@ -61,6 +61,7 @@ CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ORION=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_EEPROM_AT24=y
 # CONFIG_SCSI_PROC_FS is not set
index aa3dfb084fed6b3e4739f3a2d002daf616f18eb6..5ebfa8bf85094b8ff5ded8b819a9d7f278304a22 100644 (file)
@@ -11,7 +11,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_MVEBU=y
 CONFIG_MACH_KIRKWOOD=y
-CONFIG_MACH_T5325=y
 CONFIG_ARCH_MXC=y
 CONFIG_MACH_IMX25_DT=y
 CONFIG_MACH_IMX27_DT=y
@@ -108,6 +107,8 @@ CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_KIRKWOOD_SOC=y
 CONFIG_SND_KIRKWOOD_SOC_T5325=y
+CONFIG_SND_SOC_ALC5623=y
+CONFIG_SND_SIMPLE_CARD=y
 # CONFIG_ABX500_CORE is not set
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
index d4e8a47a2f7c8a016b8eee0adaf36e24bb0c341a..5039cc6cedc061d9296dec7d7ba89f005ca8d387 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_ARCH_BCM_MOBILE=y
 CONFIG_ARCH_BERLIN=y
 CONFIG_MACH_BERLIN_BG2=y
 CONFIG_MACH_BERLIN_BG2CD=y
+CONFIG_MACH_BERLIN_BG2Q=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_ARCH_HIGHBANK=y
 CONFIG_ARCH_HI3xxx=y
@@ -112,6 +113,7 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_ICS932S401=y
 CONFIG_APDS9802ALS=y
 CONFIG_ISL29003=y
+CONFIG_EEPROM_AT24=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_SCSI_MULTI_LUN=y
@@ -191,6 +193,7 @@ CONFIG_PINCTRL_AS3722=y
 CONFIG_PINCTRL_PALMAS=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_PCA953X_IRQ=y
 CONFIG_GPIO_TWL4030=y
 CONFIG_GPIO_PALMAS=y
@@ -273,6 +276,7 @@ CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_ARMMMCI=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_ESDHC_IMX=y
+CONFIG_MMC_SDHCI_PXAV3=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_DOVE=y
 CONFIG_MMC_SDHCI_SPEAR=y
index 36484a37a1ca1924241fc371d7aa584ca4732175..27c732fdf21eae1bfe04e8e19761dffd9996bdc6 100644 (file)
@@ -1,4 +1,5 @@
 CONFIG_SYSVIPC=y
+CONFIG_FHANDLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=19
@@ -11,7 +12,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_MVEBU=y
 CONFIG_MACH_KIRKWOOD=y
-CONFIG_MACH_T5325=y
 # CONFIG_CPU_FEROCEON_OLD_ID is not set
 CONFIG_PCI_MVEBU=y
 CONFIG_PREEMPT=y
@@ -50,6 +50,7 @@ CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ORION=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_EEPROM_AT24=y
 # CONFIG_SCSI_PROC_FS is not set
@@ -100,6 +101,8 @@ CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_KIRKWOOD_SOC=y
 CONFIG_SND_KIRKWOOD_SOC_T5325=y
+CONFIG_SND_SOC_ALC5623=y
+CONFIG_SND_SIMPLE_CARD=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_HID_DRAGONRISE=y
index a34713d8db9f6cc633d14230808e634e9c4b599b..b52a6f5c52256a67b88ee054f6ebbf1af6b6cb3a 100644 (file)
@@ -1,5 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_FHANDLE=y
 CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -29,6 +30,9 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
 CONFIG_NET=y
 CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
 CONFIG_BT=y
 CONFIG_BT_MRVL=y
 CONFIG_BT_MRVL_SDIO=y
@@ -36,6 +40,7 @@ CONFIG_CFG80211=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
+CONFIG_AHCI_MVEBU=y
 CONFIG_SATA_MV=y
 CONFIG_NETDEVICES=y
 CONFIG_MVNETA=y
@@ -53,6 +58,7 @@ CONFIG_I2C_MV64XXX=y
 CONFIG_MTD=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
@@ -79,6 +85,7 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_MMC=y
+CONFIG_MMC_SDHCI_PXAV3=y
 CONFIG_MMC_MVSDIO=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_GPIO=y
@@ -103,6 +110,8 @@ CONFIG_UDF_FS=m
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
index 6150108e15de8526828e07272e44be49d0d938ca..51702398557d0b795e5a443f50e0291daab4de6f 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_ARCH_MXS=y
 # CONFIG_ARM_THUMB is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_AEABI=y
-CONFIG_FPE_NWFPE=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -51,7 +50,6 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_M25P80=y
-# CONFIG_M25PXX_USE_FAST_READ is not set
 CONFIG_MTD_SST25L=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_GPMI_NAND=y
@@ -120,7 +118,6 @@ CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_USB_MASS_STORAGE=m
 CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
 CONFIG_MMC_MXS=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
@@ -138,7 +135,6 @@ CONFIG_DMADEVICES=y
 CONFIG_MXS_DMA=y
 CONFIG_STAGING=y
 CONFIG_MXS_LRADC=y
-CONFIG_COMMON_CLK_DEBUG=y
 CONFIG_IIO=y
 CONFIG_IIO_SYSFS_TRIGGER=y
 CONFIG_PWM=y
@@ -180,7 +176,7 @@ CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_STRICT_DEVMEM=y
 CONFIG_DEBUG_USER=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
+CONFIG_CRYPTO_DEV_MXS_DCP=y
 CONFIG_CRC_ITU_T=m
 CONFIG_CRC7=m
 CONFIG_FONTS=y
index abe61bf379d265988220ea03fa6fe9346a737bba..1da5d9e48224246ae3c813f9100587293f886fbd 100644 (file)
@@ -76,8 +76,10 @@ CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_VERSATILE=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_PL031=y
index 7079cbe898a8c8041983dcb95679dfa24fc4f0f2..d02e9d911bb7298291260b367a9ccdc03e4ec9aa 100644 (file)
@@ -75,8 +75,10 @@ CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_VERSATILE=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_PL031=y
index 83b07258a385b43c9a2920eb4cbb1b88f4f95efc..6d6437cbbc523b11510a26a7e75330a6a129e7dc 100644 (file)
@@ -25,6 +25,7 @@ CONFIG_SCHED_MC=y
 CONFIG_HAVE_ARM_ARCH_TIMER=y
 CONFIG_NR_CPUS=8
 CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
@@ -43,6 +44,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_M25P80=y
+CONFIG_EEPROM_AT24=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_SATA_RCAR=y
@@ -75,9 +77,11 @@ CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_SH_SCI_NR_UARTS=20
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_I2C_GPIO=y
+CONFIG_I2C_SH_MOBILE=y
 CONFIG_I2C_RCAR=y
 CONFIG_SPI=y
 CONFIG_SPI_RSPI=y
+CONFIG_SPI_SH_MSIOF=y
 CONFIG_GPIO_EM=y
 CONFIG_GPIO_RCAR=y
 # CONFIG_HWMON is not set
@@ -88,10 +92,14 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SOC_CAMERA=y
 CONFIG_SOC_CAMERA_PLATFORM=y
 CONFIG_VIDEO_RCAR_VIN=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_VSP1=y
 # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
 CONFIG_VIDEO_ADV7180=y
 CONFIG_DRM=y
@@ -100,7 +108,13 @@ CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_RCAR=y
+CONFIG_USB=y
 CONFIG_USB_RCAR_GEN2_PHY=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_RENESAS_USBHS=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=y
 CONFIG_MMC=y
 CONFIG_MMC_SDHI=y
 CONFIG_MMC_SH_MMCIF=y
index 2926281368ab663aef5c09470a9dbbd0c728c0e8..e65b85c33f558902c584f06a149231990fed82b5 100644 (file)
@@ -90,6 +90,7 @@ CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_MTD=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_AD525X_DPOT=y
@@ -97,6 +98,7 @@ CONFIG_AD525X_DPOT_I2C=y
 CONFIG_ICS932S401=y
 CONFIG_APDS9802ALS=y
 CONFIG_ISL29003=y
+CONFIG_EEPROM_AT24=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
index 073541a50e2313869aeb0d0c60fd705e9833cec5..d52b4ffe2012ccdcf9c54b728113f49b1a1e05d2 100644 (file)
@@ -61,6 +61,9 @@ CONFIG_SND_ARMAACI=m
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=m
 CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_VERSATILE=y
+CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
index b974184f9941883339c0480df1290a6a6f66a4ae..57f0584e8d97dc7095fa6a785be27f6e71e424e0 100644 (file)
  * you cannot return to the original mode.
  */
 .macro safe_svcmode_maskall reg:req
-#if __LINUX_ARM_ARCH__ >= 6
+#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M)
        mrs     \reg , cpsr
        eor     \reg, \reg, #HYP_MODE
        tst     \reg, #MODE_MASK
index bbae919bceb4b5762d94fc4a2f570fbed18b6fbe..74124b0d0d7952f60bee72c69ae49c30eb677c99 100644 (file)
@@ -1,24 +1,11 @@
 #ifndef _ASM_FIXMAP_H
 #define _ASM_FIXMAP_H
 
-/*
- * Nothing too fancy for now.
- *
- * On ARM we already have well known fixed virtual addresses imposed by
- * the architecture such as the vector page which is located at 0xffff0000,
- * therefore a second level page table is already allocated covering
- * 0xfff00000 upwards.
- *
- * The cache flushing code in proc-xscale.S uses the virtual area between
- * 0xfffe0000 and 0xfffeffff.
- */
-
-#define FIXADDR_START          0xfff00000UL
-#define FIXADDR_TOP            0xfffe0000UL
+#define FIXADDR_START          0xffc00000UL
+#define FIXADDR_TOP            0xffe00000UL
 #define FIXADDR_SIZE           (FIXADDR_TOP - FIXADDR_START)
 
-#define FIX_KMAP_BEGIN         0
-#define FIX_KMAP_END           (FIXADDR_SIZE >> PAGE_SHIFT)
+#define FIX_KMAP_NR_PTES       (FIXADDR_SIZE >> PAGE_SHIFT)
 
 #define __fix_to_virt(x)       (FIXADDR_START + ((x) << PAGE_SHIFT))
 #define __virt_to_fix(x)       (((x) - FIXADDR_START) >> PAGE_SHIFT)
@@ -27,7 +14,7 @@ extern void __this_fixmap_does_not_exist(void);
 
 static inline unsigned long fix_to_virt(const unsigned int idx)
 {
-       if (idx >= FIX_KMAP_END)
+       if (idx >= FIX_KMAP_NR_PTES)
                __this_fixmap_does_not_exist();
        return __fix_to_virt(idx);
 }
index 91b99abe7a95c114be0d3b628fb8b8d09f781c74..535579511ed035f50d14bc179b4c00b74a0b4f95 100644 (file)
@@ -18,6 +18,7 @@
        } while (0)
 
 extern pte_t *pkmap_page_table;
+extern pte_t *fixmap_page_table;
 
 extern void *kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
index 02fa2558f6626a71e6132844986776c46581388f..2b751464d6ff1936bc9b73e2aaeec0a707420aaf 100644 (file)
@@ -83,8 +83,6 @@
  */
 #define IOREMAP_MAX_ORDER      24
 
-#define CONSISTENT_END         (0xffe00000UL)
-
 #else /* CONFIG_MMU */
 
 /*
index ba12cc44b2cb52cf966ba197270513adb241b61b..b88933849a17e1bfb268eb49d73b41ebe9336bdb 100644 (file)
@@ -7,9 +7,20 @@
  *
  */
 
+#define VF_UART0_BASE_ADDR     0x40027000
+#define VF_UART1_BASE_ADDR     0x40028000
+#define VF_UART2_BASE_ADDR     0x40029000
+#define VF_UART3_BASE_ADDR     0x4002a000
+#define VF_UART_BASE_ADDR(n)   VF_UART##n##_BASE_ADDR
+#define VF_UART_BASE(n)                VF_UART_BASE_ADDR(n)
+#define VF_UART_PHYSICAL_BASE  VF_UART_BASE(CONFIG_DEBUG_VF_UART_PORT)
+
+#define VF_UART_VIRTUAL_BASE   0xfe000000
+
        .macro  addruart, rp, rv, tmp
-       ldr     \rp, =0x40028000        @ physical
-       ldr     \rv, =0xfe028000        @ virtual
+       ldr     \rp, =VF_UART_PHYSICAL_BASE     @ physical
+       and     \rv, \rp, #0xffffff             @ offset within 16MB section
+       add     \rv, \rv, #VF_UART_VIRTUAL_BASE
        .endm
 
        .macro  senduart, rd, rx
index 040619c32d68dfe4ce63726f44fcedcc9fe6b2cf..38ddd9f83d0e586289c56bdbf1e38a6a977ff1a7 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_ARTHUR)          += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
 obj-$(CONFIG_PCI)              += bios32.o isa.o
 obj-$(CONFIG_ARM_CPU_SUSPEND)  += sleep.o suspend.o
+obj-$(CONFIG_HIBERNATION)      += hibernate.o
 obj-$(CONFIG_SMP)              += smp.o
 ifdef CONFIG_MMU
 obj-$(CONFIG_SMP)              += smp_tlb.o
index 1879e8dd2acc18a7837f0eee71beb8241c1aa9c0..5fc897cf409b2182a9d3f60f5cb3e63c7ed84eed 100644 (file)
@@ -413,6 +413,11 @@ __und_usr:
        @
        adr     r9, BSYM(ret_from_exception)
 
+       @ IRQs must be enabled before attempting to read the instruction from
+       @ user space since that could cause a page/translation fault if the
+       @ page table was modified by another CPU.
+       enable_irq
+
        tst     r3, #PSR_T_BIT                  @ Thumb mode?
        bne     __und_usr_thumb
        sub     r4, r2, #4                      @ ARM instr at LR - 4
@@ -517,7 +522,7 @@ ENDPROC(__und_usr)
  *  r9  = normal "successful" return address
  *  r10 = this threads thread_info structure
  *  lr  = unrecognised instruction return address
- * IRQs disabled, FIQs enabled.
+ * IRQs enabled, FIQs enabled.
  */
        @
        @ Fall-through from Thumb-2 __und_usr
@@ -624,7 +629,6 @@ call_fpe:
 #endif
 
 do_fpe:
-       enable_irq
        ldr     r4, .LCfp
        add     r10, r10, #TI_FPSTATE           @ r10 = workspace
        ldr     pc, [r4]                        @ Call FP module USR entry point
@@ -652,8 +656,7 @@ __und_usr_fault_32:
        b       1f
 __und_usr_fault_16:
        mov     r1, #2
-1:     enable_irq
-       mov     r0, sp
+1:     mov     r0, sp
        adr     lr, BSYM(ret_from_exception)
        b       __und_fault
 ENDPROC(__und_usr_fault_32)
index c108ddcb9ba405cb5c53b00807a18355fc2cf4c6..af9a8a927a4e9624636f008cc28415e97482803a 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
+#include <linux/module.h>
 
 #include <asm/cacheflush.h>
 #include <asm/opcodes.h>
@@ -63,6 +64,18 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
 }
 #endif
 
+int ftrace_arch_code_modify_prepare(void)
+{
+       set_all_modules_text_rw();
+       return 0;
+}
+
+int ftrace_arch_code_modify_post_process(void)
+{
+       set_all_modules_text_ro();
+       return 0;
+}
+
 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
        return arm_gen_branch_link(pc, addr);
diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c
new file mode 100644 (file)
index 0000000..bb8b796
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Hibernation support specific for ARM
+ *
+ * Derived from work on ARM hibernation support by:
+ *
+ * Ubuntu project, hibernation support for mach-dove
+ * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu)
+ * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.)
+ *  https://lkml.org/lkml/2010/6/18/4
+ *  https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html
+ *  https://patchwork.kernel.org/patch/96442/
+ *
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <asm/system_misc.h>
+#include <asm/idmap.h>
+#include <asm/suspend.h>
+#include <asm/memory.h>
+
+extern const void __nosave_begin, __nosave_end;
+
+int pfn_is_nosave(unsigned long pfn)
+{
+       unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin);
+       unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1);
+
+       return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn);
+}
+
+void notrace save_processor_state(void)
+{
+       WARN_ON(num_online_cpus() != 1);
+       local_fiq_disable();
+}
+
+void notrace restore_processor_state(void)
+{
+       local_fiq_enable();
+}
+
+/*
+ * Snapshot kernel memory and reset the system.
+ *
+ * swsusp_save() is executed in the suspend finisher so that the CPU
+ * context pointer and memory are part of the saved image, which is
+ * required by the resume kernel image to restart execution from
+ * swsusp_arch_suspend().
+ *
+ * soft_restart is not technically needed, but is used to get success
+ * returned from cpu_suspend.
+ *
+ * When soft reboot completes, the hibernation snapshot is written out.
+ */
+static int notrace arch_save_image(unsigned long unused)
+{
+       int ret;
+
+       ret = swsusp_save();
+       if (ret == 0)
+               soft_restart(virt_to_phys(cpu_resume));
+       return ret;
+}
+
+/*
+ * Save the current CPU state before suspend / poweroff.
+ */
+int notrace swsusp_arch_suspend(void)
+{
+       return cpu_suspend(0, arch_save_image);
+}
+
+/*
+ * Restore page contents for physical pages that were in use during loading
+ * hibernation image.  Switch to idmap_pgd so the physical page tables
+ * are overwritten with the same contents.
+ */
+static void notrace arch_restore_image(void *unused)
+{
+       struct pbe *pbe;
+
+       cpu_switch_mm(idmap_pgd, &init_mm);
+       for (pbe = restore_pblist; pbe; pbe = pbe->next)
+               copy_page(pbe->orig_address, pbe->address);
+
+       soft_restart(virt_to_phys(cpu_resume));
+}
+
+static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata;
+
+/*
+ * Resume from the hibernation image.
+ * Due to the kernel heap / data restore, stack contents change underneath
+ * and that would make function calls impossible; switch to a temporary
+ * stack within the nosave region to avoid that problem.
+ */
+int swsusp_arch_resume(void)
+{
+       extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
+       call_with_stack(arch_restore_image, 0,
+               resume_stack + ARRAY_SIZE(resume_stack));
+       return 0;
+}
index 2452dd1bef53b0eb719dcda0ce127c2f5ddaeec9..a5599cfc43cbb17280e26bc942c30853ab954c7f 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/assembler.h>
 
 #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
 #define PJ4(code...)           code
  * r9  = ret_from_exception
  * lr  = undefined instr exit
  *
- * called from prefetch exception handler with interrupts disabled
+ * called from prefetch exception handler with interrupts enabled
  */
 
 ENTRY(iwmmxt_task_enable)
+       inc_preempt_count r10, r3
 
        XSC(mrc p15, 0, r2, c15, c1, 0)
        PJ4(mrc p15, 0, r2, c1, c0, 2)
        @ CP0 and CP1 accessible?
        XSC(tst r2, #0x3)
        PJ4(tst r2, #0xf)
-       movne   pc, lr                          @ if so no business here
+       bne     4f                              @ if so no business here
        @ enable access to CP0 and CP1
        XSC(orr r2, r2, #0x3)
        XSC(mcr p15, 0, r2, c15, c1, 0)
@@ -136,7 +138,7 @@ concan_dump:
        wstrd   wR15, [r1, #MMX_WR15]
 
 2:     teq     r0, #0                          @ anything to load?
-       moveq   pc, lr
+       beq     3f
 
 concan_load:
 
@@ -169,8 +171,14 @@ concan_load:
        @ clear CUP/MUP (only if r1 != 0)
        teq     r1, #0
        mov     r2, #0
-       moveq   pc, lr
+       beq     3f
        tmcr    wCon, r2
+
+3:
+#ifdef CONFIG_PREEMPT_COUNT
+       get_thread_info r10
+#endif
+4:     dec_preempt_count r10, r3
        mov     pc, lr
 
 /*
index 51798d7854aca9b9109abba97c1cc22a6efc5a33..a71ae1523620afc4cd149c26092d16d69cd858d8 100644 (file)
@@ -221,6 +221,7 @@ static struct notifier_block cpu_pmu_hotplug_notifier = {
  * PMU platform driver and devicetree bindings.
  */
 static struct of_device_id cpu_pmu_of_device_ids[] = {
+       {.compatible = "arm,cortex-a17-pmu",    .data = armv7_a17_pmu_init},
        {.compatible = "arm,cortex-a15-pmu",    .data = armv7_a15_pmu_init},
        {.compatible = "arm,cortex-a12-pmu",    .data = armv7_a12_pmu_init},
        {.compatible = "arm,cortex-a9-pmu",     .data = armv7_a9_pmu_init},
index f4ef3981ed0293a6ebcc887cf3428e8c848294ca..2037f72059874260558cbcb205848349ce6765a4 100644 (file)
@@ -1599,6 +1599,13 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
        return 0;
 }
 
+static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       armv7_a12_pmu_init(cpu_pmu);
+       cpu_pmu->name = "ARMv7 Cortex-A17";
+       return 0;
+}
+
 /*
  * Krait Performance Monitor Region Event Selection Register (PMRESRn)
  *
@@ -2021,6 +2028,11 @@ static inline int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
        return -ENODEV;
 }
 
+static inline int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return -ENODEV;
+}
+
 static inline int krait_pmu_init(struct arm_pmu *cpu_pmu)
 {
        return -ENODEV;
index b907d9b790ab7234171c713c4e6c9aed957868ea..1b880db2a0338fc08cc1b7355ee71eee7d142172 100644 (file)
@@ -127,6 +127,10 @@ ENDPROC(cpu_resume_after_mmu)
        .align
 ENTRY(cpu_resume)
 ARM_BE8(setend be)                     @ ensure we are in BE mode
+#ifdef CONFIG_ARM_VIRT_EXT
+       bl      __hyp_stub_install_secondary
+#endif
+       safe_svcmode_maskall r1
        mov     r1, #0
        ALT_SMP(mrc p15, 0, r0, c0, c0, 5)
        ALT_UP_B(1f)
@@ -144,7 +148,6 @@ ARM_BE8(setend be)                  @ ensure we are in BE mode
        ldr     r0, [r0, #SLEEP_SAVE_SP_PHYS]
        ldr     r0, [r0, r1, lsl #2]
 
-       setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1  @ set SVC, irqs off
        @ load phys pgd, stack, resume fn
   ARM( ldmia   r0!, {r1, sp, pc}       )
 THUMB( ldmia   r0!, {r1, r2, r3}       )
index 0bc94b1fd1ae9e73bdc95987797012396d9ef6bb..0fa8825cea04a0ca8044a1604d5f2bbf74a1b9a6 100644 (file)
@@ -91,13 +91,13 @@ static void __init parse_dt_topology(void)
 {
        const struct cpu_efficiency *cpu_eff;
        struct device_node *cn = NULL;
-       unsigned long min_capacity = (unsigned long)(-1);
+       unsigned long min_capacity = ULONG_MAX;
        unsigned long max_capacity = 0;
        unsigned long capacity = 0;
-       int alloc_size, cpu = 0;
+       int cpu = 0;
 
-       alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity);
-       __cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
+       __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity),
+                                GFP_NOWAIT);
 
        for_each_possible_cpu(cpu) {
                const u32 *rate;
index 466bd299b1a8aad54949364d976d9c5430c2375e..4be5bb150bdddea694fbf71bffa6dd8e9b855177 100644 (file)
@@ -23,7 +23,7 @@ config KVM
        select HAVE_KVM_CPU_RELAX_INTERCEPT
        select KVM_MMIO
        select KVM_ARM_HOST
-       depends on ARM_VIRT_EXT && ARM_LPAE
+       depends on ARM_VIRT_EXT && ARM_LPAE && !CPU_BIG_ENDIAN
        ---help---
          Support hosting virtualized guest machines. You will also
          need to select one or more of the processor modules below.
index 80bb1e6c2c2906d0764ae5b696e72053c8faff9c..16f804938b8fea9fee56fa93991cf8c45cf141e5 100644 (file)
@@ -42,6 +42,8 @@ static unsigned long hyp_idmap_start;
 static unsigned long hyp_idmap_end;
 static phys_addr_t hyp_idmap_vector;
 
+#define pgd_order get_order(PTRS_PER_PGD * sizeof(pgd_t))
+
 #define kvm_pmd_huge(_x)       (pmd_huge(_x) || pmd_trans_huge(_x))
 
 static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
@@ -293,14 +295,14 @@ void free_boot_hyp_pgd(void)
        if (boot_hyp_pgd) {
                unmap_range(NULL, boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
                unmap_range(NULL, boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
-               kfree(boot_hyp_pgd);
+               free_pages((unsigned long)boot_hyp_pgd, pgd_order);
                boot_hyp_pgd = NULL;
        }
 
        if (hyp_pgd)
                unmap_range(NULL, hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
 
-       kfree(init_bounce_page);
+       free_page((unsigned long)init_bounce_page);
        init_bounce_page = NULL;
 
        mutex_unlock(&kvm_hyp_pgd_mutex);
@@ -330,7 +332,7 @@ void free_hyp_pgds(void)
                for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE)
                        unmap_range(NULL, hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
 
-               kfree(hyp_pgd);
+               free_pages((unsigned long)hyp_pgd, pgd_order);
                hyp_pgd = NULL;
        }
 
@@ -1024,7 +1026,7 @@ int kvm_mmu_init(void)
                size_t len = __hyp_idmap_text_end - __hyp_idmap_text_start;
                phys_addr_t phys_base;
 
-               init_bounce_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+               init_bounce_page = (void *)__get_free_page(GFP_KERNEL);
                if (!init_bounce_page) {
                        kvm_err("Couldn't allocate HYP init bounce page\n");
                        err = -ENOMEM;
@@ -1050,8 +1052,9 @@ int kvm_mmu_init(void)
                         (unsigned long)phys_base);
        }
 
-       hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
-       boot_hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+       hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, pgd_order);
+       boot_hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, pgd_order);
+
        if (!hyp_pgd || !boot_hyp_pgd) {
                kvm_err("Hyp mode PGD not allocated\n");
                err = -ENOMEM;
index 49c914cd9c7a9c83159475a33c4a4a9961b7f4a9..9f19636fea2f656392c84fdff74f08e909db14ca 100644 (file)
@@ -11,7 +11,6 @@ menu "Broadcom SoC Selection"
 
 config ARCH_BCM_MOBILE
        bool "Broadcom Mobile SoC" if ARCH_MULTI_V7
-       depends on MMU
        select ARCH_REQUIRE_GPIOLIB
        select ARM_ERRATA_754322
        select ARM_ERRATA_764369 if SMP
@@ -33,10 +32,7 @@ config ARCH_BCM2835
        select ARM_AMBA
        select ARM_ERRATA_411920
        select ARM_TIMER_SP804
-       select CLKDEV_LOOKUP
        select CLKSRC_OF
-       select CPU_V6
-       select GENERIC_CLOCKEVENTS
        select PINCTRL
        select PINCTRL_BCM2835
        help
@@ -45,14 +41,10 @@ config ARCH_BCM2835
 
 config ARCH_BCM_5301X
        bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
-       depends on MMU
        select ARM_GIC
        select CACHE_L2X0
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
-       select HAVE_SMP
-       select COMMON_CLK
-       select GENERIC_CLOCKEVENTS
        select ARM_GLOBAL_TIMER
        select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
        select MIGHT_HAVE_PCI
index b0cb0722acd254fb411c7616504c9399d396c4b1..95c098f497b57a9af270ebd0fd4d233fcbdaa1a8 100644 (file)
@@ -1,5 +1,6 @@
 config ARCH_BERLIN
        bool "Marvell Berlin SoCs" if ARCH_MULTI_V7
+       select ARCH_REQUIRE_GPIOLIB
        select ARM_GIC
        select GENERIC_IRQ_CHIP
        select DW_APB_ICTL
@@ -20,6 +21,11 @@ config MACH_BERLIN_BG2CD
        select CACHE_L2X0
        select HAVE_ARM_TWD if SMP
 
+config MACH_BERLIN_BG2Q
+       bool "Marvell Armada 1500 Pro (BG2-Q)"
+       select CACHE_L2X0
+       select HAVE_ARM_TWD if SMP
+
 endmenu
 
 endif
index 85399c98f84a7f30657ecc57beb267d404593560..45ce065e7170f802483ebef099621f20e12772e7 100644 (file)
@@ -1092,20 +1092,21 @@ int da850_register_cpufreq(char *async_clk)
 
 static int da850_round_armrate(struct clk *clk, unsigned long rate)
 {
-       int i, ret = 0, diff;
+       int ret = 0, diff;
        unsigned int best = (unsigned int) -1;
        struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
+       struct cpufreq_frequency_table *pos;
 
        rate /= 1000; /* convert to kHz */
 
-       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               diff = table[i].frequency - rate;
+       cpufreq_for_each_entry(pos, table) {
+               diff = pos->frequency - rate;
                if (diff < 0)
                        diff = -diff;
 
                if (diff < best) {
                        best = diff;
-                       ret = table[i].frequency;
+                       ret = pos->frequency;
                }
        }
 
index bc4344aa10092dc8568ed8fe3890073e22147b53..4a5a7aedcb763e9673dd8d51b416c6f1024e3310 100644 (file)
@@ -108,6 +108,38 @@ static int __initdata gpio2_irqs[4] = {
        0,
 };
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+/*
+ * Compiling with both non-DT and DT support enabled, will
+ * break asm irq handler used by non-DT boards. Therefore,
+ * we provide a C-style irq handler even for non-DT boards,
+ * if MULTI_IRQ_HANDLER is set.
+ */
+
+static void __iomem *dove_irq_base = IRQ_VIRT_BASE;
+
+static asmlinkage void
+__exception_irq_entry dove_legacy_handle_irq(struct pt_regs *regs)
+{
+       u32 stat;
+
+       stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_LOW_OFF);
+       stat &= readl_relaxed(dove_irq_base + IRQ_MASK_LOW_OFF);
+       if (stat) {
+               unsigned int hwirq = __fls(stat);
+               handle_IRQ(hwirq, regs);
+               return;
+       }
+       stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_HIGH_OFF);
+       stat &= readl_relaxed(dove_irq_base + IRQ_MASK_HIGH_OFF);
+       if (stat) {
+               unsigned int hwirq = 32 + __fls(stat);
+               handle_IRQ(hwirq, regs);
+               return;
+       }
+}
+#endif
+
 void __init dove_init_irq(void)
 {
        int i;
@@ -115,6 +147,10 @@ void __init dove_init_irq(void)
        orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF);
        orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF);
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       set_handle_irq(dove_legacy_handle_irq);
+#endif
+
        /*
         * Initialize gpiolib for GPIOs 0-71.
         */
index 0ec9bb48fab9cd9b4ea20ab32ac9694d8d0d9881..e96923a3017b16ddb92ce75437ad594f80ab1566 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/assembler.h>
 #include <mach/ep93xx-regs.h>
 
 /*
  * r9  = ret_from_exception
  * lr  = undefined instr exit
  *
- * called from prefetch exception handler with interrupts disabled
+ * called from prefetch exception handler with interrupts enabled
  */
 ENTRY(crunch_task_enable)
+       inc_preempt_count r10, r3
+
        ldr     r8, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
 
        ldr     r1, [r8, #0x80]
        tst     r1, #0x00800000                 @ access to crunch enabled?
-       movne   pc, lr                          @ if so no business here
+       bne     2f                              @ if so no business here
        mov     r3, #0xaa                       @ unlock syscon swlock
        str     r3, [r8, #0xc0]
        orr     r1, r1, #0x00800000             @ enable access to crunch
@@ -142,7 +145,7 @@ crunch_save:
 
        teq             r0, #0                          @ anything to load?
        cfldr64eq       mvdx0, [r1, #CRUNCH_MVDX0]      @ mvdx0 was clobbered
-       moveq           pc, lr
+       beq             1f
 
 crunch_load:
        cfldr64         mvdx0, [r0, #CRUNCH_DSPSC]      @ load status word
@@ -190,6 +193,11 @@ crunch_load:
        cfldr64         mvdx14, [r0, #CRUNCH_MVDX14]
        cfldr64         mvdx15, [r0, #CRUNCH_MVDX15]
 
+1:
+#ifdef CONFIG_PREEMPT_COUNT
+       get_thread_info r10
+#endif
+2:     dec_preempt_count r10, r3
        mov     pc, lr
 
 /*
index 5740296dc4299090c2875b3e22dd81419d069a50..d56eb1a001d8517c65ab0f5f98b96ba16bdabe7e 100644 (file)
@@ -711,21 +711,6 @@ config MACH_IMX51_DT
          Include support for Freescale i.MX51 based platforms
          using the device tree for discovery
 
-config MACH_MX51_BABBAGE
-       bool "Support MX51 BABBAGE platforms"
-       select IMX_HAVE_PLATFORM_FSL_USB2_UDC
-       select IMX_HAVE_PLATFORM_IMX2_WDT
-       select IMX_HAVE_PLATFORM_IMX_I2C
-       select IMX_HAVE_PLATFORM_IMX_UART
-       select IMX_HAVE_PLATFORM_MXC_EHCI
-       select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
-       select IMX_HAVE_PLATFORM_SPI_IMX
-       select SOC_IMX51
-       help
-         Include support for MX51 Babbage platform, also known as MX51EVK in
-         u-boot. This includes specific configurations for the board and its
-         peripherals.
-
 config MACH_EUKREA_CPUIMX51SD
        bool "Support Eukrea CPUIMX51SD module"
        select IMX_HAVE_PLATFORM_FSL_USB2_UDC
index f4ed83032dd0fce3f9e4faada7216a0c95d2226b..8dd377be88a611e3eca94b7c75f9eae9355c0e7a 100644 (file)
@@ -109,7 +109,6 @@ endif
 obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
 
 # i.MX5 based machines
-obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o
 obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o
 obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd51-baseboard.o
 
index a2ecc006b322c2d6bdb328e353aa3eadcdcac436..4ba587da89d2ef69bf8d96dcdbf27cf8ad6e93aa 100644 (file)
  * parent - fixed parent.  No clk_set_parent support
  */
 
-#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+struct clk_gate2 {
+       struct clk_hw hw;
+       void __iomem    *reg;
+       u8              bit_idx;
+       u8              flags;
+       spinlock_t      *lock;
+       unsigned int    *share_count;
+};
+
+#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
 
 static int clk_gate2_enable(struct clk_hw *hw)
 {
-       struct clk_gate *gate = to_clk_gate(hw);
+       struct clk_gate2 *gate = to_clk_gate2(hw);
        u32 reg;
        unsigned long flags = 0;
 
-       if (gate->lock)
-               spin_lock_irqsave(gate->lock, flags);
+       spin_lock_irqsave(gate->lock, flags);
+
+       if (gate->share_count && (*gate->share_count)++ > 0)
+               goto out;
 
        reg = readl(gate->reg);
        reg |= 3 << gate->bit_idx;
        writel(reg, gate->reg);
 
-       if (gate->lock)
-               spin_unlock_irqrestore(gate->lock, flags);
+out:
+       spin_unlock_irqrestore(gate->lock, flags);
 
        return 0;
 }
 
 static void clk_gate2_disable(struct clk_hw *hw)
 {
-       struct clk_gate *gate = to_clk_gate(hw);
+       struct clk_gate2 *gate = to_clk_gate2(hw);
        u32 reg;
        unsigned long flags = 0;
 
-       if (gate->lock)
-               spin_lock_irqsave(gate->lock, flags);
+       spin_lock_irqsave(gate->lock, flags);
+
+       if (gate->share_count && --(*gate->share_count) > 0)
+               goto out;
 
        reg = readl(gate->reg);
        reg &= ~(3 << gate->bit_idx);
        writel(reg, gate->reg);
 
-       if (gate->lock)
-               spin_unlock_irqrestore(gate->lock, flags);
+out:
+       spin_unlock_irqrestore(gate->lock, flags);
 }
 
 static int clk_gate2_is_enabled(struct clk_hw *hw)
 {
        u32 reg;
-       struct clk_gate *gate = to_clk_gate(hw);
+       struct clk_gate2 *gate = to_clk_gate2(hw);
 
        reg = readl(gate->reg);
 
@@ -87,21 +100,23 @@ static struct clk_ops clk_gate2_ops = {
 struct clk *clk_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate2_flags, spinlock_t *lock)
+               u8 clk_gate2_flags, spinlock_t *lock,
+               unsigned int *share_count)
 {
-       struct clk_gate *gate;
+       struct clk_gate2 *gate;
        struct clk *clk;
        struct clk_init_data init;
 
-       gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+       gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL);
        if (!gate)
                return ERR_PTR(-ENOMEM);
 
-       /* struct clk_gate assignments */
+       /* struct clk_gate2 assignments */
        gate->reg = reg;
        gate->bit_idx = bit_idx;
        gate->flags = clk_gate2_flags;
        gate->lock = lock;
+       gate->share_count = share_count;
 
        init.name = name;
        init.ops = &clk_gate2_ops;
index dc36e6c2f1da5b83e57e41612a7caca3afce8879..ae578c096ad82ebb3590e941f57d9ee45ca308bb 100644 (file)
@@ -62,6 +62,10 @@ static struct clk_onecell_data clk_data;
 
 static const char *cpu_sel_clks[] = { "mpll", "mpll_cpu_3_4", };
 static const char *per_sel_clks[] = { "ahb", "upll", };
+static const char *cko_sel_clks[] = { "dummy", "osc", "cpu", "ahb",
+                                     "ipg", "dummy", "dummy", "dummy",
+                                     "dummy", "dummy", "per0", "per2",
+                                     "per13", "per14", "usbotg_ahb", "dummy",};
 
 enum mx25_clks {
        dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg,
@@ -82,7 +86,7 @@ enum mx25_clks {
        pwm2_ipg, pwm3_ipg, pwm4_ipg, rngb_ipg, reserved16, scc_ipg, sdma_ipg,
        sim1_ipg, sim2_ipg, slcdc_ipg, spba_ipg, ssi1_ipg, ssi2_ipg, tsc_ipg,
        uart1_ipg, uart2_ipg, uart3_ipg, uart4_ipg, uart5_ipg, reserved17,
-       wdt_ipg, clk_max
+       wdt_ipg, cko_div, cko_sel, cko, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -117,6 +121,9 @@ static int __init __mx25_clocks_init(unsigned long osc_rate)
        clk[per13_sel] = imx_clk_mux("per13_sel", ccm(CCM_MCR), 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
        clk[per14_sel] = imx_clk_mux("per14_sel", ccm(CCM_MCR), 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
        clk[per15_sel] = imx_clk_mux("per15_sel", ccm(CCM_MCR), 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+       clk[cko_div] = imx_clk_divider("cko_div", "cko_sel", ccm(CCM_MCR), 24, 6);
+       clk[cko_sel] = imx_clk_mux("cko_sel", ccm(CCM_MCR), 20, 4, cko_sel_clks, ARRAY_SIZE(cko_sel_clks));
+       clk[cko] = imx_clk_gate("cko", "cko_div", ccm(CCM_MCR),  30);
        clk[per0] = imx_clk_divider("per0", "per0_sel", ccm(CCM_PCDR0), 0, 6);
        clk[per1] = imx_clk_divider("per1", "per1_sel", ccm(CCM_PCDR0), 8, 6);
        clk[per2] = imx_clk_divider("per2", "per2_sel", ccm(CCM_PCDR0), 16, 6);
@@ -230,6 +237,12 @@ static int __init __mx25_clocks_init(unsigned long osc_rate)
        clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0");
        clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0");
 
+       /*
+        * Let's initially set up CLKO parent as ipg, since this configuration
+        * is used on some imx25 board designs to clock the audio codec.
+        */
+       clk_set_parent(clk[cko_sel], clk[ipg]);
+
        return 0;
 }
 
@@ -304,8 +317,6 @@ int __init mx25_clocks_init(void)
 int __init mx25_clocks_init_dt(void)
 {
        struct device_node *np;
-       void __iomem *base;
-       int irq;
        unsigned long osc_rate = 24000000;
 
        /* retrieve the freqency of fixed clocks from device tree */
@@ -325,12 +336,7 @@ int __init mx25_clocks_init_dt(void)
 
        __mx25_clocks_init(osc_rate);
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx25-gpt");
-       base = of_iomap(np, 0);
-       WARN_ON(!base);
-       irq = irq_of_parse_and_map(np, 0);
-
-       mxc_timer_init(base, irq);
+       mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx25-gpt"));
 
        return 0;
 }
index d2da8908b26859370f797b746515f501bee89ad1..317a662626d6ca11c7848a59912c029905c40c93 100644 (file)
@@ -82,7 +82,8 @@ enum mx27_clks {
        csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate,
        uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate,
        uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel,
-       mpll_sel, spll_gate, clk_max
+       mpll_sel, spll_gate, mshc_div, rtic_ipg_gate, mshc_ipg_gate,
+       rtic_ahb_gate, mshc_baud_gate, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -117,6 +118,7 @@ int __init mx27_clocks_init(unsigned long fref)
                clk[ipg] = imx_clk_divider("ipg", "ahb", CCM_CSCR, 8, 1);
        }
 
+       clk[mshc_div] = imx_clk_divider("mshc_div", "ahb", CCM_PCDR0, 0, 6);
        clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", CCM_PCDR0, 6, 4);
        clk[per1_div] = imx_clk_divider("per1_div", "mpll_main2", CCM_PCDR1, 0, 6);
        clk[per2_div] = imx_clk_divider("per2_div", "mpll_main2", CCM_PCDR1, 8, 6);
@@ -145,9 +147,11 @@ int __init mx27_clocks_init(unsigned long fref)
        clk[sdhc1_ipg_gate] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 5);
        clk[scc_ipg_gate] = imx_clk_gate("scc_ipg_gate", "ipg", CCM_PCCR0, 6);
        clk[sahara_ipg_gate] = imx_clk_gate("sahara_ipg_gate", "ipg", CCM_PCCR0, 7);
+       clk[rtic_ipg_gate] = imx_clk_gate("rtic_ipg_gate", "ipg", CCM_PCCR0, 8);
        clk[rtc_ipg_gate] = imx_clk_gate("rtc_ipg_gate", "ipg", CCM_PCCR0, 9);
        clk[pwm_ipg_gate] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR0, 11);
        clk[owire_ipg_gate] = imx_clk_gate("owire_ipg_gate", "ipg", CCM_PCCR0, 12);
+       clk[mshc_ipg_gate] = imx_clk_gate("mshc_ipg_gate", "ipg", CCM_PCCR0, 13);
        clk[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 14);
        clk[kpp_ipg_gate] = imx_clk_gate("kpp_ipg_gate", "ipg", CCM_PCCR0, 15);
        clk[iim_ipg_gate] = imx_clk_gate("iim_ipg_gate", "ipg", CCM_PCCR0, 16);
@@ -166,6 +170,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk[cspi3_ipg_gate] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR0, 29);
        clk[cspi2_ipg_gate] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 30);
        clk[cspi1_ipg_gate] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 31);
+       clk[mshc_baud_gate] = imx_clk_gate("mshc_baud_gate", "mshc_div", CCM_PCCR1, 2);
        clk[nfc_baud_gate] = imx_clk_gate("nfc_baud_gate", "nfc_div", CCM_PCCR1,  3);
        clk[ssi2_baud_gate] = imx_clk_gate("ssi2_baud_gate", "ssi2_div", CCM_PCCR1,  4);
        clk[ssi1_baud_gate] = imx_clk_gate("ssi1_baud_gate", "ssi1_div", CCM_PCCR1,  5);
@@ -177,6 +182,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk[usb_ahb_gate] = imx_clk_gate("usb_ahb_gate", "ahb", CCM_PCCR1, 11);
        clk[slcdc_ahb_gate] = imx_clk_gate("slcdc_ahb_gate", "ahb", CCM_PCCR1, 12);
        clk[sahara_ahb_gate] = imx_clk_gate("sahara_ahb_gate", "ahb", CCM_PCCR1, 13);
+       clk[rtic_ahb_gate] = imx_clk_gate("rtic_ahb_gate", "ahb", CCM_PCCR1, 14);
        clk[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", CCM_PCCR1, 15);
        clk[vpu_ahb_gate] = imx_clk_gate("vpu_ahb_gate", "ahb", CCM_PCCR1, 16);
        clk[fec_ahb_gate] = imx_clk_gate("fec_ahb_gate", "ahb", CCM_PCCR1, 17);
@@ -221,16 +227,6 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.5");
        clk_register_clkdev(clk[gpt1_ipg_gate], "ipg", "imx-gpt.0");
        clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.0");
-       clk_register_clkdev(clk[gpt2_ipg_gate], "ipg", "imx-gpt.1");
-       clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.1");
-       clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2");
-       clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.2");
-       clk_register_clkdev(clk[gpt4_ipg_gate], "ipg", "imx-gpt.3");
-       clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.3");
-       clk_register_clkdev(clk[gpt5_ipg_gate], "ipg", "imx-gpt.4");
-       clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.4");
-       clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5");
-       clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5");
        clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.0");
        clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "imx21-mmc.0");
        clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.1");
@@ -278,14 +274,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[emma_ipg_gate], "emma-ipg", "imx27-camera.0");
        clk_register_clkdev(clk[emma_ahb_gate], "ahb", "m2m-emmaprp.0");
        clk_register_clkdev(clk[emma_ipg_gate], "ipg", "m2m-emmaprp.0");
-       clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL);
-       clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL);
-       clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL);
-       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, "cpu0");
-       clk_register_clkdev(clk[emi_ahb_gate], "emi_ahb" , NULL);
 
        mxc_timer_init(MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), MX27_INT_GPT1);
 
@@ -296,7 +285,6 @@ int __init mx27_clocks_init(unsigned long fref)
        return 0;
 }
 
-#ifdef CONFIG_OF
 int __init mx27_clocks_init_dt(void)
 {
        struct device_node *np;
@@ -312,4 +300,3 @@ int __init mx27_clocks_init_dt(void)
 
        return mx27_clocks_init(fref);
 }
-#endif
index b5b65f3efaf1c30651686f9d79ee004318815b66..4a9de0835eb1d0a2616af36ce3d1c899533ef996 100644 (file)
@@ -191,7 +191,6 @@ int __init mx31_clocks_init(unsigned long fref)
        return 0;
 }
 
-#ifdef CONFIG_OF
 int __init mx31_clocks_init_dt(void)
 {
        struct device_node *np;
@@ -207,4 +206,3 @@ int __init mx31_clocks_init_dt(void)
 
        return mx31_clocks_init(fref);
 }
-#endif
index 568ef0a4de84b8892c0ee5b84fd339a5fecbf67a..21d2b111c83d5e5c778445545e2879b60a33b667 100644 (file)
@@ -322,9 +322,8 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,
 
 static void __init mx50_clocks_init(struct device_node *np)
 {
-       void __iomem *base;
        unsigned long r;
-       int i, irq;
+       int i;
 
        clk[IMX5_CLK_PLL1_SW]           = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE);
        clk[IMX5_CLK_PLL2_SW]           = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE);
@@ -372,11 +371,7 @@ static void __init mx50_clocks_init(struct device_node *np)
        r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
        clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx50-gpt");
-       base = of_iomap(np, 0);
-       WARN_ON(!base);
-       irq = irq_of_parse_and_map(np, 0);
-       mxc_timer_init(base, irq);
+       mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx50-gpt"));
 }
 CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);
 
@@ -436,7 +431,6 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
 
        clk_register_clkdev(clk[IMX5_CLK_HSI2C_GATE], NULL, "imx21-i2c.2");
        clk_register_clkdev(clk[IMX5_CLK_MX51_MIPI], "mipi_hsp", NULL);
-       clk_register_clkdev(clk[IMX5_CLK_VPU_GATE], NULL, "imx51-vpu.0");
        clk_register_clkdev(clk[IMX5_CLK_FEC_GATE], NULL, "imx27-fec.0");
        clk_register_clkdev(clk[IMX5_CLK_USB_PHY_GATE], "phy", "mxc-ehci.0");
        clk_register_clkdev(clk[IMX5_CLK_ESDHC1_IPG_GATE], "ipg", "sdhci-esdhc-imx51.0");
@@ -492,9 +486,8 @@ CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init_dt);
 
 static void __init mx53_clocks_init(struct device_node *np)
 {
-       int i, irq;
+       int i;
        unsigned long r;
-       void __iomem *base;
 
        clk[IMX5_CLK_PLL1_SW]           = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE);
        clk[IMX5_CLK_PLL2_SW]           = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE);
@@ -561,7 +554,6 @@ static void __init mx53_clocks_init(struct device_node *np)
 
        mx5_clocks_common_init(0, 0, 0, 0);
 
-       clk_register_clkdev(clk[IMX5_CLK_VPU_GATE], NULL, "imx53-vpu.0");
        clk_register_clkdev(clk[IMX5_CLK_I2C3_GATE], NULL, "imx21-i2c.2");
        clk_register_clkdev(clk[IMX5_CLK_FEC_GATE], NULL, "imx25-fec.0");
        clk_register_clkdev(clk[IMX5_CLK_USB_PHY1_GATE], "usb_phy1", "mxc-ehci.0");
@@ -592,10 +584,6 @@ static void __init mx53_clocks_init(struct device_node *np)
        r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
        clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt");
-       base = of_iomap(np, 0);
-       WARN_ON(!base);
-       irq = irq_of_parse_and_map(np, 0);
-       mxc_timer_init(base, irq);
+       mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt"));
 }
 CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
index 2b4d6acfa34abdd67a6c6ed9becb44345dd17929..8e795dea02ece013f4bb0dc9caa1bda63bc5ffc1 100644 (file)
@@ -107,7 +107,7 @@ enum mx6q_clks {
        sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
        usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow,
        spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div,
-       lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max
+       lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, esai_ahb, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -140,11 +140,13 @@ static struct clk_div_table video_div_table[] = {
        { /* sentinel */ }
 };
 
+static unsigned int share_count_esai;
+
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
-       int i, irq;
+       int i;
        int ret;
 
        clk[dummy] = imx_clk_fixed("dummy", 0);
@@ -352,9 +354,14 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[ecspi2]       = imx_clk_gate2("ecspi2",        "ecspi_root",        base + 0x6c, 2);
        clk[ecspi3]       = imx_clk_gate2("ecspi3",        "ecspi_root",        base + 0x6c, 4);
        clk[ecspi4]       = imx_clk_gate2("ecspi4",        "ecspi_root",        base + 0x6c, 6);
-       clk[ecspi5]       = imx_clk_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
+       if (cpu_is_imx6dl())
+               /* ecspi5 is replaced with i2c4 on imx6dl & imx6s */
+               clk[ecspi5] = imx_clk_gate2("i2c4",        "ipg_per",           base + 0x6c, 8);
+       else
+               clk[ecspi5] = imx_clk_gate2("ecspi5",      "ecspi_root",        base + 0x6c, 8);
        clk[enet]         = imx_clk_gate2("enet",          "ipg",               base + 0x6c, 10);
-       clk[esai]         = imx_clk_gate2("esai",          "esai_podf",         base + 0x6c, 16);
+       clk[esai]         = imx_clk_gate2_shared("esai",   "esai_podf",         base + 0x6c, 16, &share_count_esai);
+       clk[esai_ahb]     = imx_clk_gate2_shared("esai_ahb", "ahb",             base + 0x6c, 16, &share_count_esai);
        clk[gpt_ipg]      = imx_clk_gate2("gpt_ipg",       "ipg",               base + 0x6c, 20);
        clk[gpt_ipg_per]  = imx_clk_gate2("gpt_ipg_per",   "ipg_per",           base + 0x6c, 22);
        if (cpu_is_imx6dl())
@@ -489,10 +496,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        /* Set initial power mode */
        imx6q_set_lpm(WAIT_CLOCKED);
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
-       base = of_iomap(np, 0);
-       WARN_ON(!base);
-       irq = irq_of_parse_and_map(np, 0);
-       mxc_timer_init(base, irq);
+       mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"));
 }
 CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
index f7073c0782fb0f1ce45b384357241f97948fedc3..21cf06cebade559b59b787e88b4c8876822d2f59 100644 (file)
@@ -169,7 +169,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
-       int irq;
        int i;
        int ret;
 
@@ -385,9 +384,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
        imx6q_set_lpm(WAIT_CLOCKED);
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt");
-       base = of_iomap(np, 0);
-       WARN_ON(!base);
-       irq = irq_of_parse_and_map(np, 0);
-       mxc_timer_init(base, irq);
+       mxc_timer_init_dt(np);
 }
 CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
index 048c5ad8a80b67ed54b7d2dfa7f2d746a1356f30..e29f6ebe9f39d0047abce6e010b9e577a1db14bc 100644 (file)
@@ -28,7 +28,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
 struct clk *clk_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
-               u8 clk_gate_flags, spinlock_t *lock);
+               u8 clk_gate_flags, spinlock_t *lock,
+               unsigned int *share_count);
 
 struct clk * imx_obtain_fixed_clock(
                        const char *name, unsigned long rate);
@@ -37,7 +38,15 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
        return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-                       shift, 0, &imx_ccm_lock);
+                       shift, 0, &imx_ccm_lock, NULL);
+}
+
+static inline struct clk *imx_clk_gate2_shared(const char *name,
+               const char *parent, void __iomem *reg, u8 shift,
+               unsigned int *share_count)
+{
+       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+                       shift, 0, &imx_ccm_lock, share_count);
 }
 
 struct clk *imx_clk_pfd(const char *name, const char *parent_name,
index b5241ea7670642fd2902f1896ad8c666daea3f4f..4facd01d1c75f8ba0146ffbd2c63e8b1b63fdc6c 100644 (file)
@@ -17,6 +17,7 @@ struct irq_data;
 struct platform_device;
 struct pt_regs;
 struct clk;
+struct device_node;
 enum mxc_cpu_pwr_mode;
 
 void mx1_map_io(void);
@@ -56,6 +57,7 @@ void imx51_init_late(void);
 void imx53_init_late(void);
 void epit_timer_init(void __iomem *base, int irq);
 void mxc_timer_init(void __iomem *, int);
+void mxc_timer_init_dt(struct device_node *);
 int mx1_clocks_init(unsigned long fref);
 int mx21_clocks_init(unsigned long lref, unsigned long fref);
 int mx25_clocks_init(void);
index 11bd01d402f29019888b4cf3a8ef02ed70b4619c..0dc0651825b144fca488c582badba9948bb964b2 100644 (file)
@@ -12,7 +12,7 @@
 #define imx_mx2_emmaprp_data_entry_single(soc)                         \
        {                                                               \
                .iobase = soc ## _EMMAPRP_BASE_ADDR,                    \
-               .iosize = SZ_32,                                        \
+               .iosize = SZ_256,                                       \
                .irq = soc ## _INT_EMMAPRP,                             \
        }
 
index a06aa4dc37fc4f99ca4e24d31e069aa40daf9242..30c30fdae53fe3a468d59e87a30671dec790a4e3 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
+#include <linux/basic_mmio_gpio.h>
 #include <linux/gpio.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
 
 #include "common.h"
 #include "devices-imx21.h"
 #include "hardware.h"
 #include "iomux-mx21.h"
 
-/*
- * Memory-mapped I/O on MX21ADS base board
- */
-#define MX21ADS_MMIO_BASE_ADDR   0xf5000000
-#define MX21ADS_MMIO_SIZE        0xc00000
-
-#define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
-               (MX21ADS_MMIO_BASE_ADDR + (offset))
+#define MX21ADS_CS8900A_REG            (MX21_CS1_BASE_ADDR + 0x000000)
+#define MX21ADS_ST16C255_IOBASE_REG    (MX21_CS1_BASE_ADDR + 0x200000)
+#define MX21ADS_VERSION_REG            (MX21_CS1_BASE_ADDR + 0x400000)
+#define MX21ADS_IO_REG                 (MX21_CS1_BASE_ADDR + 0x800000)
 
-#define MX21ADS_CS8900A_MMIO_SIZE   0x200000
-#define MX21ADS_CS8900A_IRQ_GPIO    IMX_GPIO_NR(5, 11)
-#define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000)
-#define MX21ADS_VERSION_REG         MX21ADS_REG_ADDR(0x400000)
-#define MX21ADS_IO_REG              MX21ADS_REG_ADDR(0x800000)
+#define MX21ADS_MMC_CD                 IMX_GPIO_NR(4, 25)
+#define MX21ADS_CS8900A_IRQ_GPIO       IMX_GPIO_NR(5, 11)
+#define MX21ADS_MMGPIO_BASE            (6 * 32)
 
 /* MX21ADS_IO_REG bit definitions */
-#define MX21ADS_IO_SD_WP        0x0001 /* read */
-#define MX21ADS_IO_TP6          0x0001 /* write */
-#define MX21ADS_IO_SW_SEL       0x0002 /* read */
-#define MX21ADS_IO_TP7          0x0002 /* write */
-#define MX21ADS_IO_RESET_E_UART 0x0004
-#define MX21ADS_IO_RESET_BASE   0x0008
-#define MX21ADS_IO_CSI_CTL2     0x0010
-#define MX21ADS_IO_CSI_CTL1     0x0020
-#define MX21ADS_IO_CSI_CTL0     0x0040
-#define MX21ADS_IO_UART1_EN     0x0080
-#define MX21ADS_IO_UART4_EN     0x0100
-#define MX21ADS_IO_LCDON        0x0200
-#define MX21ADS_IO_IRDA_EN      0x0400
-#define MX21ADS_IO_IRDA_FIR_SEL 0x0800
-#define MX21ADS_IO_IRDA_MD0_B   0x1000
-#define MX21ADS_IO_IRDA_MD1     0x2000
-#define MX21ADS_IO_LED4_ON      0x4000
-#define MX21ADS_IO_LED3_ON      0x8000
+#define MX21ADS_IO_SD_WP               (MX21ADS_MMGPIO_BASE + 0)
+#define MX21ADS_IO_TP6                 (MX21ADS_IO_SD_WP)
+#define MX21ADS_IO_SW_SEL              (MX21ADS_MMGPIO_BASE + 1)
+#define MX21ADS_IO_TP7                 (MX21ADS_IO_SW_SEL)
+#define MX21ADS_IO_RESET_E_UART                (MX21ADS_MMGPIO_BASE + 2)
+#define MX21ADS_IO_RESET_BASE          (MX21ADS_MMGPIO_BASE + 3)
+#define MX21ADS_IO_CSI_CTL2            (MX21ADS_MMGPIO_BASE + 4)
+#define MX21ADS_IO_CSI_CTL1            (MX21ADS_MMGPIO_BASE + 5)
+#define MX21ADS_IO_CSI_CTL0            (MX21ADS_MMGPIO_BASE + 6)
+#define MX21ADS_IO_UART1_EN            (MX21ADS_MMGPIO_BASE + 7)
+#define MX21ADS_IO_UART4_EN            (MX21ADS_MMGPIO_BASE + 8)
+#define MX21ADS_IO_LCDON               (MX21ADS_MMGPIO_BASE + 9)
+#define MX21ADS_IO_IRDA_EN             (MX21ADS_MMGPIO_BASE + 10)
+#define MX21ADS_IO_IRDA_FIR_SEL                (MX21ADS_MMGPIO_BASE + 11)
+#define MX21ADS_IO_IRDA_MD0_B          (MX21ADS_MMGPIO_BASE + 12)
+#define MX21ADS_IO_IRDA_MD1            (MX21ADS_MMGPIO_BASE + 13)
+#define MX21ADS_IO_LED4_ON             (MX21ADS_MMGPIO_BASE + 14)
+#define MX21ADS_IO_LED3_ON             (MX21ADS_MMGPIO_BASE + 15)
 
 static const int mx21ads_pins[] __initconst = {
 
@@ -143,11 +138,8 @@ static struct physmap_flash_data mx21ads_flash_data = {
        .width = 4,
 };
 
-static struct resource mx21ads_flash_resource = {
-       .start = MX21_CS0_BASE_ADDR,
-       .end = MX21_CS0_BASE_ADDR + 0x02000000 - 1,
-       .flags = IORESOURCE_MEM,
-};
+static struct resource mx21ads_flash_resource =
+       DEFINE_RES_MEM(MX21_CS0_BASE_ADDR, SZ_32M);
 
 static struct platform_device mx21ads_nor_mtd_device = {
        .name = "physmap-flash",
@@ -160,7 +152,7 @@ static struct platform_device mx21ads_nor_mtd_device = {
 };
 
 static struct resource mx21ads_cs8900_resources[] __initdata = {
-       DEFINE_RES_MEM(MX21_CS1_BASE_ADDR, MX21ADS_CS8900A_MMIO_SIZE),
+       DEFINE_RES_MEM(MX21ADS_CS8900A_REG, SZ_1K),
        /* irq number is run-time assigned */
        DEFINE_RES_IRQ(-1),
 };
@@ -179,24 +171,50 @@ static const struct imxuart_platform_data uart_pdata_rts __initconst = {
 static const struct imxuart_platform_data uart_pdata_norts __initconst = {
 };
 
-static int mx21ads_fb_init(struct platform_device *pdev)
-{
-       u16 tmp;
+static struct resource mx21ads_mmgpio_resource =
+       DEFINE_RES_MEM_NAMED(MX21ADS_IO_REG, SZ_2, "dat");
 
-       tmp = __raw_readw(MX21ADS_IO_REG);
-       tmp |= MX21ADS_IO_LCDON;
-       __raw_writew(tmp, MX21ADS_IO_REG);
-       return 0;
-}
+static struct bgpio_pdata mx21ads_mmgpio_pdata = {
+       .base   = MX21ADS_MMGPIO_BASE,
+       .ngpio  = 16,
+};
 
-static void mx21ads_fb_exit(struct platform_device *pdev)
-{
-       u16 tmp;
+static struct platform_device mx21ads_mmgpio = {
+       .name = "basic-mmio-gpio",
+       .id = PLATFORM_DEVID_AUTO,
+       .resource = &mx21ads_mmgpio_resource,
+       .num_resources = 1,
+       .dev = {
+               .platform_data = &mx21ads_mmgpio_pdata,
+       },
+};
 
-       tmp = __raw_readw(MX21ADS_IO_REG);
-       tmp &= ~MX21ADS_IO_LCDON;
-       __raw_writew(tmp, MX21ADS_IO_REG);
-}
+static struct regulator_consumer_supply mx21ads_lcd_regulator_consumer =
+       REGULATOR_SUPPLY("lcd", "imx-fb.0");
+
+static struct regulator_init_data mx21ads_lcd_regulator_init_data = {
+       .constraints = {
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .consumer_supplies      = &mx21ads_lcd_regulator_consumer,
+       .num_consumer_supplies  = 1,
+};
+
+static struct fixed_voltage_config mx21ads_lcd_regulator_pdata = {
+       .supply_name    = "LCD",
+       .microvolts     = 3300000,
+       .gpio           = MX21ADS_IO_LCDON,
+       .enable_high    = 1,
+       .init_data      = &mx21ads_lcd_regulator_init_data,
+};
+
+static struct platform_device mx21ads_lcd_regulator = {
+       .name = "reg-fixed-voltage",
+       .id = PLATFORM_DEVID_AUTO,
+       .dev = {
+               .platform_data = &mx21ads_lcd_regulator_pdata,
+       },
+};
 
 /*
  * Connected is a portrait Sharp-QVGA display
@@ -229,26 +247,30 @@ static const struct imx_fb_platform_data mx21ads_fb_data __initconst = {
        .pwmr           = 0x00a903ff,
        .lscr1          = 0x00120300,
        .dmacr          = 0x00020008,
-
-       .init = mx21ads_fb_init,
-       .exit = mx21ads_fb_exit,
 };
 
 static int mx21ads_sdhc_get_ro(struct device *dev)
 {
-       return (__raw_readw(MX21ADS_IO_REG) & MX21ADS_IO_SD_WP) ? 1 : 0;
+       return gpio_get_value(MX21ADS_IO_SD_WP);
 }
 
 static int mx21ads_sdhc_init(struct device *dev, irq_handler_t detect_irq,
        void *data)
 {
-       return request_irq(gpio_to_irq(IMX_GPIO_NR(4, 25)), detect_irq,
-               IRQF_TRIGGER_FALLING, "mmc-detect", data);
+       int ret;
+
+       ret = gpio_request(MX21ADS_IO_SD_WP, "mmc-ro");
+       if (ret)
+               return ret;
+
+       return request_irq(gpio_to_irq(MX21ADS_MMC_CD), detect_irq,
+                          IRQF_TRIGGER_FALLING, "mmc-detect", data);
 }
 
 static void mx21ads_sdhc_exit(struct device *dev, void *data)
 {
-       free_irq(gpio_to_irq(IMX_GPIO_NR(4, 25)), data);
+       free_irq(gpio_to_irq(MX21ADS_MMC_CD), data);
+       gpio_free(MX21ADS_IO_SD_WP);
 }
 
 static const struct imxmmc_platform_data mx21ads_sdhc_pdata __initconst = {
@@ -264,29 +286,9 @@ mx21ads_nand_board_info __initconst = {
        .hw_ecc = 1,
 };
 
-static struct map_desc mx21ads_io_desc[] __initdata = {
-       /*
-        * Memory-mapped I/O on MX21ADS Base board:
-        *   - CS8900A Ethernet controller
-        *   - ST16C2552CJ UART
-        *   - CPU and Base board version
-        *   - Base board I/O register
-        */
-       {
-               .virtual = MX21ADS_MMIO_BASE_ADDR,
-               .pfn = __phys_to_pfn(MX21_CS1_BASE_ADDR),
-               .length = MX21ADS_MMIO_SIZE,
-               .type = MT_DEVICE,
-       },
-};
-
-static void __init mx21ads_map_io(void)
-{
-       mx21_map_io();
-       iotable_init(mx21ads_io_desc, ARRAY_SIZE(mx21ads_io_desc));
-}
-
 static struct platform_device *platform_devices[] __initdata = {
+       &mx21ads_mmgpio,
+       &mx21ads_lcd_regulator,
        &mx21ads_nor_mtd_device,
 };
 
@@ -300,12 +302,13 @@ static void __init mx21ads_board_init(void)
        imx21_add_imx_uart0(&uart_pdata_rts);
        imx21_add_imx_uart2(&uart_pdata_norts);
        imx21_add_imx_uart3(&uart_pdata_rts);
-       imx21_add_imx_fb(&mx21ads_fb_data);
        imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata);
        imx21_add_mxc_nand(&mx21ads_nand_board_info);
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
+       imx21_add_imx_fb(&mx21ads_fb_data);
+
        mx21ads_cs8900_resources[1].start =
                        gpio_to_irq(MX21ADS_CS8900A_IRQ_GPIO);
        mx21ads_cs8900_resources[1].end =
@@ -321,7 +324,7 @@ static void __init mx21ads_timer_init(void)
 MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
        /* maintainer: Freescale Semiconductor, Inc. */
        .atag_offset = 0x100,
-       .map_io = mx21ads_map_io,
+       .map_io         = mx21_map_io,
        .init_early = imx21_init_early,
        .init_irq = mx21_init_irq,
        .handle_irq = imx21_handle_irq,
diff --git a/arch/arm/mach-imx/mach-mx51_babbage.c b/arch/arm/mach-imx/mach-mx51_babbage.c
deleted file mode 100644 (file)
index f3d264a..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.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
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/input.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-#include "devices-imx51.h"
-#include "hardware.h"
-#include "iomux-mx51.h"
-
-#define BABBAGE_USB_HUB_RESET  IMX_GPIO_NR(1, 7)
-#define BABBAGE_USBH1_STP      IMX_GPIO_NR(1, 27)
-#define BABBAGE_USB_PHY_RESET  IMX_GPIO_NR(2, 5)
-#define BABBAGE_FEC_PHY_RESET  IMX_GPIO_NR(2, 14)
-#define BABBAGE_POWER_KEY      IMX_GPIO_NR(2, 21)
-#define BABBAGE_ECSPI1_CS0     IMX_GPIO_NR(4, 24)
-#define BABBAGE_ECSPI1_CS1     IMX_GPIO_NR(4, 25)
-#define BABBAGE_SD2_CD         IMX_GPIO_NR(1, 6)
-#define BABBAGE_SD2_WP         IMX_GPIO_NR(1, 5)
-
-/* USB_CTRL_1 */
-#define MX51_USB_CTRL_1_OFFSET                 0x10
-#define MX51_USB_CTRL_UH1_EXT_CLK_EN           (1 << 25)
-
-#define        MX51_USB_PLLDIV_12_MHZ          0x00
-#define        MX51_USB_PLL_DIV_19_2_MHZ       0x01
-#define        MX51_USB_PLL_DIV_24_MHZ 0x02
-
-static struct gpio_keys_button babbage_buttons[] = {
-       {
-               .gpio           = BABBAGE_POWER_KEY,
-               .code           = BTN_0,
-               .desc           = "PWR",
-               .active_low     = 1,
-               .wakeup         = 1,
-       },
-};
-
-static const struct gpio_keys_platform_data imx_button_data __initconst = {
-       .buttons        = babbage_buttons,
-       .nbuttons       = ARRAY_SIZE(babbage_buttons),
-};
-
-static iomux_v3_cfg_t mx51babbage_pads[] = {
-       /* UART1 */
-       MX51_PAD_UART1_RXD__UART1_RXD,
-       MX51_PAD_UART1_TXD__UART1_TXD,
-       MX51_PAD_UART1_RTS__UART1_RTS,
-       MX51_PAD_UART1_CTS__UART1_CTS,
-
-       /* UART2 */
-       MX51_PAD_UART2_RXD__UART2_RXD,
-       MX51_PAD_UART2_TXD__UART2_TXD,
-
-       /* UART3 */
-       MX51_PAD_EIM_D25__UART3_RXD,
-       MX51_PAD_EIM_D26__UART3_TXD,
-       MX51_PAD_EIM_D27__UART3_RTS,
-       MX51_PAD_EIM_D24__UART3_CTS,
-
-       /* I2C1 */
-       MX51_PAD_EIM_D16__I2C1_SDA,
-       MX51_PAD_EIM_D19__I2C1_SCL,
-
-       /* I2C2 */
-       MX51_PAD_KEY_COL4__I2C2_SCL,
-       MX51_PAD_KEY_COL5__I2C2_SDA,
-
-       /* HSI2C */
-       MX51_PAD_I2C1_CLK__I2C1_CLK,
-       MX51_PAD_I2C1_DAT__I2C1_DAT,
-
-       /* USB HOST1 */
-       MX51_PAD_USBH1_CLK__USBH1_CLK,
-       MX51_PAD_USBH1_DIR__USBH1_DIR,
-       MX51_PAD_USBH1_NXT__USBH1_NXT,
-       MX51_PAD_USBH1_DATA0__USBH1_DATA0,
-       MX51_PAD_USBH1_DATA1__USBH1_DATA1,
-       MX51_PAD_USBH1_DATA2__USBH1_DATA2,
-       MX51_PAD_USBH1_DATA3__USBH1_DATA3,
-       MX51_PAD_USBH1_DATA4__USBH1_DATA4,
-       MX51_PAD_USBH1_DATA5__USBH1_DATA5,
-       MX51_PAD_USBH1_DATA6__USBH1_DATA6,
-       MX51_PAD_USBH1_DATA7__USBH1_DATA7,
-
-       /* USB HUB reset line*/
-       MX51_PAD_GPIO1_7__GPIO1_7,
-
-       /* USB PHY reset line */
-       MX51_PAD_EIM_D21__GPIO2_5,
-
-       /* FEC */
-       MX51_PAD_EIM_EB2__FEC_MDIO,
-       MX51_PAD_EIM_EB3__FEC_RDATA1,
-       MX51_PAD_EIM_CS2__FEC_RDATA2,
-       MX51_PAD_EIM_CS3__FEC_RDATA3,
-       MX51_PAD_EIM_CS4__FEC_RX_ER,
-       MX51_PAD_EIM_CS5__FEC_CRS,
-       MX51_PAD_NANDF_RB2__FEC_COL,
-       MX51_PAD_NANDF_RB3__FEC_RX_CLK,
-       MX51_PAD_NANDF_D9__FEC_RDATA0,
-       MX51_PAD_NANDF_D8__FEC_TDATA0,
-       MX51_PAD_NANDF_CS2__FEC_TX_ER,
-       MX51_PAD_NANDF_CS3__FEC_MDC,
-       MX51_PAD_NANDF_CS4__FEC_TDATA1,
-       MX51_PAD_NANDF_CS5__FEC_TDATA2,
-       MX51_PAD_NANDF_CS6__FEC_TDATA3,
-       MX51_PAD_NANDF_CS7__FEC_TX_EN,
-       MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK,
-
-       /* FEC PHY reset line */
-       MX51_PAD_EIM_A20__GPIO2_14,
-
-       /* SD 1 */
-       MX51_PAD_SD1_CMD__SD1_CMD,
-       MX51_PAD_SD1_CLK__SD1_CLK,
-       MX51_PAD_SD1_DATA0__SD1_DATA0,
-       MX51_PAD_SD1_DATA1__SD1_DATA1,
-       MX51_PAD_SD1_DATA2__SD1_DATA2,
-       MX51_PAD_SD1_DATA3__SD1_DATA3,
-       /* CD/WP from controller */
-       MX51_PAD_GPIO1_0__SD1_CD,
-       MX51_PAD_GPIO1_1__SD1_WP,
-
-       /* SD 2 */
-       MX51_PAD_SD2_CMD__SD2_CMD,
-       MX51_PAD_SD2_CLK__SD2_CLK,
-       MX51_PAD_SD2_DATA0__SD2_DATA0,
-       MX51_PAD_SD2_DATA1__SD2_DATA1,
-       MX51_PAD_SD2_DATA2__SD2_DATA2,
-       MX51_PAD_SD2_DATA3__SD2_DATA3,
-       /* CD/WP gpio */
-       MX51_PAD_GPIO1_6__GPIO1_6,
-       MX51_PAD_GPIO1_5__GPIO1_5,
-
-       /* eCSPI1 */
-       MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
-       MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
-       MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK,
-       MX51_PAD_CSPI1_SS0__GPIO4_24,
-       MX51_PAD_CSPI1_SS1__GPIO4_25,
-
-       /* Audio */
-       MX51_PAD_AUD3_BB_TXD__AUD3_TXD,
-       MX51_PAD_AUD3_BB_RXD__AUD3_RXD,
-       MX51_PAD_AUD3_BB_CK__AUD3_TXC,
-       MX51_PAD_AUD3_BB_FS__AUD3_TXFS,
-};
-
-/* Serial ports */
-static const struct imxuart_platform_data uart_pdata __initconst = {
-       .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static const struct imxi2c_platform_data babbage_i2c_data __initconst = {
-       .bitrate = 100000,
-};
-
-static const struct imxi2c_platform_data babbage_hsi2c_data __initconst = {
-       .bitrate = 400000,
-};
-
-static struct gpio mx51_babbage_usbh1_gpios[] = {
-       { BABBAGE_USBH1_STP, GPIOF_OUT_INIT_LOW, "usbh1_stp" },
-       { BABBAGE_USB_PHY_RESET, GPIOF_OUT_INIT_LOW, "usbh1_phy_reset" },
-};
-
-static int gpio_usbh1_active(void)
-{
-       iomux_v3_cfg_t usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO1_27;
-       int ret;
-
-       /* Set USBH1_STP to GPIO and toggle it */
-       mxc_iomux_v3_setup_pad(usbh1stp_gpio);
-       ret = gpio_request_array(mx51_babbage_usbh1_gpios,
-                                       ARRAY_SIZE(mx51_babbage_usbh1_gpios));
-
-       if (ret) {
-               pr_debug("failed to get USBH1 pins: %d\n", ret);
-               return ret;
-       }
-
-       msleep(100);
-       gpio_set_value(BABBAGE_USBH1_STP, 1);
-       gpio_set_value(BABBAGE_USB_PHY_RESET, 1);
-       gpio_free_array(mx51_babbage_usbh1_gpios,
-                                       ARRAY_SIZE(mx51_babbage_usbh1_gpios));
-       return 0;
-}
-
-static inline void babbage_usbhub_reset(void)
-{
-       int ret;
-
-       /* Reset USB hub */
-       ret = gpio_request_one(BABBAGE_USB_HUB_RESET,
-                                       GPIOF_OUT_INIT_LOW, "GPIO1_7");
-       if (ret) {
-               printk(KERN_ERR"failed to get GPIO_USB_HUB_RESET: %d\n", ret);
-               return;
-       }
-
-       msleep(2);
-       /* Deassert reset */
-       gpio_set_value(BABBAGE_USB_HUB_RESET, 1);
-}
-
-static inline void babbage_fec_reset(void)
-{
-       int ret;
-
-       /* reset FEC PHY */
-       ret = gpio_request_one(BABBAGE_FEC_PHY_RESET,
-                                       GPIOF_OUT_INIT_LOW, "fec-phy-reset");
-       if (ret) {
-               printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret);
-               return;
-       }
-       msleep(1);
-       gpio_set_value(BABBAGE_FEC_PHY_RESET, 1);
-}
-
-/* This function is board specific as the bit mask for the plldiv will also
-be different for other Freescale SoCs, thus a common bitmask is not
-possible and cannot get place in /plat-mxc/ehci.c.*/
-static int initialize_otg_port(struct platform_device *pdev)
-{
-       u32 v;
-       void __iomem *usb_base;
-       void __iomem *usbother_base;
-
-       usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K);
-       if (!usb_base)
-               return -ENOMEM;
-       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
-       /* Set the PHY clock to 19.2MHz */
-       v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
-       v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
-       v |= MX51_USB_PLL_DIV_19_2_MHZ;
-       __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
-       iounmap(usb_base);
-
-       mdelay(10);
-
-       return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY);
-}
-
-static int initialize_usbh1_port(struct platform_device *pdev)
-{
-       u32 v;
-       void __iomem *usb_base;
-       void __iomem *usbother_base;
-
-       usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K);
-       if (!usb_base)
-               return -ENOMEM;
-       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
-       /* The clock for the USBH1 ULPI port will come externally from the PHY. */
-       v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
-       __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
-       iounmap(usb_base);
-
-       mdelay(10);
-
-       return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED |
-                       MXC_EHCI_ITC_NO_THRESHOLD);
-}
-
-static const struct mxc_usbh_platform_data dr_utmi_config __initconst = {
-       .init           = initialize_otg_port,
-       .portsc = MXC_EHCI_UTMI_16BIT,
-};
-
-static const struct fsl_usb2_platform_data usb_pdata __initconst = {
-       .operating_mode = FSL_USB2_DR_DEVICE,
-       .phy_mode       = FSL_USB2_PHY_UTMI_WIDE,
-};
-
-static const struct mxc_usbh_platform_data usbh1_config __initconst = {
-       .init           = initialize_usbh1_port,
-       .portsc = MXC_EHCI_MODE_ULPI,
-};
-
-static bool otg_mode_host __initdata;
-
-static int __init babbage_otg_mode(char *options)
-{
-       if (!strcmp(options, "host"))
-               otg_mode_host = true;
-       else if (!strcmp(options, "device"))
-               otg_mode_host = false;
-       else
-               pr_info("otg_mode neither \"host\" nor \"device\". "
-                       "Defaulting to device\n");
-       return 1;
-}
-__setup("otg_mode=", babbage_otg_mode);
-
-static struct spi_board_info mx51_babbage_spi_board_info[] __initdata = {
-       {
-               .modalias = "mtd_dataflash",
-               .max_speed_hz = 25000000,
-               .bus_num = 0,
-               .chip_select = 1,
-               .mode = SPI_MODE_0,
-               .platform_data = NULL,
-       },
-};
-
-static int mx51_babbage_spi_cs[] = {
-       BABBAGE_ECSPI1_CS0,
-       BABBAGE_ECSPI1_CS1,
-};
-
-static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = {
-       .chipselect     = mx51_babbage_spi_cs,
-       .num_chipselect = ARRAY_SIZE(mx51_babbage_spi_cs),
-};
-
-static const struct esdhc_platform_data mx51_babbage_sd1_data __initconst = {
-       .cd_type = ESDHC_CD_CONTROLLER,
-       .wp_type = ESDHC_WP_CONTROLLER,
-};
-
-static const struct esdhc_platform_data mx51_babbage_sd2_data __initconst = {
-       .cd_gpio = BABBAGE_SD2_CD,
-       .wp_gpio = BABBAGE_SD2_WP,
-       .cd_type = ESDHC_CD_GPIO,
-       .wp_type = ESDHC_WP_GPIO,
-};
-
-void __init imx51_babbage_common_init(void)
-{
-       mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads,
-                                        ARRAY_SIZE(mx51babbage_pads));
-}
-
-/*
- * Board specific initialization.
- */
-static void __init mx51_babbage_init(void)
-{
-       iomux_v3_cfg_t usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP;
-       iomux_v3_cfg_t power_key = NEW_PAD_CTRL(MX51_PAD_EIM_A27__GPIO2_21,
-               PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH);
-
-       imx51_soc_init();
-
-       imx51_babbage_common_init();
-
-       imx51_add_imx_uart(0, &uart_pdata);
-       imx51_add_imx_uart(1, NULL);
-       imx51_add_imx_uart(2, &uart_pdata);
-
-       babbage_fec_reset();
-       imx51_add_fec(NULL);
-
-       /* Set the PAD settings for the pwr key. */
-       mxc_iomux_v3_setup_pad(power_key);
-       imx_add_gpio_keys(&imx_button_data);
-
-       imx51_add_imx_i2c(0, &babbage_i2c_data);
-       imx51_add_imx_i2c(1, &babbage_i2c_data);
-       imx51_add_hsi2c(&babbage_hsi2c_data);
-
-       if (otg_mode_host)
-               imx51_add_mxc_ehci_otg(&dr_utmi_config);
-       else {
-               initialize_otg_port(NULL);
-               imx51_add_fsl_usb2_udc(&usb_pdata);
-       }
-
-       gpio_usbh1_active();
-       imx51_add_mxc_ehci_hs(1, &usbh1_config);
-       /* setback USBH1_STP to be function */
-       mxc_iomux_v3_setup_pad(usbh1stp);
-       babbage_usbhub_reset();
-
-       imx51_add_sdhci_esdhc_imx(0, &mx51_babbage_sd1_data);
-       imx51_add_sdhci_esdhc_imx(1, &mx51_babbage_sd2_data);
-
-       spi_register_board_info(mx51_babbage_spi_board_info,
-               ARRAY_SIZE(mx51_babbage_spi_board_info));
-       imx51_add_ecspi(0, &mx51_babbage_spi_pdata);
-       imx51_add_imx2_wdt(0);
-}
-
-static void __init mx51_babbage_timer_init(void)
-{
-       mx51_clocks_init(32768, 24000000, 22579200, 0);
-}
-
-MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
-       /* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */
-       .atag_offset = 0x100,
-       .map_io = mx51_map_io,
-       .init_early = imx51_init_early,
-       .init_irq = mx51_init_irq,
-       .handle_irq = imx51_handle_irq,
-       .init_time      = mx51_babbage_timer_init,
-       .init_machine = mx51_babbage_init,
-       .init_late      = imx51_init_late,
-       .restart        = mxc_restart,
-MACHINE_END
index 65222ea0df6d7176883a886ed6054eb080c19a0b..bed081e58262ed1f94190a44039b6251db5d9f5e 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/sched_clock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/mach/time.h>
 
@@ -328,3 +331,15 @@ void __init mxc_timer_init(void __iomem *base, int irq)
        /* Make irqs happen */
        setup_irq(irq, &mxc_timer_irq);
 }
+
+void __init mxc_timer_init_dt(struct device_node *np)
+{
+       void __iomem *base;
+       int irq;
+
+       base = of_iomap(np, 0);
+       WARN_ON(!base);
+       irq = irq_of_parse_and_map(np, 0);
+
+       mxc_timer_init(base, irq);
+}
index 2801da49e2a36bfea53cf1fd5a084c51dbac42a6..ff18ff20f71fe4b1f41e4fc032342f6be9c4a7f5 100644 (file)
@@ -195,7 +195,7 @@ static void __init kirkwood_dt_init(void)
 {
        kirkwood_disable_mbus_error_propagation();
 
-       BUG_ON(mvebu_mbus_dt_init());
+       BUG_ON(mvebu_mbus_dt_init(false));
 
 #ifdef CONFIG_CACHE_FEROCEON_L2
        feroceon_of_init();
index 2a97a2e4163cdf9593276159756ade03833ac028..2c47a8ad0e27fbffad7b1217ac1047e2125e8213 100644 (file)
@@ -7,6 +7,7 @@
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
+#include <asm/exception.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/irq.h>
@@ -30,11 +31,47 @@ static int __initdata gpio1_irqs[4] = {
        0,
 };
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+/*
+ * Compiling with both non-DT and DT support enabled, will
+ * break asm irq handler used by non-DT boards. Therefore,
+ * we provide a C-style irq handler even for non-DT boards,
+ * if MULTI_IRQ_HANDLER is set.
+ */
+
+static void __iomem *kirkwood_irq_base = IRQ_VIRT_BASE;
+
+asmlinkage void
+__exception_irq_entry kirkwood_legacy_handle_irq(struct pt_regs *regs)
+{
+       u32 stat;
+
+       stat = readl_relaxed(kirkwood_irq_base + IRQ_CAUSE_LOW_OFF);
+       stat &= readl_relaxed(kirkwood_irq_base + IRQ_MASK_LOW_OFF);
+       if (stat) {
+               unsigned int hwirq = __fls(stat);
+               handle_IRQ(hwirq, regs);
+               return;
+       }
+       stat = readl_relaxed(kirkwood_irq_base + IRQ_CAUSE_HIGH_OFF);
+       stat &= readl_relaxed(kirkwood_irq_base + IRQ_MASK_HIGH_OFF);
+       if (stat) {
+               unsigned int hwirq = 32 + __fls(stat);
+               handle_IRQ(hwirq, regs);
+               return;
+       }
+}
+#endif
+
 void __init kirkwood_init_irq(void)
 {
        orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF);
        orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF);
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       set_handle_irq(kirkwood_legacy_handle_irq);
+#endif
+
        /*
         * Initialize gpiolib for GPIOs 0-49.
         */
index 3f73eecbcfb033d3370ad41642f7fe95b9d948b9..199187e474ce524600922a4d46fd5c41a537711d 100644 (file)
@@ -3,15 +3,14 @@ config ARCH_MVEBU
        select ARCH_SUPPORTS_BIG_ENDIAN
        select CLKSRC_MMIO
        select GENERIC_IRQ_CHIP
-       select IRQ_DOMAIN
        select PINCTRL
        select PLAT_ORION
+       select SOC_BUS
        select MVEBU_MBUS
        select ZONE_DMA if ARM_LPAE
        select ARCH_REQUIRE_GPIOLIB
        select MIGHT_HAVE_PCI
        select PCI_QUIRKS if PCI
-       select OF_ADDRESS_PCI
 
 if ARCH_MVEBU
 
@@ -38,7 +37,9 @@ config MACH_ARMADA_375
        select ARM_ERRATA_753970
        select ARM_GIC
        select ARMADA_375_CLK
-       select CPU_V7
+       select HAVE_ARM_SCU
+       select HAVE_ARM_TWD if SMP
+       select HAVE_SMP
        select MACH_MVEBU_V7
        select PINCTRL_ARMADA_375
        help
@@ -51,7 +52,9 @@ config MACH_ARMADA_38X
        select ARM_ERRATA_753970
        select ARM_GIC
        select ARMADA_38X_CLK
-       select CPU_V7
+       select HAVE_ARM_SCU
+       select HAVE_ARM_TWD if SMP
+       select HAVE_SMP
        select MACH_MVEBU_V7
        select PINCTRL_ARMADA_38X
        help
@@ -86,24 +89,15 @@ config MACH_KIRKWOOD
        select ARCH_REQUIRE_GPIOLIB
        select CPU_FEROCEON
        select KIRKWOOD_CLK
-       select OF_IRQ
        select ORION_IRQCHIP
        select ORION_TIMER
        select PCI
        select PCI_QUIRKS
        select PINCTRL_KIRKWOOD
-       select USE_OF
        help
          Say 'Y' here if you want your kernel to support boards based
          on the Marvell Kirkwood device tree.
 
-config MACH_T5325
-       bool "HP T5325 thin client"
-       depends on MACH_KIRKWOOD
-       help
-         Say 'Y' here if you want your kernel to support the
-         HP T5325 Thin client
-
 endmenu
 
 endif
index a63e43b6b451e24c1aba904006f9d5a3c636a47d..854b72af9faaf5c2476e68df3a41c3dd535c5c01 100644 (file)
@@ -4,10 +4,12 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 AFLAGS_coherency_ll.o          := -Wa,-march=armv7-a
 
 obj-y                           += system-controller.o mvebu-soc-id.o
-obj-$(CONFIG_MACH_MVEBU_V7)      += board-v7.o
+
+ifeq ($(CONFIG_MACH_MVEBU_V7),y)
+obj-y                           += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o
+obj-$(CONFIG_SMP)               += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
+obj-$(CONFIG_HOTPLUG_CPU)       += hotplug.o
+endif
+
 obj-$(CONFIG_MACH_DOVE)                 += dove.o
-obj-$(CONFIG_ARCH_MVEBU)        += coherency.o coherency_ll.o pmsu.o
-obj-$(CONFIG_SMP)                += platsmp.o headsmp.o
-obj-$(CONFIG_HOTPLUG_CPU)        += hotplug.o
 obj-$(CONFIG_MACH_KIRKWOOD)     += kirkwood.o kirkwood-pm.o
-obj-$(CONFIG_MACH_T5325)        += board-t5325.o
index 237c86b83390178a069f22971c960766bdaa22f2..c3465f5b12500fb74e6975ce46c9a8a34c1871f3 100644 (file)
@@ -20,8 +20,6 @@
 
 #define ARMADA_XP_MAX_CPUS 4
 
-void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
-void armada_xp_mpic_smp_cpu_init(void);
 void armada_xp_secondary_startup(void);
 extern struct smp_operations armada_xp_smp_ops;
 #endif
diff --git a/arch/arm/mach-mvebu/board-t5325.c b/arch/arm/mach-mvebu/board-t5325.c
deleted file mode 100644 (file)
index 65ace6d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * HP T5325 Board Setup
- *
- * Copyright (C) 2014
- *
- * Andrew Lunn <andrew@lunn.ch>
- *
- * 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/kernel.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <sound/alc5623.h>
-#include "board.h"
-
-static struct platform_device hp_t5325_audio_device = {
-       .name           = "t5325-audio",
-       .id             = -1,
-};
-
-static struct alc5623_platform_data alc5621_data = {
-       .add_ctrl = 0x3700,
-       .jack_det_ctrl = 0x4810,
-};
-
-static struct i2c_board_info i2c_board_info[] __initdata = {
-       {
-               I2C_BOARD_INFO("alc5621", 0x1a),
-               .platform_data = &alc5621_data,
-       },
-};
-
-void __init t5325_init(void)
-{
-       i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info));
-       platform_device_register(&hp_t5325_audio_device);
-}
index 333fca8fdc41c2cf667a849b7461bd8fb2c9baac..bc0283f0dd88dca7e24320a1d2dfda165099335a 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
+#include <asm/smp_scu.h>
 #include "armada-370-xp.h"
 #include "common.h"
 #include "coherency.h"
 #include "mvebu-soc-id.h"
 
+/*
+ * Enables the SCU when available. Obviously, this is only useful on
+ * Cortex-A based SOCs, not on PJ4B based ones.
+ */
+static void __init mvebu_scu_enable(void)
+{
+       void __iomem *scu_base;
+
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+       if (np) {
+               scu_base = of_iomap(np, 0);
+               scu_enable(scu_base);
+               of_node_put(np);
+       }
+}
+
 /*
  * Early versions of Armada 375 SoC have a bug where the BootROM
  * leaves an external data abort pending. The kernel is hit by this
@@ -57,11 +75,10 @@ static void __init mvebu_timer_and_clk_init(void)
 {
        of_clk_init(NULL);
        clocksource_of_init();
+       mvebu_scu_enable();
        coherency_init();
-       BUG_ON(mvebu_mbus_dt_init());
-#ifdef CONFIG_CACHE_L2X0
+       BUG_ON(mvebu_mbus_dt_init(coherency_available()));
        l2x0_of_init(0, ~0UL);
-#endif
 
        if (of_machine_is_compatible("marvell,armada375"))
                hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0,
@@ -78,7 +95,7 @@ static void __init i2c_quirk(void)
         * mechanism. We can exit only if we are sure that we can
         * get the SoC revision and it is more recent than A0.
         */
-       if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV)
+       if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV)
                return;
 
        for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
@@ -96,10 +113,66 @@ static void __init i2c_quirk(void)
        return;
 }
 
+#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc
+
+static void __init thermal_quirk(void)
+{
+       struct device_node *np;
+       u32 dev, rev;
+
+       if (mvebu_get_soc_id(&dev, &rev) && rev > ARMADA_375_Z1_REV)
+               return;
+
+       for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
+               struct property *prop;
+               __be32 newval, *newprop, *oldprop;
+               int len;
+
+               /*
+                * The register offset is at a wrong location. This quirk
+                * creates a new reg property as a clone of the previous
+                * one and corrects the offset.
+                */
+               oldprop = (__be32 *)of_get_property(np, "reg", &len);
+               if (!oldprop)
+                       continue;
+
+               /* Create a duplicate of the 'reg' property */
+               prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+               prop->length = len;
+               prop->name = kstrdup("reg", GFP_KERNEL);
+               prop->value = kzalloc(len, GFP_KERNEL);
+               memcpy(prop->value, oldprop, len);
+
+               /* Fixup the register offset of the second entry */
+               oldprop += 2;
+               newprop = (__be32 *)prop->value + 2;
+               newval = cpu_to_be32(be32_to_cpu(*oldprop) -
+                                    A375_Z1_THERMAL_FIXUP_OFFSET);
+               *newprop = newval;
+               of_update_property(np, prop);
+
+               /*
+                * The thermal controller needs some quirk too, so let's change
+                * the compatible string to reflect this.
+                */
+               prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+               prop->name = kstrdup("compatible", GFP_KERNEL);
+               prop->length = sizeof("marvell,armada375-z1-thermal");
+               prop->value = kstrdup("marvell,armada375-z1-thermal",
+                                               GFP_KERNEL);
+               of_update_property(np, prop);
+       }
+       return;
+}
+
 static void __init mvebu_dt_init(void)
 {
        if (of_machine_is_compatible("plathome,openblocks-ax3-4"))
                i2c_quirk();
+       if (of_machine_is_compatible("marvell,a375-db"))
+               thermal_quirk();
+
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
@@ -123,6 +196,7 @@ static const char * const armada_375_dt_compat[] = {
 
 DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)")
        .init_time      = mvebu_timer_and_clk_init,
+       .init_machine   = mvebu_dt_init,
        .restart        = mvebu_restart,
        .dt_compat      = armada_375_dt_compat,
 MACHINE_END
index de7f0a191394d744e8801632ee057cd754880155..9c7bb4386f8bc92574a0723ebd7ea303e9028201 100644 (file)
 #ifndef __ARCH_MVEBU_BOARD_H
 #define __ARCH_MVEBU_BOARD_H
 
-#ifdef CONFIG_MACH_T5325
-void t5325_init(void);
-#else
-static inline void t5325_init(void) {};
-#endif
-
 #endif
index 4e9d58148ca7e3031cbbdaa5dba2bb5aa0607619..ff8d5ef7da6a34a8dbd38f3ff8ad67350b81994c 100644 (file)
@@ -17,6 +17,8 @@
  * supplies basic routines for configuring and controlling hardware coherency
  */
 
+#define pr_fmt(fmt) "mvebu-coherency: " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/smp.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <linux/clk.h>
 #include <asm/smp_plat.h>
 #include <asm/cacheflush.h>
 #include "armada-370-xp.h"
 #include "coherency.h"
 
 unsigned long coherency_phys_base;
-static void __iomem *coherency_base;
+void __iomem *coherency_base;
 static void __iomem *coherency_cpu_base;
 
 /* Coherency fabric registers */
@@ -38,27 +43,190 @@ static void __iomem *coherency_cpu_base;
 
 #define IO_SYNC_BARRIER_CTL_OFFSET                0x0
 
+enum {
+       COHERENCY_FABRIC_TYPE_NONE,
+       COHERENCY_FABRIC_TYPE_ARMADA_370_XP,
+       COHERENCY_FABRIC_TYPE_ARMADA_375,
+       COHERENCY_FABRIC_TYPE_ARMADA_380,
+};
+
 static struct of_device_id of_coherency_table[] = {
-       {.compatible = "marvell,coherency-fabric"},
+       {.compatible = "marvell,coherency-fabric",
+        .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_370_XP },
+       {.compatible = "marvell,armada-375-coherency-fabric",
+        .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_375 },
+       {.compatible = "marvell,armada-380-coherency-fabric",
+        .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_380 },
        { /* end of list */ },
 };
 
-/* Function defined in coherency_ll.S */
-int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id);
+/* Functions defined in coherency_ll.S */
+int ll_enable_coherency(void);
+void ll_add_cpu_to_smp_group(void);
 
-int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
+int set_cpu_coherent(void)
 {
        if (!coherency_base) {
-               pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id);
+               pr_warn("Can't make current CPU cache coherent.\n");
                pr_warn("Coherency fabric is not initialized\n");
                return 1;
        }
 
-       return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
+       ll_add_cpu_to_smp_group();
+       return ll_enable_coherency();
+}
+
+/*
+ * The below code implements the I/O coherency workaround on Armada
+ * 375. This workaround consists in using the two channels of the
+ * first XOR engine to trigger a XOR transaction that serves as the
+ * I/O coherency barrier.
+ */
+
+static void __iomem *xor_base, *xor_high_base;
+static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
+static void *coherency_wa_buf[CONFIG_NR_CPUS];
+static bool coherency_wa_enabled;
+
+#define XOR_CONFIG(chan)            (0x10 + (chan * 4))
+#define XOR_ACTIVATION(chan)        (0x20 + (chan * 4))
+#define WINDOW_BAR_ENABLE(chan)     (0x240 + ((chan) << 2))
+#define WINDOW_BASE(w)              (0x250 + ((w) << 2))
+#define WINDOW_SIZE(w)              (0x270 + ((w) << 2))
+#define WINDOW_REMAP_HIGH(w)        (0x290 + ((w) << 2))
+#define WINDOW_OVERRIDE_CTRL(chan)  (0x2A0 + ((chan) << 2))
+#define XOR_DEST_POINTER(chan)      (0x2B0 + (chan * 4))
+#define XOR_BLOCK_SIZE(chan)        (0x2C0 + (chan * 4))
+#define XOR_INIT_VALUE_LOW           0x2E0
+#define XOR_INIT_VALUE_HIGH          0x2E4
+
+static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void)
+{
+       int idx = smp_processor_id();
+
+       /* Write '1' to the first word of the buffer */
+       writel(0x1, coherency_wa_buf[idx]);
+
+       /* Wait until the engine is idle */
+       while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3)
+               ;
+
+       dmb();
+
+       /* Trigger channel */
+       writel(0x1, xor_base + XOR_ACTIVATION(idx));
+
+       /* Poll the data until it is cleared by the XOR transaction */
+       while (readl(coherency_wa_buf[idx]))
+               ;
+}
+
+static void __init armada_375_coherency_init_wa(void)
+{
+       const struct mbus_dram_target_info *dram;
+       struct device_node *xor_node;
+       struct property *xor_status;
+       struct clk *xor_clk;
+       u32 win_enable = 0;
+       int i;
+
+       pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n");
+
+       /*
+        * Since the workaround uses one XOR engine, we grab a
+        * reference to its Device Tree node first.
+        */
+       xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor");
+       BUG_ON(!xor_node);
+
+       /*
+        * Then we mark it as disabled so that the real XOR driver
+        * will not use it.
+        */
+       xor_status = kzalloc(sizeof(struct property), GFP_KERNEL);
+       BUG_ON(!xor_status);
+
+       xor_status->value = kstrdup("disabled", GFP_KERNEL);
+       BUG_ON(!xor_status->value);
+
+       xor_status->length = 8;
+       xor_status->name = kstrdup("status", GFP_KERNEL);
+       BUG_ON(!xor_status->name);
+
+       of_update_property(xor_node, xor_status);
+
+       /*
+        * And we remap the registers, get the clock, and do the
+        * initial configuration of the XOR engine.
+        */
+       xor_base = of_iomap(xor_node, 0);
+       xor_high_base = of_iomap(xor_node, 1);
+
+       xor_clk = of_clk_get_by_name(xor_node, NULL);
+       BUG_ON(!xor_clk);
+
+       clk_prepare_enable(xor_clk);
+
+       dram = mv_mbus_dram_info();
+
+       for (i = 0; i < 8; i++) {
+               writel(0, xor_base + WINDOW_BASE(i));
+               writel(0, xor_base + WINDOW_SIZE(i));
+               if (i < 4)
+                       writel(0, xor_base + WINDOW_REMAP_HIGH(i));
+       }
+
+       for (i = 0; i < dram->num_cs; i++) {
+               const struct mbus_dram_window *cs = dram->cs + i;
+               writel((cs->base & 0xffff0000) |
+                      (cs->mbus_attr << 8) |
+                      dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i));
+               writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i));
+
+               win_enable |= (1 << i);
+               win_enable |= 3 << (16 + (2 * i));
+       }
+
+       writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0));
+       writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1));
+       writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0));
+       writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1));
+
+       for (i = 0; i < CONFIG_NR_CPUS; i++) {
+               coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               BUG_ON(!coherency_wa_buf[i]);
+
+               /*
+                * We can't use the DMA mapping API, since we don't
+                * have a valid 'struct device' pointer
+                */
+               coherency_wa_buf_phys[i] =
+                       virt_to_phys(coherency_wa_buf[i]);
+               BUG_ON(!coherency_wa_buf_phys[i]);
+
+               /*
+                * Configure the XOR engine for memset operation, with
+                * a 128 bytes block size
+                */
+               writel(0x444, xor_base + XOR_CONFIG(i));
+               writel(128, xor_base + XOR_BLOCK_SIZE(i));
+               writel(coherency_wa_buf_phys[i],
+                      xor_base + XOR_DEST_POINTER(i));
+       }
+
+       writel(0x0, xor_base + XOR_INIT_VALUE_LOW);
+       writel(0x0, xor_base + XOR_INIT_VALUE_HIGH);
+
+       coherency_wa_enabled = true;
 }
 
 static inline void mvebu_hwcc_sync_io_barrier(void)
 {
+       if (coherency_wa_enabled) {
+               mvebu_hwcc_armada375_sync_io_barrier_wa();
+               return;
+       }
+
        writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
        while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
 }
@@ -121,11 +289,35 @@ static struct notifier_block mvebu_hwcc_platform_nb = {
        .notifier_call = mvebu_hwcc_platform_notifier,
 };
 
-int __init coherency_init(void)
+static void __init armada_370_coherency_init(struct device_node *np)
+{
+       struct resource res;
+
+       of_address_to_resource(np, 0, &res);
+       coherency_phys_base = res.start;
+       /*
+        * Ensure secondary CPUs will see the updated value,
+        * which they read before they join the coherency
+        * fabric, and therefore before they are coherent with
+        * the boot CPU cache.
+        */
+       sync_cache_w(&coherency_phys_base);
+       coherency_base = of_iomap(np, 0);
+       coherency_cpu_base = of_iomap(np, 1);
+       set_cpu_coherent();
+}
+
+static void __init armada_375_380_coherency_init(struct device_node *np)
+{
+       coherency_cpu_base = of_iomap(np, 0);
+}
+
+static int coherency_type(void)
 {
        struct device_node *np;
+       const struct of_device_id *match;
 
-       np = of_find_matching_node(NULL, of_coherency_table);
+       np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
        if (np) {
                struct resource res;
                pr_info("Initializing Coherency fabric\n");
@@ -140,23 +332,47 @@ int __init coherency_init(void)
                sync_cache_w(&coherency_phys_base);
                coherency_base = of_iomap(np, 0);
                coherency_cpu_base = of_iomap(np, 1);
-               set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
+               set_cpu_coherent();
                of_node_put(np);
        }
 
-       return 0;
+       return COHERENCY_FABRIC_TYPE_NONE;
 }
 
-static int __init coherency_late_init(void)
+int coherency_available(void)
+{
+       return coherency_type() != COHERENCY_FABRIC_TYPE_NONE;
+}
+
+int __init coherency_init(void)
 {
+       int type = coherency_type();
        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);
-       }
+
+       if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
+               armada_370_coherency_init(np);
+       else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 ||
+                type == COHERENCY_FABRIC_TYPE_ARMADA_380)
+               armada_375_380_coherency_init(np);
+
+       return 0;
+}
+
+static int __init coherency_late_init(void)
+{
+       int type = coherency_type();
+
+       if (type == COHERENCY_FABRIC_TYPE_NONE)
+               return 0;
+
+       if (type == COHERENCY_FABRIC_TYPE_ARMADA_375)
+               armada_375_coherency_init_wa();
+
+       bus_register_notifier(&platform_bus_type,
+                             &mvebu_hwcc_platform_nb);
+
        return 0;
 }
 
index 760226c4135309b4ec79ddda47ba9fb18c31a3f4..54cb7607b52669ec7d31aad95e44ffd04471a4fb 100644 (file)
@@ -15,8 +15,9 @@
 #define __MACH_370_XP_COHERENCY_H
 
 extern unsigned long coherency_phys_base;
+int set_cpu_coherent(void);
 
-int set_cpu_coherent(unsigned int cpu_id, int smp_group_id);
 int coherency_init(void);
+int coherency_available(void);
 
 #endif /* __MACH_370_XP_COHERENCY_H */
index ee7598fe75db873dc81843610939d189969833a3..6828f9f157b0b36d02abb6daab4843c143d2bf4d 100644 (file)
 #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
 
 #include <asm/assembler.h>
+#include <asm/cp15.h>
 
        .text
-/*
- * r0: Coherency fabric base register address
- * r1: HW CPU id
- */
-ENTRY(ll_set_cpu_coherent)
-       /* Create bit by cpu index */
-       mov     r3, #(1 << 24)
-       lsl     r1, r3, r1
-ARM_BE8(rev    r1, r1)
+/* Returns with the coherency address in r1 (r0 is untouched)*/
+ENTRY(ll_get_coherency_base)
+       mrc     p15, 0, r1, c1, c0, 0
+       tst     r1, #CR_M @ Check MMU bit enabled
+       bne     1f
 
-       /* Add CPU to SMP group - Atomic */
-       add     r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET
+       /* use physical address of the coherency register */
+       adr     r1, 3f
+       ldr     r3, [r1]
+       ldr     r1, [r1, r3]
+       b       2f
 1:
-       ldrex   r2, [r3]
-       orr     r2, r2, r1
-       strex   r0, r2, [r3]
-       cmp     r0, #0
-       bne 1b
-
-       /* Enable coherency on CPU - Atomic */
-       add     r3, r3, #ARMADA_XP_CFB_CFG_REG_OFFSET
+       /* use virtual address of the coherency register */
+       ldr     r1, =coherency_base
+       ldr     r1, [r1]
+2:
+       mov     pc, lr
+ENDPROC(ll_get_coherency_base)
+
+/* Returns with the CPU ID in r3 (r0 is untouched)*/
+ENTRY(ll_get_cpuid)
+       mrc     15, 0, r3, cr0, cr0, 5
+       and     r3, r3, #15
+       mov     r2, #(1 << 24)
+       lsl     r3, r2, r3
+ARM_BE8(rev    r1, r1)
+       mov     pc, lr
+ENDPROC(ll_get_cpuid)
+
+/* ll_add_cpu_to_smp_group, ll_enable_coherency and
+ * ll_disable_coherency use strex/ldrex whereas MMU can be off. The
+ * Armada XP SoC has an exclusive monitor that can track transactions
+ * to Device and/or SO and as such also when MMU is disabled the
+ * exclusive transactions will be functional
+ */
+
+ENTRY(ll_add_cpu_to_smp_group)
+       /*
+        * r0 being untouched in ll_get_coherency_base and
+        * ll_get_cpuid, we can use it to save lr modifing it with the
+        * following bl
+        */
+       mov r0, lr
+       bl      ll_get_coherency_base
+       bl      ll_get_cpuid
+       mov lr, r0
+       add     r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
 1:
-       ldrex   r2, [r3]
-       orr     r2, r2, r1
-       strex   r0, r2, [r3]
-       cmp     r0, #0
-       bne 1b
+       ldrex   r2, [r0]
+       orr     r2, r2, r3
+       strex   r1, r2, [r0]
+       cmp     r1, #0
+       bne     1b
+       mov     pc, lr
+ENDPROC(ll_add_cpu_to_smp_group)
 
+ENTRY(ll_enable_coherency)
+       /*
+        * r0 being untouched in ll_get_coherency_base and
+        * ll_get_cpuid, we can use it to save lr modifing it with the
+        * following bl
+        */
+       mov r0, lr
+       bl      ll_get_coherency_base
+       bl      ll_get_cpuid
+       mov lr, r0
+       add     r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
+1:
+       ldrex   r2, [r0]
+       orr     r2, r2, r3
+       strex   r1, r2, [r0]
+       cmp     r1, #0
+       bne     1b
        dsb
-
        mov     r0, #0
        mov     pc, lr
-ENDPROC(ll_set_cpu_coherent)
+ENDPROC(ll_enable_coherency)
+
+ENTRY(ll_disable_coherency)
+       /*
+        * r0 being untouched in ll_get_coherency_base and
+        * ll_get_cpuid, we can use it to save lr modifing it with the
+        * following bl
+        */
+       mov r0, lr
+       bl      ll_get_coherency_base
+       bl      ll_get_cpuid
+       mov lr, r0
+       add     r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
+1:
+       ldrex   r2, [r0]
+       bic     r2, r2, r3
+       strex   r1, r2, [r0]
+       cmp     r1, #0
+       bne     1b
+       dsb
+       mov     pc, lr
+ENDPROC(ll_disable_coherency)
+
+       .align 2
+3:
+       .long   coherency_phys_base - .
index 55449c487c9e9dff0a8e084b75a269d650cb5a93..b67fb7a10d8b466086672170c5615de4583f009f 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/reboot.h>
 
 void mvebu_restart(enum reboot_mode mode, const char *cmd);
+int mvebu_cpu_reset_deassert(int cpu);
+void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
+void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
 
 void armada_xp_cpu_die(unsigned int cpu);
 
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c
new file mode 100644 (file)
index 0000000..4a8f9ee
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ */
+
+#define pr_fmt(fmt) "mvebu-cpureset: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/resource.h>
+#include "armada-370-xp.h"
+
+static void __iomem *cpu_reset_base;
+static size_t cpu_reset_size;
+
+#define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
+#define CPU_RESET_ASSERT      BIT(0)
+
+int mvebu_cpu_reset_deassert(int cpu)
+{
+       u32 reg;
+
+       if (!cpu_reset_base)
+               return -ENODEV;
+
+       if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
+               return -EINVAL;
+
+       reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
+       reg &= ~CPU_RESET_ASSERT;
+       writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
+
+       return 0;
+}
+
+static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
+{
+       struct resource res;
+
+       if (of_address_to_resource(np, res_idx, &res)) {
+               pr_err("unable to get resource\n");
+               return -ENOENT;
+       }
+
+       if (!request_mem_region(res.start, resource_size(&res),
+                               np->full_name)) {
+               pr_err("unable to request region\n");
+               return -EBUSY;
+       }
+
+       cpu_reset_base = ioremap(res.start, resource_size(&res));
+       if (!cpu_reset_base) {
+               pr_err("unable to map registers\n");
+               release_mem_region(res.start, resource_size(&res));
+               return -ENOMEM;
+       }
+
+       cpu_reset_size = resource_size(&res);
+
+       return 0;
+}
+
+int __init mvebu_cpu_reset_init(void)
+{
+       struct device_node *np;
+       int res_idx;
+       int ret;
+
+       np = of_find_compatible_node(NULL, NULL,
+                                    "marvell,armada-370-cpu-reset");
+       if (np) {
+               res_idx = 0;
+       } else {
+               /*
+                * This code is kept for backward compatibility with
+                * old Device Trees.
+                */
+               np = of_find_compatible_node(NULL, NULL,
+                                            "marvell,armada-370-xp-pmsu");
+               if (np) {
+                       pr_warn(FW_WARN "deprecated pmsu binding\n");
+                       res_idx = 1;
+               }
+       }
+
+       /* No reset node found */
+       if (!np)
+               return -ENODEV;
+
+       ret = mvebu_cpu_reset_map(np, res_idx);
+       of_node_put(np);
+
+       return ret;
+}
+
+early_initcall(mvebu_cpu_reset_init);
index 5e5a43624237681f6f85b288147880babc66fef6..b50464ec1130ff0b5961990d2684953c582d44cc 100644 (file)
@@ -23,7 +23,7 @@ static void __init dove_init(void)
 #ifdef CONFIG_CACHE_TAUROS2
        tauros2_init(0);
 #endif
-       BUG_ON(mvebu_mbus_dt_init());
+       BUG_ON(mvebu_mbus_dt_init(false));
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S
new file mode 100644 (file)
index 0000000..5925366
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SMP support: Entry point for secondary CPUs of Marvell EBU
+ * Cortex-A9 based SOCs (Armada 375 and Armada 38x).
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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/linkage.h>
+#include <linux/init.h>
+
+       __CPUINIT
+#define CPU_RESUME_ADDR_REG 0xf10182d4
+
+.global armada_375_smp_cpu1_enable_code_start
+.global armada_375_smp_cpu1_enable_code_end
+
+armada_375_smp_cpu1_enable_code_start:
+       ldr     r0, [pc, #4]
+       ldr     r1, [r0]
+       mov     pc, r1
+       .word   CPU_RESUME_ADDR_REG
+armada_375_smp_cpu1_enable_code_end:
+
+ENTRY(mvebu_cortex_a9_secondary_startup)
+       bl      v7_invalidate_l1
+       b       secondary_startup
+ENDPROC(mvebu_cortex_a9_secondary_startup)
index 3dd80df428f7edbf92885011a64141bf472add8c..2c4032e368badaa94d5ff60b7a6361b42d7f04dd 100644 (file)
 ENTRY(armada_xp_secondary_startup)
  ARM_BE8(setend        be )                    @ go BE8 if entered LE
 
-       /* Get coherency fabric base physical address */
-       adr     r0, 1f
-       ldr     r1, [r0]
-       ldr     r0, [r0, r1]
+       bl      ll_add_cpu_to_smp_group
 
-       /* Read CPU id */
-       mrc     p15, 0, r1, c0, c0, 5
-       and     r1, r1, #0xF
+       bl      ll_enable_coherency
 
-       /* Add CPU to coherency fabric */
-       bl      ll_set_cpu_coherent
        b       secondary_startup
 
 ENDPROC(armada_xp_secondary_startup)
-
-       .align 2
-1:
-       .long   coherency_phys_base - .
index 120207fc36f1f87d210c98d747bb28ee914015a0..46f105913c84b75e6b6c7b1095cdf485f015af5d 100644 (file)
@@ -169,7 +169,7 @@ static void __init kirkwood_dt_init(void)
 {
        kirkwood_disable_mbus_error_propagation();
 
-       BUG_ON(mvebu_mbus_dt_init());
+       BUG_ON(mvebu_mbus_dt_init(false));
 
 #ifdef CONFIG_CACHE_FEROCEON_L2
        feroceon_of_init();
@@ -180,9 +180,6 @@ static void __init kirkwood_dt_init(void)
        kirkwood_pm_init();
        kirkwood_dt_eth_fixup();
 
-       if (of_machine_is_compatible("hp,t5325"))
-               t5325_init();
-
        of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL);
 }
 
index f3d4cf53f7466ba6c44f5ef1d91484e3ce8f62e6..874a7504818e89c53680a2a21ed9b386fbc1fa52 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
 #include "mvebu-soc-id.h"
 
 #define PCIE_DEV_ID_OFF                0x0
@@ -118,3 +120,31 @@ clk_err:
 }
 core_initcall(mvebu_soc_id_init);
 
+static int __init mvebu_soc_device(void)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+
+       /* Also protects against running on non-mvebu systems */
+       if (!is_id_valid)
+               return 0;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+
+       soc_dev_attr->family = kasprintf(GFP_KERNEL, "Marvell");
+       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", soc_rev);
+       soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%X", soc_dev_id);
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               kfree(soc_dev_attr->family);
+               kfree(soc_dev_attr->revision);
+               kfree(soc_dev_attr->soc_id);
+               kfree(soc_dev_attr);
+       }
+
+       return 0;
+}
+postcore_initcall(mvebu_soc_device);
index 31654252fe35ca63e41706572ddc88e3bb9455f3..294a443f56fcb6f57a85b0f0e947cf0600a6861b 100644 (file)
@@ -20,6 +20,9 @@
 #define MV78XX0_A0_REV     0x1
 #define MV78XX0_B0_REV     0x2
 
+/* Armada 375 */
+#define ARMADA_375_Z1_REV   0x0
+
 #ifdef CONFIG_ARCH_MVEBU
 int mvebu_get_soc_id(u32 *dev, u32 *rev);
 #else
diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c
new file mode 100644 (file)
index 0000000..04d0b18
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
+ * based SOCs (Armada 375/38x).
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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/io.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+#include <linux/mbus.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
+#include "common.h"
+#include "pmsu.h"
+
+#define CRYPT0_ENG_ID   41
+#define CRYPT0_ENG_ATTR 0x1
+#define SRAM_PHYS_BASE  0xFFFF0000
+
+#define BOOTROM_BASE    0xFFF00000
+#define BOOTROM_SIZE    0x100000
+
+extern unsigned char armada_375_smp_cpu1_enable_code_end;
+extern unsigned char armada_375_smp_cpu1_enable_code_start;
+
+void armada_375_smp_cpu1_enable_wa(void)
+{
+       void __iomem *sram_virt_base;
+
+       mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
+       mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR,
+                               SRAM_PHYS_BASE, SZ_64K);
+       sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
+
+       memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start,
+              &armada_375_smp_cpu1_enable_code_end
+              - &armada_375_smp_cpu1_enable_code_start);
+}
+
+extern void mvebu_cortex_a9_secondary_startup(void);
+
+static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
+                                                   struct task_struct *idle)
+{
+       int ret, hw_cpu;
+
+       pr_info("Booting CPU %d\n", cpu);
+
+       /*
+        * Write the address of secondary startup into the system-wide
+        * flags register. The boot monitor waits until it receives a
+        * soft interrupt, and then the secondary CPU branches to this
+        * address.
+        */
+       hw_cpu = cpu_logical_map(cpu);
+
+       if (of_machine_is_compatible("marvell,armada375"))
+               mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
+       else
+               mvebu_pmsu_set_cpu_boot_addr(hw_cpu,
+                                            mvebu_cortex_a9_secondary_startup);
+
+       smp_wmb();
+       ret = mvebu_cpu_reset_deassert(hw_cpu);
+       if (ret) {
+               pr_err("Could not start the secondary CPU: %d\n", ret);
+               return ret;
+       }
+       arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+       return 0;
+}
+
+static void __init mvebu_cortex_a9_smp_prepare_cpus(unsigned int max_cpus)
+{
+       if (of_machine_is_compatible("marvell,armada375"))
+               armada_375_smp_cpu1_enable_wa();
+}
+
+static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
+       .smp_prepare_cpus       = mvebu_cortex_a9_smp_prepare_cpus,
+       .smp_boot_secondary     = mvebu_cortex_a9_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_die                = armada_xp_cpu_die,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
+                     &mvebu_cortex_a9_smp_ops);
+CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
+                     &mvebu_cortex_a9_smp_ops);
index a6da03f5b24ec921090af5508a2b6d87a66c7197..88b976b317198f7733b4945eaad440c195175aaa 100644 (file)
@@ -70,16 +70,19 @@ static void __init set_secondary_cpus_clock(void)
        }
 }
 
-static void armada_xp_secondary_init(unsigned int cpu)
-{
-       armada_xp_mpic_smp_cpu_init();
-}
-
 static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
+       int ret, hw_cpu;
+
        pr_info("Booting CPU %d\n", cpu);
 
-       armada_xp_boot_cpu(cpu, armada_xp_secondary_startup);
+       hw_cpu = cpu_logical_map(cpu);
+       mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
+       ret = mvebu_cpu_reset_deassert(hw_cpu);
+       if (ret) {
+               pr_warn("unable to boot CPU: %d\n", ret);
+               return ret;
+       }
 
        return 0;
 }
@@ -90,8 +93,6 @@ static void __init armada_xp_smp_init_cpus(void)
 
        if (ncores == 0 || ncores > ARMADA_XP_MAX_CPUS)
                panic("Invalid number of CPUs in DT\n");
-
-       set_smp_cross_call(armada_mpic_send_doorbell);
 }
 
 static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
@@ -102,7 +103,7 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
 
        set_secondary_cpus_clock();
        flush_cache_all();
-       set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
+       set_cpu_coherent();
 
        /*
         * In order to boot the secondary CPUs we need to ensure
@@ -124,9 +125,11 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
 struct smp_operations armada_xp_smp_ops __initdata = {
        .smp_init_cpus          = armada_xp_smp_init_cpus,
        .smp_prepare_cpus       = armada_xp_smp_prepare_cpus,
-       .smp_secondary_init     = armada_xp_secondary_init,
        .smp_boot_secondary     = armada_xp_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
        .cpu_die                = armada_xp_cpu_die,
 #endif
 };
+
+CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp",
+                     &armada_xp_smp_ops);
index d71ef53107c4e9a530a558458d31eecf92039bd2..53a55c8520bf9a1fbab97919457af791f202ca2d 100644 (file)
  * other SOC units
  */
 
+#define pr_fmt(fmt) "mvebu-pmsu: " fmt
+
+#include <linux/cpu_pm.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 #include <linux/smp.h>
+#include <linux/resource.h>
+#include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <asm/smp_plat.h>
-#include "pmsu.h"
+#include <asm/suspend.h>
+#include <asm/tlbflush.h>
+#include "common.h"
 
 static void __iomem *pmsu_mp_base;
-static void __iomem *pmsu_reset_base;
 
-#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu)    ((cpu * 0x100) + 0x24)
-#define PMSU_RESET_CTL_OFFSET(cpu)             (cpu * 0x8)
+#define PMSU_BASE_OFFSET    0x100
+#define PMSU_REG_SIZE      0x1000
+
+/* PMSU MP registers */
+#define PMSU_CONTROL_AND_CONFIG(cpu)       ((cpu * 0x100) + 0x104)
+#define PMSU_CONTROL_AND_CONFIG_DFS_REQ                BIT(18)
+#define PMSU_CONTROL_AND_CONFIG_PWDDN_REQ      BIT(16)
+#define PMSU_CONTROL_AND_CONFIG_L2_PWDDN       BIT(20)
+
+#define PMSU_CPU_POWER_DOWN_CONTROL(cpu)    ((cpu * 0x100) + 0x108)
+
+#define PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP     BIT(0)
+
+#define PMSU_STATUS_AND_MASK(cpu)          ((cpu * 0x100) + 0x10c)
+#define PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT     BIT(16)
+#define PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT  BIT(17)
+#define PMSU_STATUS_AND_MASK_IRQ_WAKEUP                BIT(20)
+#define PMSU_STATUS_AND_MASK_FIQ_WAKEUP                BIT(21)
+#define PMSU_STATUS_AND_MASK_DBG_WAKEUP                BIT(22)
+#define PMSU_STATUS_AND_MASK_IRQ_MASK          BIT(24)
+#define PMSU_STATUS_AND_MASK_FIQ_MASK          BIT(25)
+
+#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124)
+
+/* PMSU fabric registers */
+#define L2C_NFABRIC_PM_CTL                 0x4
+#define L2C_NFABRIC_PM_CTL_PWR_DOWN            BIT(20)
+
+extern void ll_disable_coherency(void);
+extern void ll_enable_coherency(void);
+
+static struct platform_device armada_xp_cpuidle_device = {
+       .name = "cpuidle-armada-370-xp",
+};
 
 static struct of_device_id of_pmsu_table[] = {
-       {.compatible = "marvell,armada-370-xp-pmsu"},
+       { .compatible = "marvell,armada-370-pmsu", },
+       { .compatible = "marvell,armada-370-xp-pmsu", },
+       { .compatible = "marvell,armada-380-pmsu", },
        { /* end of list */ },
 };
 
-#ifdef CONFIG_SMP
-int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
+void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
 {
-       int reg, hw_cpu;
+       writel(virt_to_phys(boot_addr), pmsu_mp_base +
+               PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
+}
+
+static int __init armada_370_xp_pmsu_init(void)
+{
+       struct device_node *np;
+       struct resource res;
+       int ret = 0;
+
+       np = of_find_matching_node(NULL, of_pmsu_table);
+       if (!np)
+               return 0;
+
+       pr_info("Initializing Power Management Service Unit\n");
 
-       if (!pmsu_mp_base || !pmsu_reset_base) {
-               pr_warn("Can't boot CPU. PMSU is uninitialized\n");
-               return 1;
+       if (of_address_to_resource(np, 0, &res)) {
+               pr_err("unable to get resource\n");
+               ret = -ENOENT;
+               goto out;
        }
 
-       hw_cpu = cpu_logical_map(cpu_id);
+       if (of_device_is_compatible(np, "marvell,armada-370-xp-pmsu")) {
+               pr_warn(FW_WARN "deprecated pmsu binding\n");
+               res.start = res.start - PMSU_BASE_OFFSET;
+               res.end = res.start + PMSU_REG_SIZE - 1;
+       }
 
-       writel(virt_to_phys(boot_addr), pmsu_mp_base +
-                       PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
+       if (!request_mem_region(res.start, resource_size(&res),
+                               np->full_name)) {
+               pr_err("unable to request region\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       pmsu_mp_base = ioremap(res.start, resource_size(&res));
+       if (!pmsu_mp_base) {
+               pr_err("unable to map registers\n");
+               release_mem_region(res.start, resource_size(&res));
+               ret = -ENOMEM;
+               goto out;
+       }
+
+ out:
+       of_node_put(np);
+       return ret;
+}
+
+static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
+{
+       u32 reg;
+
+       if (pmsu_mp_base == NULL)
+               return;
+
+       /* Enable L2 & Fabric powerdown in Deep-Idle mode - Fabric */
+       reg = readl(pmsu_mp_base + L2C_NFABRIC_PM_CTL);
+       reg |= L2C_NFABRIC_PM_CTL_PWR_DOWN;
+       writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL);
+}
+
+static void armada_370_xp_cpu_resume(void)
+{
+       asm volatile("bl    ll_add_cpu_to_smp_group\n\t"
+                    "bl    ll_enable_coherency\n\t"
+                    "b     cpu_resume\n\t");
+}
+
+/* No locking is needed because we only access per-CPU registers */
+void armada_370_xp_pmsu_idle_prepare(bool deepidle)
+{
+       unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
+       u32 reg;
+
+       if (pmsu_mp_base == NULL)
+               return;
 
-       /* Release CPU from reset by clearing reset bit*/
-       reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
-       reg &= (~0x1);
-       writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
+       /*
+        * Adjust the PMSU configuration to wait for WFI signal, enable
+        * IRQ and FIQ as wakeup events, set wait for snoop queue empty
+        * indication and mask IRQ and FIQ from CPU
+        */
+       reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+       reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT    |
+              PMSU_STATUS_AND_MASK_IRQ_WAKEUP       |
+              PMSU_STATUS_AND_MASK_FIQ_WAKEUP       |
+              PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT |
+              PMSU_STATUS_AND_MASK_IRQ_MASK         |
+              PMSU_STATUS_AND_MASK_FIQ_MASK;
+       writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+
+       reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+       /* ask HW to power down the L2 Cache if needed */
+       if (deepidle)
+               reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
+
+       /* request power down */
+       reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ;
+       writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+
+       /* Disable snoop disable by HW - SW is taking care of it */
+       reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+       reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
+       writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+}
+
+static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
+{
+       armada_370_xp_pmsu_idle_prepare(deepidle);
+
+       v7_exit_coherency_flush(all);
+
+       ll_disable_coherency();
+
+       dsb();
+
+       wfi();
+
+       /* If we are here, wfi failed. As processors run out of
+        * coherency for some time, tlbs might be stale, so flush them
+        */
+       local_flush_tlb_all();
+
+       ll_enable_coherency();
+
+       /* Test the CR_C bit and set it if it was cleared */
+       asm volatile(
+       "mrc    p15, 0, %0, c1, c0, 0 \n\t"
+       "tst    %0, #(1 << 2) \n\t"
+       "orreq  %0, %0, #(1 << 2) \n\t"
+       "mcreq  p15, 0, %0, c1, c0, 0 \n\t"
+       "isb    "
+       : : "r" (0));
+
+       pr_warn("Failed to suspend the system\n");
 
        return 0;
 }
-#endif
 
-static int __init armada_370_xp_pmsu_init(void)
+static int armada_370_xp_cpu_suspend(unsigned long deepidle)
+{
+       return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend);
+}
+
+/* No locking is needed because we only access per-CPU registers */
+static noinline void armada_370_xp_pmsu_idle_restore(void)
+{
+       unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
+       u32 reg;
+
+       if (pmsu_mp_base == NULL)
+               return;
+
+       /* cancel ask HW to power down the L2 Cache if possible */
+       reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+       reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
+       writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+
+       /* cancel Enable wakeup events and mask interrupts */
+       reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+       reg &= ~(PMSU_STATUS_AND_MASK_IRQ_WAKEUP | PMSU_STATUS_AND_MASK_FIQ_WAKEUP);
+       reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT;
+       reg &= ~PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT;
+       reg &= ~(PMSU_STATUS_AND_MASK_IRQ_MASK | PMSU_STATUS_AND_MASK_FIQ_MASK);
+       writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+}
+
+static int armada_370_xp_cpu_pm_notify(struct notifier_block *self,
+                                   unsigned long action, void *hcpu)
+{
+       if (action == CPU_PM_ENTER) {
+               unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
+               mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
+       } else if (action == CPU_PM_EXIT) {
+               armada_370_xp_pmsu_idle_restore();
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block armada_370_xp_cpu_pm_notifier = {
+       .notifier_call = armada_370_xp_cpu_pm_notify,
+};
+
+int __init armada_370_xp_cpu_pm_init(void)
 {
        struct device_node *np;
 
+       /*
+        * Check that all the requirements are available to enable
+        * cpuidle. So far, it is only supported on Armada XP, cpuidle
+        * needs the coherency fabric and the PMSU enabled
+        */
+
+       if (!of_machine_is_compatible("marvell,armadaxp"))
+               return 0;
+
+       np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+       if (!np)
+               return 0;
+       of_node_put(np);
+
        np = of_find_matching_node(NULL, of_pmsu_table);
-       if (np) {
-               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);
-       }
+       if (!np)
+               return 0;
+       of_node_put(np);
+
+       armada_370_xp_pmsu_enable_l2_powerdown_onidle();
+       armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
+       platform_device_register(&armada_xp_cpuidle_device);
+       cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier);
 
        return 0;
 }
 
+arch_initcall(armada_370_xp_cpu_pm_init);
 early_initcall(armada_370_xp_pmsu_init);
index 614ba6832ff3ae4e14fe72ff12bdd98c83b95964..0c5524ac75b75c4b00b1cb2ba2814e94be35bc2a 100644 (file)
@@ -37,6 +37,8 @@ struct mvebu_system_controller {
 
        u32 rstoutn_mask_reset_out_en;
        u32 system_soft_reset;
+
+       u32 resume_boot_addr;
 };
 static struct mvebu_system_controller *mvebu_sc;
 
@@ -52,6 +54,7 @@ static const struct mvebu_system_controller armada_375_system_controller = {
        .system_soft_reset_offset = 0x58,
        .rstoutn_mask_reset_out_en = 0x1,
        .system_soft_reset = 0x1,
+       .resume_boot_addr = 0xd4,
 };
 
 static const struct mvebu_system_controller orion_system_controller = {
@@ -98,6 +101,16 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd)
                ;
 }
 
+#ifdef CONFIG_SMP
+void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
+{
+       BUG_ON(system_controller_base == NULL);
+       BUG_ON(mvebu_sc->resume_boot_addr == 0);
+       writel(virt_to_phys(boot_addr), system_controller_base +
+              mvebu_sc->resume_boot_addr);
+}
+#endif
+
 static int __init mvebu_system_controller_init(void)
 {
        const struct of_device_id *match;
@@ -114,4 +127,4 @@ static int __init mvebu_system_controller_init(void)
        return 0;
 }
 
-arch_initcall(mvebu_system_controller_init);
+early_initcall(mvebu_system_controller_init);
index 75e92952c18efe3e597791e6798c2ee2ce5969a1..40c5d5f1451cd34b19ebed5e2d58f150f6f4a29d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Secondary CPU startup routine source file.
  *
- * Copyright (C) 2009 Texas Instruments, Inc.
+ * Copyright (C) 2009-2014 Texas Instruments, Inc.
  *
  * Author:
  *      Santosh Shilimkar <santosh.shilimkar@ti.com>
  * code.  This routine also provides a holding flag into which
  * secondary core is held until we're ready for it to initialise.
  * The primary core will update this flag using a hardware
-+ * register AuxCoreBoot0.
+ * register AuxCoreBoot0.
  */
 ENTRY(omap5_secondary_startup)
+.arm
+THUMB( adr     r9, BSYM(wait)  )       @ CPU may be entered in ARM mode.
+THUMB( bx      r9              )       @ If this is a Thumb-2 kernel,
+THUMB( .thumb                  )       @ switch to Thumb now.
 wait:  ldr     r2, =AUX_CORE_BOOT0_PA  @ read from AuxCoreBoot0
        ldr     r0, [r2]
        mov     r0, r0, lsr #5
index 615e5b1fb025dddebadf72e21a7845c0a4306c14..6bf6267005571b5fadc03d4bab9d8e60489d2d0c 100644 (file)
 
 static bool is_offset_valid;
 static u8 smps_offset;
-/*
- * Flag to ensure Smartreflex bit in TWL
- * being cleared in board file is not overwritten.
- */
-static bool __initdata twl_sr_enable_autoinit;
 
-#define TWL4030_DCDC_GLOBAL_CFG        0x06
 #define REG_SMPS_OFFSET         0xE0
-#define SMARTREFLEX_ENABLE     BIT(3)
 
 static unsigned long twl4030_vsel_to_uv(const u8 vsel)
 {
@@ -251,18 +244,6 @@ int __init omap3_twl_init(void)
        if (!cpu_is_omap34xx())
                return -ENODEV;
 
-       /*
-        * The smartreflex bit on twl4030 specifies if the setting of voltage
-        * is done over the I2C_SR path. Since this setting is independent of
-        * the actual usage of smartreflex AVS module, we enable TWL SR bit
-        * by default irrespective of whether smartreflex AVS module is enabled
-        * on the OMAP side or not. This is because without this bit enabled,
-        * the voltage scaling through vp forceupdate/bypass mechanism of
-        * voltage scaling will not function on TWL over I2C_SR.
-        */
-       if (!twl_sr_enable_autoinit)
-               omap3_twl_set_sr_bit(true);
-
        voltdm = voltdm_lookup("mpu_iva");
        omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
 
@@ -271,44 +252,3 @@ int __init omap3_twl_init(void)
 
        return 0;
 }
-
-/**
- * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL
- * @enable: enable SR mode in twl or not
- *
- * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure
- * voltage scaling through OMAP SR works. Else, the smartreflex bit
- * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but
- * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct
- * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages,
- * in those scenarios this bit is to be cleared (enable = false).
- *
- * Returns 0 on success, error is returned if I2C read/write fails.
- */
-int __init omap3_twl_set_sr_bit(bool enable)
-{
-       u8 temp;
-       int ret;
-       if (twl_sr_enable_autoinit)
-               pr_warning("%s: unexpected multiple calls\n", __func__);
-
-       ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
-                             TWL4030_DCDC_GLOBAL_CFG);
-       if (ret)
-               goto err;
-
-       if (enable)
-               temp |= SMARTREFLEX_ENABLE;
-       else
-               temp &= ~SMARTREFLEX_ENABLE;
-
-       ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
-                              TWL4030_DCDC_GLOBAL_CFG);
-       if (!ret) {
-               twl_sr_enable_autoinit = true;
-               return 0;
-       }
-err:
-       pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret);
-       return ret;
-}
index 14f2cae4109ca10fc61962b4d787a5f89ed70097..2412efb6cdd963950725bf2a51118851f0813c9a 100644 (file)
@@ -5,6 +5,11 @@ menu "Orion Implementations"
 config ARCH_ORION5X_DT
        bool "Marvell Orion5x Flattened Device Tree"
        select USE_OF
+       select ORION_CLK
+       select ORION_IRQCHIP
+       select ORION_TIMER
+       select PINCTRL
+       select PINCTRL_ORION
        help
          Say 'Y' here if you want your kernel to support the
          Marvell Orion5x using flattened device tree.
@@ -23,6 +28,14 @@ config MACH_RD88F5182
          Say 'Y' here if you want your kernel to support the
          Marvell Orion-NAS (88F5182) RD2
 
+config MACH_RD88F5182_DT
+       bool "Marvell Orion-NAS Reference Design (Flattened Device Tree)"
+       select ARCH_ORION5X_DT
+       select I2C_BOARDINFO
+       help
+         Say 'Y' here if you want your kernel to support the Marvell
+         Orion-NAS (88F5182) RD2, Flattened Device Tree.
+
 config MACH_KUROBOX_PRO
        bool "KuroBox Pro"
        select I2C_BOARDINFO
@@ -102,28 +115,13 @@ config MACH_MV2120
          Say 'Y' here if you want your kernel to support the
          HP Media Vault mv2120 or mv5100.
 
-config MACH_EDMINI_V2_DT
-       bool "LaCie Ethernet Disk mini V2 (Flattened Device Tree)"
-       select I2C_BOARDINFO
+config MACH_D2NET_DT
+       bool "LaCie d2 Network / Big Disk Network (Flattened Device Tree)"
        select ARCH_ORION5X_DT
-       help
-         Say 'Y' here if you want your kernel to support the
-         LaCie Ethernet Disk mini V2 (Flattened Device Tree).
-
-config MACH_D2NET
-       bool "LaCie d2 Network"
-       select I2C_BOARDINFO
        help
          Say 'Y' here if you want your kernel to support the
          LaCie d2 Network NAS.
 
-config MACH_BIGDISK
-       bool "LaCie Big Disk Network"
-       select I2C_BOARDINFO
-       help
-         Say 'Y' here if you want your kernel to support the
-         LaCie Big Disk Network NAS.
-
 config MACH_NET2BIG
        bool "LaCie 2Big Network"
        select I2C_BOARDINFO
@@ -131,8 +129,9 @@ config MACH_NET2BIG
          Say 'Y' here if you want your kernel to support the
          LaCie 2Big Network NAS.
 
-config MACH_MSS2
-       bool "Maxtor Shared Storage II"
+config MACH_MSS2_DT
+       bool "Maxtor Shared Storage II (Flattened Device Tree)"
+       select ARCH_ORION5X_DT
        help
          Say 'Y' here if you want your kernel to support the
          Maxtor Shared Storage II platform.
index 45da805fb23692d07703310e8076a0cd8e4070f5..a40b5c9a58c4fb1795ff18c78bfe0c4f4073f42a 100644 (file)
@@ -12,10 +12,7 @@ obj-$(CONFIG_MACH_TS409)     += ts409-setup.o tsx09-common.o
 obj-$(CONFIG_MACH_WRT350N_V2)  += wrt350n-v2-setup.o
 obj-$(CONFIG_MACH_TS78XX)      += ts78xx-setup.o
 obj-$(CONFIG_MACH_MV2120)      += mv2120-setup.o
-obj-$(CONFIG_MACH_D2NET)       += d2net-setup.o
-obj-$(CONFIG_MACH_BIGDISK)     += d2net-setup.o
 obj-$(CONFIG_MACH_NET2BIG)     += net2big-setup.o
-obj-$(CONFIG_MACH_MSS2)                += mss2-setup.o
 obj-$(CONFIG_MACH_WNR854T)     += wnr854t-setup.o
 obj-$(CONFIG_MACH_RD88F5181L_GE)       += rd88f5181l-ge-setup.o
 obj-$(CONFIG_MACH_RD88F5181L_FXO)      += rd88f5181l-fxo-setup.o
@@ -23,4 +20,6 @@ obj-$(CONFIG_MACH_RD88F6183AP_GE)     += rd88f6183ap-ge-setup.o
 obj-$(CONFIG_MACH_LINKSTATION_LSCHL)   += ls-chl-setup.o
 
 obj-$(CONFIG_ARCH_ORION5X_DT)          += board-dt.o
-obj-$(CONFIG_MACH_EDMINI_V2_DT)        += edmini_v2-setup.o
+obj-$(CONFIG_MACH_D2NET_DT)    += board-d2net.o
+obj-$(CONFIG_MACH_MSS2_DT)     += board-mss2.o
+obj-$(CONFIG_MACH_RD88F5182_DT)        += board-rd88f5182.o
diff --git a/arch/arm/mach-orion5x/board-d2net.c b/arch/arm/mach-orion5x/board-d2net.c
new file mode 100644 (file)
index 0000000..8a72841
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * arch/arm/mach-orion5x/board-d2net.c
+ *
+ * LaCie d2Network and Big Disk Network NAS setup
+ *
+ * Copyright (C) 2009 Simon Guinot <sguinot@lacie.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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/orion5x.h>
+#include <plat/orion-gpio.h>
+#include "common.h"
+
+/*****************************************************************************
+ * LaCie d2 Network Info
+ ****************************************************************************/
+
+/*****************************************************************************
+ * GPIO LED's
+ ****************************************************************************/
+
+/*
+ * The blue front LED is wired to the CPLD and can blink in relation with the
+ * SATA activity.
+ *
+ * The following array detail the different LED registers and the combination
+ * of their possible values:
+ *
+ * led_off   | blink_ctrl | SATA active | LED state
+ *           |            |             |
+ *    1      |     x      |      x      |  off
+ *    0      |     0      |      0      |  off
+ *    0      |     1      |      0      |  blink (rate 300ms)
+ *    0      |     x      |      1      |  on
+ *
+ * Notes: The blue and the red front LED's can't be on at the same time.
+ *        Red LED have priority.
+ */
+
+#define D2NET_GPIO_RED_LED             6
+#define D2NET_GPIO_BLUE_LED_BLINK_CTRL 16
+#define D2NET_GPIO_BLUE_LED_OFF                23
+
+static struct gpio_led d2net_leds[] = {
+       {
+               .name = "d2net:blue:sata",
+               .default_trigger = "default-on",
+               .gpio = D2NET_GPIO_BLUE_LED_OFF,
+               .active_low = 1,
+       },
+       {
+               .name = "d2net:red:fail",
+               .gpio = D2NET_GPIO_RED_LED,
+       },
+};
+
+static struct gpio_led_platform_data d2net_led_data = {
+       .num_leds = ARRAY_SIZE(d2net_leds),
+       .leds = d2net_leds,
+};
+
+static struct platform_device d2net_gpio_leds = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &d2net_led_data,
+       },
+};
+
+static void __init d2net_gpio_leds_init(void)
+{
+       int err;
+
+       /* Configure register blink_ctrl to allow SATA activity LED blinking. */
+       err = gpio_request(D2NET_GPIO_BLUE_LED_BLINK_CTRL, "blue LED blink");
+       if (err == 0) {
+               err = gpio_direction_output(D2NET_GPIO_BLUE_LED_BLINK_CTRL, 1);
+               if (err)
+                       gpio_free(D2NET_GPIO_BLUE_LED_BLINK_CTRL);
+       }
+       if (err)
+               pr_err("d2net: failed to configure blue LED blink GPIO\n");
+
+       platform_device_register(&d2net_gpio_leds);
+}
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+
+void __init d2net_init(void)
+{
+       d2net_gpio_leds_init();
+
+       pr_notice("d2net: Flash write are not yet supported.\n");
+}
index c134a826070a14ccadda4293181f27cf81278804..35d418faf8f1b87c243199bd7552a24d39e53e43 100644 (file)
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/cpu.h>
+#include <linux/mbus.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
 #include <asm/system_misc.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/map.h>
 #include <mach/orion5x.h>
+#include <mach/bridge-regs.h>
 #include <plat/irq.h>
+#include <plat/time.h>
 #include "common.h"
 
 static struct of_dev_auxdata orion5x_auxdata_lookup[] __initdata = {
@@ -39,14 +45,13 @@ static void __init orion5x_dt_init(void)
        orion5x_id(&dev, &rev, &dev_name);
        printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk);
 
+       BUG_ON(mvebu_mbus_dt_init());
+
        /*
         * Setup Orion address map
         */
        orion5x_setup_wins();
 
-       /* Setup root of clk tree */
-       clk_init();
-
        /*
         * Don't issue "Wait for Interrupt" instruction if we are
         * running on D0 5281 silicon.
@@ -56,8 +61,8 @@ static void __init orion5x_dt_init(void)
                cpu_idle_poll_ctrl(true);
        }
 
-       if (of_machine_is_compatible("lacie,ethernet-disk-mini-v2"))
-               edmini_v2_init();
+       if (of_machine_is_compatible("maxtor,shared-storage-2"))
+               mss2_init();
 
        of_platform_populate(NULL, of_default_bus_match_table,
                             orion5x_auxdata_lookup, NULL);
@@ -71,9 +76,6 @@ static const char *orion5x_dt_compat[] = {
 DT_MACHINE_START(ORION5X_DT, "Marvell Orion5x (Flattened Device Tree)")
        /* Maintainer: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> */
        .map_io         = orion5x_map_io,
-       .init_early     = orion5x_init_early,
-       .init_irq       = orion_dt_init_irq,
-       .init_time      = orion5x_timer_init,
        .init_machine   = orion5x_dt_init,
        .restart        = orion5x_restart,
        .dt_compat      = orion5x_dt_compat,
diff --git a/arch/arm/mach-orion5x/board-mss2.c b/arch/arm/mach-orion5x/board-mss2.c
new file mode 100644 (file)
index 0000000..66f9c3b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Maxtor Shared Storage II Board Setup
+ *
+ * Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.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/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/orion5x.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+
+/*****************************************************************************
+ * Maxtor Shared Storage II Info
+ ****************************************************************************/
+
+/****************************************************************************
+ * PCI setup
+ ****************************************************************************/
+static int __init mss2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int irq;
+
+       /*
+        * Check for devices with hard-wired IRQs.
+        */
+       irq = orion5x_pci_map_irq(dev, slot, pin);
+       if (irq != -1)
+               return irq;
+
+       return -1;
+}
+
+static struct hw_pci mss2_pci __initdata = {
+       .nr_controllers = 2,
+       .setup          = orion5x_pci_sys_setup,
+       .scan           = orion5x_pci_sys_scan_bus,
+       .map_irq        = mss2_pci_map_irq,
+};
+
+static int __init mss2_pci_init(void)
+{
+       if (machine_is_mss2())
+               pci_common_init(&mss2_pci);
+
+       return 0;
+}
+subsys_initcall(mss2_pci_init);
+
+/*****************************************************************************
+ * MSS2 power off method
+ ****************************************************************************/
+/*
+ * On the Maxtor Shared Storage II, the shutdown process is the following :
+ * - Userland modifies U-boot env to tell U-boot to go idle at next boot
+ * - The board reboots
+ * - U-boot starts and go into an idle mode until the user press "power"
+ */
+static void mss2_power_off(void)
+{
+       u32 reg;
+
+       /*
+        * Enable and issue soft reset
+        */
+       reg = readl(RSTOUTn_MASK);
+       reg |= 1 << 2;
+       writel(reg, RSTOUTn_MASK);
+
+       reg = readl(CPU_SOFT_RESET);
+       reg |= 1;
+       writel(reg, CPU_SOFT_RESET);
+}
+
+void __init mss2_init(void)
+{
+       /* register mss2 specific power-off method */
+       pm_power_off = mss2_power_off;
+}
diff --git a/arch/arm/mach-orion5x/board-rd88f5182.c b/arch/arm/mach-orion5x/board-rd88f5182.c
new file mode 100644 (file)
index 0000000..270824b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * arch/arm/mach-orion5x/rd88f5182-setup.c
+ *
+ * Marvell Orion-NAS Reference Design Setup
+ *
+ * Maintainer: Ronen Shitrit <rshitrit@marvell.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/gpio.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/orion5x.h>
+#include "common.h"
+
+/*****************************************************************************
+ * RD-88F5182 Info
+ ****************************************************************************/
+
+/*
+ * PCI
+ */
+
+#define RD88F5182_PCI_SLOT0_OFFS       7
+#define RD88F5182_PCI_SLOT0_IRQ_A_PIN  7
+#define RD88F5182_PCI_SLOT0_IRQ_B_PIN  6
+
+/*****************************************************************************
+ * PCI
+ ****************************************************************************/
+
+static void __init rd88f5182_pci_preinit(void)
+{
+       int pin;
+
+       /*
+        * Configure PCI GPIO IRQ pins
+        */
+       pin = RD88F5182_PCI_SLOT0_IRQ_A_PIN;
+       if (gpio_request(pin, "PCI IntA") == 0) {
+               if (gpio_direction_input(pin) == 0) {
+                       irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW);
+               } else {
+                       printk(KERN_ERR "rd88f5182_pci_preinit failed to "
+                                       "set_irq_type pin %d\n", pin);
+                       gpio_free(pin);
+               }
+       } else {
+               printk(KERN_ERR "rd88f5182_pci_preinit failed to request gpio %d\n", pin);
+       }
+
+       pin = RD88F5182_PCI_SLOT0_IRQ_B_PIN;
+       if (gpio_request(pin, "PCI IntB") == 0) {
+               if (gpio_direction_input(pin) == 0) {
+                       irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW);
+               } else {
+                       printk(KERN_ERR "rd88f5182_pci_preinit failed to "
+                                       "set_irq_type pin %d\n", pin);
+                       gpio_free(pin);
+               }
+       } else {
+               printk(KERN_ERR "rd88f5182_pci_preinit failed to gpio_request %d\n", pin);
+       }
+}
+
+static int __init rd88f5182_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
+{
+       int irq;
+
+       /*
+        * Check for devices with hard-wired IRQs.
+        */
+       irq = orion5x_pci_map_irq(dev, slot, pin);
+       if (irq != -1)
+               return irq;
+
+       /*
+        * PCI IRQs are connected via GPIOs
+        */
+       switch (slot - RD88F5182_PCI_SLOT0_OFFS) {
+       case 0:
+               if (pin == 1)
+                       return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_A_PIN);
+               else
+                       return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_B_PIN);
+       default:
+               return -1;
+       }
+}
+
+static struct hw_pci rd88f5182_pci __initdata = {
+       .nr_controllers = 2,
+       .preinit        = rd88f5182_pci_preinit,
+       .setup          = orion5x_pci_sys_setup,
+       .scan           = orion5x_pci_sys_scan_bus,
+       .map_irq        = rd88f5182_pci_map_irq,
+};
+
+static int __init rd88f5182_pci_init(void)
+{
+       if (of_machine_is_compatible("marvell,rd-88f5182-nas"))
+               pci_common_init(&rd88f5182_pci);
+
+       return 0;
+}
+
+subsys_initcall(rd88f5182_pci_init);
index f565f9944af2ee45b795b180391853ffa8810a12..26d6f34b6027e4a4e34c9a74ef56ad614edfa9e2 100644 (file)
@@ -21,7 +21,7 @@ struct mv_sata_platform_data;
 #define ORION_MBUS_DEVBUS_BOOT_ATTR   0x0f
 #define ORION_MBUS_DEVBUS_TARGET(cs)  0x01
 #define ORION_MBUS_DEVBUS_ATTR(cs)    (~(1 << cs))
-#define ORION_MBUS_SRAM_TARGET        0x00
+#define ORION_MBUS_SRAM_TARGET        0x09
 #define ORION_MBUS_SRAM_ATTR          0x00
 
 /*
@@ -64,17 +64,16 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
 struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
 int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
-/* board init functions for boards not fully converted to fdt */
-#ifdef CONFIG_MACH_EDMINI_V2_DT
-void edmini_v2_init(void);
-#else
-static inline void edmini_v2_init(void) {};
-#endif
-
 struct meminfo;
 struct tag;
 extern void __init tag_fixup_mem32(struct tag *, char **, struct meminfo *);
 
+#ifdef CONFIG_MACH_MSS2_DT
+extern void mss2_init(void);
+#else
+static inline void mss2_init(void) {}
+#endif
+
 /*****************************************************************************
  * Helpers to access Orion registers
  ****************************************************************************/
diff --git a/arch/arm/mach-orion5x/d2net-setup.c b/arch/arm/mach-orion5x/d2net-setup.c
deleted file mode 100644 (file)
index 8f68b74..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * arch/arm/mach-orion5x/d2net-setup.c
- *
- * LaCie d2Network and Big Disk Network NAS setup
- *
- * Copyright (C) 2009 Simon Guinot <sguinot@lacie.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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mv643xx_eth.h>
-#include <linux/leds.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/ata_platform.h>
-#include <linux/gpio.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
-#include <plat/orion-gpio.h>
-#include "common.h"
-#include "mpp.h"
-
-/*****************************************************************************
- * LaCie d2 Network Info
- ****************************************************************************/
-
-/*
- * 512KB NOR flash Device bus boot chip select
- */
-
-#define D2NET_NOR_BOOT_BASE            0xfff80000
-#define D2NET_NOR_BOOT_SIZE            SZ_512K
-
-/*****************************************************************************
- * 512KB NOR Flash on Boot Device
- ****************************************************************************/
-
-/*
- * TODO: Check write support on flash MX29LV400CBTC-70G
- */
-
-static struct mtd_partition d2net_partitions[] = {
-       {
-               .name           = "Full512kb",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       },
-};
-
-static struct physmap_flash_data d2net_nor_flash_data = {
-       .width          = 1,
-       .parts          = d2net_partitions,
-       .nr_parts       = ARRAY_SIZE(d2net_partitions),
-};
-
-static struct resource d2net_nor_flash_resource = {
-       .flags                  = IORESOURCE_MEM,
-       .start                  = D2NET_NOR_BOOT_BASE,
-       .end                    = D2NET_NOR_BOOT_BASE
-                                       + D2NET_NOR_BOOT_SIZE - 1,
-};
-
-static struct platform_device d2net_nor_flash = {
-       .name                   = "physmap-flash",
-       .id                     = 0,
-       .dev            = {
-               .platform_data  = &d2net_nor_flash_data,
-       },
-       .num_resources          = 1,
-       .resource               = &d2net_nor_flash_resource,
-};
-
-/*****************************************************************************
- * Ethernet
- ****************************************************************************/
-
-static struct mv643xx_eth_platform_data d2net_eth_data = {
-       .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
-};
-
-/*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-/*
- * i2c addr | chip         | description
- * 0x32     | Ricoh 5C372b | RTC
- * 0x3e     | GMT G762     | PWM fan controller
- * 0x50     | HT24LC08     | eeprom (1kB)
- *
- * TODO: Add G762 support to the g760a driver.
- */
-static struct i2c_board_info __initdata d2net_i2c_devices[] = {
-       {
-               I2C_BOARD_INFO("rs5c372b", 0x32),
-       }, {
-               I2C_BOARD_INFO("24c08", 0x50),
-       },
-};
-
-/*****************************************************************************
- * SATA
- ****************************************************************************/
-
-static struct mv_sata_platform_data d2net_sata_data = {
-       .n_ports        = 2,
-};
-
-#define D2NET_GPIO_SATA0_POWER 3
-#define D2NET_GPIO_SATA1_POWER 12
-
-static void __init d2net_sata_power_init(void)
-{
-       int err;
-
-       err = gpio_request(D2NET_GPIO_SATA0_POWER, "SATA0 power");
-       if (err == 0) {
-               err = gpio_direction_output(D2NET_GPIO_SATA0_POWER, 1);
-               if (err)
-                       gpio_free(D2NET_GPIO_SATA0_POWER);
-       }
-       if (err)
-               pr_err("d2net: failed to configure SATA0 power GPIO\n");
-
-       err = gpio_request(D2NET_GPIO_SATA1_POWER, "SATA1 power");
-       if (err == 0) {
-               err = gpio_direction_output(D2NET_GPIO_SATA1_POWER, 1);
-               if (err)
-                       gpio_free(D2NET_GPIO_SATA1_POWER);
-       }
-       if (err)
-               pr_err("d2net: failed to configure SATA1 power GPIO\n");
-}
-
-/*****************************************************************************
- * GPIO LED's
- ****************************************************************************/
-
-/*
- * The blue front LED is wired to the CPLD and can blink in relation with the
- * SATA activity.
- *
- * The following array detail the different LED registers and the combination
- * of their possible values:
- *
- * led_off   | blink_ctrl | SATA active | LED state
- *           |            |             |
- *    1      |     x      |      x      |  off
- *    0      |     0      |      0      |  off
- *    0      |     1      |      0      |  blink (rate 300ms)
- *    0      |     x      |      1      |  on
- *
- * Notes: The blue and the red front LED's can't be on at the same time.
- *        Red LED have priority.
- */
-
-#define D2NET_GPIO_RED_LED             6
-#define D2NET_GPIO_BLUE_LED_BLINK_CTRL 16
-#define D2NET_GPIO_BLUE_LED_OFF                23
-
-static struct gpio_led d2net_leds[] = {
-       {
-               .name = "d2net:blue:sata",
-               .default_trigger = "default-on",
-               .gpio = D2NET_GPIO_BLUE_LED_OFF,
-               .active_low = 1,
-       },
-       {
-               .name = "d2net:red:fail",
-               .gpio = D2NET_GPIO_RED_LED,
-       },
-};
-
-static struct gpio_led_platform_data d2net_led_data = {
-       .num_leds = ARRAY_SIZE(d2net_leds),
-       .leds = d2net_leds,
-};
-
-static struct platform_device d2net_gpio_leds = {
-       .name           = "leds-gpio",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &d2net_led_data,
-       },
-};
-
-static void __init d2net_gpio_leds_init(void)
-{
-       int err;
-
-       /* Configure GPIO over MPP max number. */
-       orion_gpio_set_valid(D2NET_GPIO_BLUE_LED_OFF, 1);
-
-       /* Configure register blink_ctrl to allow SATA activity LED blinking. */
-       err = gpio_request(D2NET_GPIO_BLUE_LED_BLINK_CTRL, "blue LED blink");
-       if (err == 0) {
-               err = gpio_direction_output(D2NET_GPIO_BLUE_LED_BLINK_CTRL, 1);
-               if (err)
-                       gpio_free(D2NET_GPIO_BLUE_LED_BLINK_CTRL);
-       }
-       if (err)
-               pr_err("d2net: failed to configure blue LED blink GPIO\n");
-
-       platform_device_register(&d2net_gpio_leds);
-}
-
-/****************************************************************************
- * GPIO keys
- ****************************************************************************/
-
-#define D2NET_GPIO_PUSH_BUTTON         18
-#define D2NET_GPIO_POWER_SWITCH_ON     8
-#define D2NET_GPIO_POWER_SWITCH_OFF    9
-
-#define D2NET_SWITCH_POWER_ON          0x1
-#define D2NET_SWITCH_POWER_OFF         0x2
-
-static struct gpio_keys_button d2net_buttons[] = {
-       {
-               .type           = EV_SW,
-               .code           = D2NET_SWITCH_POWER_OFF,
-               .gpio           = D2NET_GPIO_POWER_SWITCH_OFF,
-               .desc           = "Power rocker switch (auto|off)",
-               .active_low     = 0,
-       },
-       {
-               .type           = EV_SW,
-               .code           = D2NET_SWITCH_POWER_ON,
-               .gpio           = D2NET_GPIO_POWER_SWITCH_ON,
-               .desc           = "Power rocker switch (on|auto)",
-               .active_low     = 0,
-       },
-       {
-               .type           = EV_KEY,
-               .code           = KEY_POWER,
-               .gpio           = D2NET_GPIO_PUSH_BUTTON,
-               .desc           = "Front Push Button",
-               .active_low     = 0,
-       },
-};
-
-static struct gpio_keys_platform_data d2net_button_data = {
-       .buttons        = d2net_buttons,
-       .nbuttons       = ARRAY_SIZE(d2net_buttons),
-};
-
-static struct platform_device d2net_gpio_buttons = {
-       .name           = "gpio-keys",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &d2net_button_data,
-       },
-};
-
-/*****************************************************************************
- * General Setup
- ****************************************************************************/
-
-static unsigned int d2net_mpp_modes[] __initdata = {
-       MPP0_GPIO,      /* Board ID (bit 0) */
-       MPP1_GPIO,      /* Board ID (bit 1) */
-       MPP2_GPIO,      /* Board ID (bit 2) */
-       MPP3_GPIO,      /* SATA 0 power */
-       MPP4_UNUSED,
-       MPP5_GPIO,      /* Fan fail detection */
-       MPP6_GPIO,      /* Red front LED */
-       MPP7_UNUSED,
-       MPP8_GPIO,      /* Rear power switch (on|auto) */
-       MPP9_GPIO,      /* Rear power switch (auto|off) */
-       MPP10_UNUSED,
-       MPP11_UNUSED,
-       MPP12_GPIO,     /* SATA 1 power */
-       MPP13_UNUSED,
-       MPP14_SATA_LED, /* SATA 0 active */
-       MPP15_SATA_LED, /* SATA 1 active */
-       MPP16_GPIO,     /* Blue front LED blink control */
-       MPP17_UNUSED,
-       MPP18_GPIO,     /* Front button (0 = Released, 1 = Pushed ) */
-       MPP19_UNUSED,
-       0,
-       /* 22: USB port 1 fuse (0 = Fail, 1 = Ok) */
-       /* 23: Blue front LED off */
-       /* 24: Inhibit board power off (0 = Disabled, 1 = Enabled) */
-};
-
-#define D2NET_GPIO_INHIBIT_POWER_OFF    24
-
-static void __init d2net_init(void)
-{
-       /*
-        * Setup basic Orion functions. Need to be called early.
-        */
-       orion5x_init();
-
-       orion5x_mpp_conf(d2net_mpp_modes);
-
-       /*
-        * Configure peripherals.
-        */
-       orion5x_ehci0_init();
-       orion5x_eth_init(&d2net_eth_data);
-       orion5x_i2c_init();
-       orion5x_uart0_init();
-
-       d2net_sata_power_init();
-       orion5x_sata_init(&d2net_sata_data);
-
-       mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
-                                   ORION_MBUS_DEVBUS_BOOT_ATTR,
-                                   D2NET_NOR_BOOT_BASE,
-                                   D2NET_NOR_BOOT_SIZE);
-       platform_device_register(&d2net_nor_flash);
-
-       platform_device_register(&d2net_gpio_buttons);
-
-       d2net_gpio_leds_init();
-
-       pr_notice("d2net: Flash write are not yet supported.\n");
-
-       i2c_register_board_info(0, d2net_i2c_devices,
-                               ARRAY_SIZE(d2net_i2c_devices));
-
-       orion_gpio_set_valid(D2NET_GPIO_INHIBIT_POWER_OFF, 1);
-}
-
-/* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
-
-#ifdef CONFIG_MACH_D2NET
-MACHINE_START(D2NET, "LaCie d2 Network")
-       .atag_offset    = 0x100,
-       .init_machine   = d2net_init,
-       .map_io         = orion5x_map_io,
-       .init_early     = orion5x_init_early,
-       .init_irq       = orion5x_init_irq,
-       .init_time      = orion5x_timer_init,
-       .fixup          = tag_fixup_mem32,
-       .restart        = orion5x_restart,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_MACH_BIGDISK
-MACHINE_START(BIGDISK, "LaCie Big Disk Network")
-       .atag_offset    = 0x100,
-       .init_machine   = d2net_init,
-       .map_io         = orion5x_map_io,
-       .init_early     = orion5x_init_early,
-       .init_irq       = orion5x_init_irq,
-       .init_time      = orion5x_timer_init,
-       .fixup          = tag_fixup_mem32,
-       .restart        = orion5x_restart,
-MACHINE_END
-#endif
-
diff --git a/arch/arm/mach-orion5x/edmini_v2-setup.c b/arch/arm/mach-orion5x/edmini_v2-setup.c
deleted file mode 100644 (file)
index f66c1b2..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * arch/arm/mach-orion5x/edmini_v2-setup.c
- *
- * LaCie Ethernet Disk mini V2 Setup
- *
- * Copyright (C) 2008 Christopher Moore <moore@free.fr>
- * Copyright (C) 2008 Albert Aribaud <albert.aribaud@free.fr>
- *
- * 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.
- */
-
-/*
- * TODO: add Orion USB device port init when kernel.org support is added.
- * TODO: add flash write support: see below.
- * TODO: add power-off support.
- * TODO: add I2C EEPROM support.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <linux/mbus.h>
-#include <linux/mtd/physmap.h>
-#include <linux/leds.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/ata_platform.h>
-#include <linux/gpio.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
-#include "common.h"
-#include "mpp.h"
-
-/*****************************************************************************
- * EDMINI_V2 Info
- ****************************************************************************/
-
-/*
- * 512KB NOR flash Device bus boot chip select
- */
-
-#define EDMINI_V2_NOR_BOOT_BASE                0xfff80000
-#define EDMINI_V2_NOR_BOOT_SIZE                SZ_512K
-
-/*****************************************************************************
- * 512KB NOR Flash on BOOT Device
- ****************************************************************************/
-
-/*
- * Currently the MTD code does not recognize the MX29LV400CBCT as a bottom
- * -type device. This could cause risks of accidentally erasing critical
- * flash sectors. We thus define a single, write-protected partition covering
- * the whole flash.
- * TODO: once the flash part TOP/BOTTOM detection issue is sorted out in the MTD
- * code, break this into at least three partitions: 'u-boot code', 'u-boot
- * environment' and 'whatever is left'.
- */
-
-static struct mtd_partition edmini_v2_partitions[] = {
-       {
-               .name           = "Full512kb",
-               .size           = 0x00080000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE,
-       },
-};
-
-static struct physmap_flash_data edmini_v2_nor_flash_data = {
-       .width          = 1,
-       .parts          = edmini_v2_partitions,
-       .nr_parts       = ARRAY_SIZE(edmini_v2_partitions),
-};
-
-static struct resource edmini_v2_nor_flash_resource = {
-       .flags                  = IORESOURCE_MEM,
-       .start                  = EDMINI_V2_NOR_BOOT_BASE,
-       .end                    = EDMINI_V2_NOR_BOOT_BASE
-               + EDMINI_V2_NOR_BOOT_SIZE - 1,
-};
-
-static struct platform_device edmini_v2_nor_flash = {
-       .name                   = "physmap-flash",
-       .id                     = 0,
-       .dev            = {
-               .platform_data  = &edmini_v2_nor_flash_data,
-       },
-       .num_resources          = 1,
-       .resource               = &edmini_v2_nor_flash_resource,
-};
-
-/*****************************************************************************
- * RTC 5C372a on I2C bus
- ****************************************************************************/
-
-#define EDMINIV2_RTC_GPIO      3
-
-static struct i2c_board_info __initdata edmini_v2_i2c_rtc = {
-       I2C_BOARD_INFO("rs5c372a", 0x32),
-       .irq = 0,
-};
-
-/*****************************************************************************
- * General Setup
- ****************************************************************************/
-static unsigned int edminiv2_mpp_modes[] __initdata = {
-       MPP0_UNUSED,
-       MPP1_UNUSED,
-       MPP2_UNUSED,
-       MPP3_GPIO,      /* RTC interrupt */
-       MPP4_UNUSED,
-       MPP5_UNUSED,
-       MPP6_UNUSED,
-       MPP7_UNUSED,
-       MPP8_UNUSED,
-       MPP9_UNUSED,
-       MPP10_UNUSED,
-       MPP11_UNUSED,
-       MPP12_SATA_LED, /* SATA 0 presence */
-       MPP13_SATA_LED, /* SATA 1 presence */
-       MPP14_SATA_LED, /* SATA 0 active */
-       MPP15_SATA_LED, /* SATA 1 active */
-       /* 16: Power LED control (0 = On, 1 = Off) */
-       MPP16_GPIO,
-       /* 17: Power LED control select (0 = CPLD, 1 = GPIO16) */
-       MPP17_GPIO,
-       /* 18: Power button status (0 = Released, 1 = Pressed) */
-       MPP18_GPIO,
-       MPP19_UNUSED,
-       0,
-};
-
-void __init edmini_v2_init(void)
-{
-       orion5x_mpp_conf(edminiv2_mpp_modes);
-
-       /*
-        * Configure peripherals.
-        */
-       orion5x_ehci0_init();
-
-       mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
-                                   ORION_MBUS_DEVBUS_BOOT_ATTR,
-                                   EDMINI_V2_NOR_BOOT_BASE,
-                                   EDMINI_V2_NOR_BOOT_SIZE);
-       platform_device_register(&edmini_v2_nor_flash);
-
-       pr_notice("edmini_v2: USB device port, flash write and power-off "
-                 "are not yet supported.\n");
-
-       /* Get RTC IRQ and register the chip */
-       if (gpio_request(EDMINIV2_RTC_GPIO, "rtc") == 0) {
-               if (gpio_direction_input(EDMINIV2_RTC_GPIO) == 0)
-                       edmini_v2_i2c_rtc.irq = gpio_to_irq(EDMINIV2_RTC_GPIO);
-               else
-                       gpio_free(EDMINIV2_RTC_GPIO);
-       }
-
-       if (edmini_v2_i2c_rtc.irq == 0)
-               pr_warning("edmini_v2: failed to get RTC IRQ\n");
-
-       i2c_register_board_info(0, &edmini_v2_i2c_rtc, 1);
-}
index 9654b0cc58928741c13281eaf7c6b737411dd7ec..cd4bac4d7e43f194f8bf0306f7ed808d48caec3d 100644 (file)
@@ -16,6 +16,7 @@
 #include <mach/bridge-regs.h>
 #include <plat/orion-gpio.h>
 #include <plat/irq.h>
+#include <asm/exception.h>
 #include "common.h"
 
 static int __initdata gpio0_irqs[4] = {
@@ -25,10 +26,37 @@ static int __initdata gpio0_irqs[4] = {
        IRQ_ORION5X_GPIO_24_31,
 };
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+/*
+ * Compiling with both non-DT and DT support enabled, will
+ * break asm irq handler used by non-DT boards. Therefore,
+ * we provide a C-style irq handler even for non-DT boards,
+ * if MULTI_IRQ_HANDLER is set.
+ */
+
+asmlinkage void
+__exception_irq_entry orion5x_legacy_handle_irq(struct pt_regs *regs)
+{
+       u32 stat;
+
+       stat = readl_relaxed(MAIN_IRQ_CAUSE);
+       stat &= readl_relaxed(MAIN_IRQ_MASK);
+       if (stat) {
+               unsigned int hwirq = __fls(stat);
+               handle_IRQ(hwirq, regs);
+               return;
+       }
+}
+#endif
+
 void __init orion5x_init_irq(void)
 {
        orion_irq_init(0, MAIN_IRQ_MASK);
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       set_handle_irq(orion5x_legacy_handle_irq);
+#endif
+
        /*
         * Initialize gpiolib for GPIOs 0-31.
         */
diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c
deleted file mode 100644 (file)
index e105130..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Maxtor Shared Storage II Board Setup
- *
- * Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.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/init.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mv643xx_eth.h>
-#include <linux/leds.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/ata_platform.h>
-#include <linux/gpio.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
-#include <mach/bridge-regs.h>
-#include "common.h"
-#include "mpp.h"
-
-#define MSS2_NOR_BOOT_BASE     0xff800000
-#define MSS2_NOR_BOOT_SIZE     SZ_256K
-
-/*****************************************************************************
- * Maxtor Shared Storage II Info
- ****************************************************************************/
-
-/*
- * Maxtor Shared Storage II hardware :
- * - Marvell 88F5182-A2 C500
- * - Marvell 88E1111 Gigabit Ethernet PHY
- * - RTC M41T81 (@0x68) on I2C bus
- * - 256KB NOR flash
- * - 64MB of RAM
- */
-
-/*****************************************************************************
- * 256KB NOR Flash on BOOT Device
- ****************************************************************************/
-
-static struct physmap_flash_data mss2_nor_flash_data = {
-       .width          = 1,
-};
-
-static struct resource mss2_nor_flash_resource = {
-       .flags          = IORESOURCE_MEM,
-       .start          = MSS2_NOR_BOOT_BASE,
-       .end            = MSS2_NOR_BOOT_BASE + MSS2_NOR_BOOT_SIZE - 1,
-};
-
-static struct platform_device mss2_nor_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &mss2_nor_flash_data,
-       },
-       .resource       = &mss2_nor_flash_resource,
-       .num_resources  = 1,
-};
-
-/****************************************************************************
- * PCI setup
- ****************************************************************************/
-static int __init mss2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       int irq;
-
-       /*
-        * Check for devices with hard-wired IRQs.
-        */
-       irq = orion5x_pci_map_irq(dev, slot, pin);
-       if (irq != -1)
-               return irq;
-
-       return -1;
-}
-
-static struct hw_pci mss2_pci __initdata = {
-       .nr_controllers = 2,
-       .setup          = orion5x_pci_sys_setup,
-       .scan           = orion5x_pci_sys_scan_bus,
-       .map_irq        = mss2_pci_map_irq,
-};
-
-static int __init mss2_pci_init(void)
-{
-       if (machine_is_mss2())
-               pci_common_init(&mss2_pci);
-
-       return 0;
-}
-subsys_initcall(mss2_pci_init);
-
-
-/*****************************************************************************
- * Ethernet
- ****************************************************************************/
-
-static struct mv643xx_eth_platform_data mss2_eth_data = {
-       .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
-};
-
-/*****************************************************************************
- * SATA
- ****************************************************************************/
-
-static struct mv_sata_platform_data mss2_sata_data = {
-       .n_ports        = 2,
-};
-
-/*****************************************************************************
- * GPIO buttons
- ****************************************************************************/
-
-#define MSS2_GPIO_KEY_RESET    12
-#define MSS2_GPIO_KEY_POWER    11
-
-static struct gpio_keys_button mss2_buttons[] = {
-       {
-               .code           = KEY_POWER,
-               .gpio           = MSS2_GPIO_KEY_POWER,
-               .desc           = "Power",
-               .active_low     = 1,
-       }, {
-               .code           = KEY_RESTART,
-               .gpio           = MSS2_GPIO_KEY_RESET,
-               .desc           = "Reset",
-               .active_low     = 1,
-       },
-};
-
-static struct gpio_keys_platform_data mss2_button_data = {
-       .buttons        = mss2_buttons,
-       .nbuttons       = ARRAY_SIZE(mss2_buttons),
-};
-
-static struct platform_device mss2_button_device = {
-       .name           = "gpio-keys",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &mss2_button_data,
-       },
-};
-
-/*****************************************************************************
- * RTC m41t81 on I2C bus
- ****************************************************************************/
-
-#define MSS2_GPIO_RTC_IRQ      3
-
-static struct i2c_board_info __initdata mss2_i2c_rtc = {
-       I2C_BOARD_INFO("m41t81", 0x68),
-};
-
-/*****************************************************************************
- * MSS2 power off method
- ****************************************************************************/
-/*
- * On the Maxtor Shared Storage II, the shutdown process is the following :
- * - Userland modifies U-boot env to tell U-boot to go idle at next boot
- * - The board reboots
- * - U-boot starts and go into an idle mode until the user press "power"
- */
-static void mss2_power_off(void)
-{
-       u32 reg;
-
-       /*
-        * Enable and issue soft reset
-        */
-       reg = readl(RSTOUTn_MASK);
-       reg |= 1 << 2;
-       writel(reg, RSTOUTn_MASK);
-
-       reg = readl(CPU_SOFT_RESET);
-       reg |= 1;
-       writel(reg, CPU_SOFT_RESET);
-}
-
-/****************************************************************************
- * General Setup
- ****************************************************************************/
-static unsigned int mss2_mpp_modes[] __initdata = {
-       MPP0_GPIO,              /* Power LED */
-       MPP1_GPIO,              /* Error LED */
-       MPP2_UNUSED,
-       MPP3_GPIO,              /* RTC interrupt */
-       MPP4_GPIO,              /* HDD ind. (Single/Dual)*/
-       MPP5_GPIO,              /* HD0 5V control */
-       MPP6_GPIO,              /* HD0 12V control */
-       MPP7_GPIO,              /* HD1 5V control */
-       MPP8_GPIO,              /* HD1 12V control */
-       MPP9_UNUSED,
-       MPP10_GPIO,             /* Fan control */
-       MPP11_GPIO,             /* Power button */
-       MPP12_GPIO,             /* Reset button */
-       MPP13_UNUSED,
-       MPP14_SATA_LED,         /* SATA 0 active */
-       MPP15_SATA_LED,         /* SATA 1 active */
-       MPP16_UNUSED,
-       MPP17_UNUSED,
-       MPP18_UNUSED,
-       MPP19_UNUSED,
-       0,
-};
-
-static void __init mss2_init(void)
-{
-       /* Setup basic Orion functions. Need to be called early. */
-       orion5x_init();
-
-       orion5x_mpp_conf(mss2_mpp_modes);
-
-       /*
-        * MPP[20] Unused
-        * MPP[21] PCI clock
-        * MPP[22] USB 0 over current
-        * MPP[23] USB 1 over current
-        */
-
-       /*
-        * Configure peripherals.
-        */
-       orion5x_ehci0_init();
-       orion5x_ehci1_init();
-       orion5x_eth_init(&mss2_eth_data);
-       orion5x_i2c_init();
-       orion5x_sata_init(&mss2_sata_data);
-       orion5x_uart0_init();
-       orion5x_xor_init();
-
-       mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
-                                   ORION_MBUS_DEVBUS_BOOT_ATTR,
-                                   MSS2_NOR_BOOT_BASE,
-                                   MSS2_NOR_BOOT_SIZE);
-       platform_device_register(&mss2_nor_flash);
-
-       platform_device_register(&mss2_button_device);
-
-       if (gpio_request(MSS2_GPIO_RTC_IRQ, "rtc") == 0) {
-               if (gpio_direction_input(MSS2_GPIO_RTC_IRQ) == 0)
-                       mss2_i2c_rtc.irq = gpio_to_irq(MSS2_GPIO_RTC_IRQ);
-               else
-                       gpio_free(MSS2_GPIO_RTC_IRQ);
-       }
-       i2c_register_board_info(0, &mss2_i2c_rtc, 1);
-
-       /* register mss2 specific power-off method */
-       pm_power_off = mss2_power_off;
-}
-
-MACHINE_START(MSS2, "Maxtor Shared Storage II")
-       /* Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.com> */
-       .atag_offset    = 0x100,
-       .init_machine   = mss2_init,
-       .map_io         = orion5x_map_io,
-       .init_early     = orion5x_init_early,
-       .init_irq       = orion5x_init_irq,
-       .init_time      = orion5x_timer_init,
-       .fixup          = tag_fixup_mem32,
-       .restart        = orion5x_restart,
-MACHINE_END
index a028be23433453d0ef7bacef1af026853dcbb412..6aa22147cace9c89c1dae3edc28e99d4fa5a913c 100644 (file)
@@ -3,8 +3,6 @@ config ARCH_QCOM
        select ARCH_REQUIRE_GPIOLIB
        select ARM_GIC
        select CLKSRC_OF
-       select GENERIC_CLOCKEVENTS
-       select HAVE_SMP
        select QCOM_SCM if SMP
        help
          Support for Qualcomm's devicetree based systems.
index 1d5ee5c9a1dcd36624ab2c29d0a7111e7a3e1bdc..960b8dd78c4498f935fb841a510bb38736d09d4e 100644 (file)
@@ -148,6 +148,21 @@ struct platform_device realview_cf_device = {
        },
 };
 
+static struct resource realview_leds_resources[] = {
+       {
+               .start  = REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET,
+               .end    = REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET + 4,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device realview_leds_device = {
+       .name           = "versatile-leds",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(realview_leds_resources),
+       .resource       = realview_leds_resources,
+};
+
 static struct resource realview_i2c_resource = {
        .start          = REALVIEW_I2C_BASE,
        .end            = REALVIEW_I2C_BASE + SZ_4K - 1,
index 602ca5ec52c53a855e3bb6fa8ec2013486d28ba8..13dc830ef469a3587e22a54e1ad31a2b44a43737 100644 (file)
@@ -37,6 +37,7 @@ struct machine_desc;
 
 extern struct platform_device realview_flash_device;
 extern struct platform_device realview_cf_device;
+extern struct platform_device realview_leds_device;
 extern struct platform_device realview_i2c_device;
 extern struct mmci_platform_data realview_mmc0_plat_data;
 extern struct mmci_platform_data realview_mmc1_plat_data;
index c85ddb2a0ad09083e3e3c30901bc28bb3c807af2..6bb070e801287606466a54cd1e411d4b377570ef 100644 (file)
@@ -452,6 +452,7 @@ static void __init realview_eb_init(void)
        realview_flash_register(&realview_eb_flash_resource, 1);
        platform_device_register(&realview_i2c_device);
        platform_device_register(&char_lcd_device);
+       platform_device_register(&realview_leds_device);
        eth_device_register();
        realview_usb_register(realview_eb_isp1761_resources);
 
index c5eade76461be3cf2faa4d6dffbb9becc7cbb872..173f2c15de49ac6709d028d607fb0bb49a339df5 100644 (file)
@@ -367,6 +367,7 @@ static void __init realview_pb1176_init(void)
        realview_usb_register(realview_pb1176_isp1761_resources);
        platform_device_register(&pmu_device);
        platform_device_register(&char_lcd_device);
+       platform_device_register(&realview_leds_device);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
index f4b0962578feb94dd653033620bfed0fcfddeaac..bde7e6b1fd44ddba8cde40e13497b0bfc9f71314 100644 (file)
@@ -347,6 +347,7 @@ static void __init realview_pb11mp_init(void)
        realview_eth_register(NULL, realview_pb11mp_smsc911x_resources);
        platform_device_register(&realview_i2c_device);
        platform_device_register(&realview_cf_device);
+       platform_device_register(&realview_leds_device);
        realview_usb_register(realview_pb11mp_isp1761_resources);
        platform_device_register(&pmu_device);
 
index 10a3e1d76891315d6fce093a36d69618cbe48f44..4e57a8599265b6d69c70285a7573957f3da9347d 100644 (file)
@@ -289,6 +289,7 @@ static void __init realview_pba8_init(void)
        realview_eth_register(NULL, realview_pba8_smsc911x_resources);
        platform_device_register(&realview_i2c_device);
        platform_device_register(&realview_cf_device);
+       platform_device_register(&realview_leds_device);
        realview_usb_register(realview_pba8_isp1761_resources);
        platform_device_register(&pmu_device);
 
index 9d75493e3f0cc110751b168cadff78093b0d129f..72c96caebefa92fdfaac1f4cb19348b793a69631 100644 (file)
@@ -385,6 +385,7 @@ static void __init realview_pbx_init(void)
        realview_eth_register(NULL, realview_pbx_smsc911x_resources);
        platform_device_register(&realview_i2c_device);
        platform_device_register(&realview_cf_device);
+       platform_device_register(&realview_leds_device);
        realview_usb_register(realview_pbx_isp1761_resources);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
index 40cf50b9940cb13b02ab34173d479ac26cdcfbe9..fbafb9a1975bf4d7a816e4b393b0e2191bfb87d8 100644 (file)
@@ -25,6 +25,7 @@ comment "S3C24XX SoCs"
 config CPU_S3C2410
        bool "SAMSUNG S3C2410"
        default y
+       depends on SAMSUNG_CLOCK
        select CPU_ARM920T
        select CPU_LLSERIAL_S3C2410
        select S3C2410_CLOCK
@@ -38,8 +39,10 @@ config CPU_S3C2410
 
 config CPU_S3C2412
        bool "SAMSUNG S3C2412"
+       select COMMON_CLK
        select CPU_ARM926T
        select CPU_LLSERIAL_S3C2440
+       select S3C2412_COMMON_CLK
        select S3C2412_DMA if S3C24XX_DMA
        select S3C2412_PM if PM
        help
@@ -47,17 +50,18 @@ config CPU_S3C2412
 
 config CPU_S3C2416
        bool "SAMSUNG S3C2416/S3C2450"
+       select COMMON_CLK
        select CPU_ARM926T
        select CPU_LLSERIAL_S3C2440
        select S3C2416_PM if PM
-       select S3C2443_COMMON
+       select S3C2443_COMMON_CLK
        select S3C2443_DMA if S3C24XX_DMA
-       select SAMSUNG_CLKSRC
        help
          Support for the S3C2416 SoC from the S3C24XX line
 
 config CPU_S3C2440
        bool "SAMSUNG S3C2440"
+       depends on SAMSUNG_CLOCK
        select CPU_ARM920T
        select CPU_LLSERIAL_S3C2440
        select S3C2410_CLOCK
@@ -68,6 +72,7 @@ config CPU_S3C2440
 
 config CPU_S3C2442
        bool "SAMSUNG S3C2442"
+       depends on SAMSUNG_CLOCK
        select CPU_ARM920T
        select CPU_LLSERIAL_S3C2440
        select S3C2410_CLOCK
@@ -83,11 +88,11 @@ config CPU_S3C244X
 
 config CPU_S3C2443
        bool "SAMSUNG S3C2443"
+       select COMMON_CLK
        select CPU_ARM920T
        select CPU_LLSERIAL_S3C2440
-       select S3C2443_COMMON
+       select S3C2443_COMMON_CLK
        select S3C2443_DMA if S3C24XX_DMA
-       select SAMSUNG_CLKSRC
        help
          Support for the S3C2443 SoC from the S3C24XX line
 
@@ -359,6 +364,11 @@ config S3C2412_PM_SLEEP
 
 if CPU_S3C2412
 
+config S3C2412_COMMON_CLK
+       bool
+       help
+         Build the s3c2412 clock driver based on the common clock framework.
+
 config CPU_S3C2412_ONLY
        bool
        depends on !CPU_S3C2410 && !CPU_S3C2416 && !CPU_S3C2440 && \
@@ -641,11 +651,11 @@ endif     # CPU_S3C2442
 
 if CPU_S3C2443 || CPU_S3C2416
 
-config S3C2443_COMMON
+config S3C2443_COMMON_CLK
        bool
        help
-         Common code for the S3C2443 and similar processors, which includes
-         the S3C2416 and S3C2450.
+         Temporary symbol to build the clock driver based on the common clock
+         framework.
 
 config S3C2443_DMA
        bool
index 7f54e5b954ca8ccecde16a69dc19710eedbfda32..f25479721dc94d7c3b9924ee0ca406dce8ef6353 100644 (file)
@@ -21,12 +21,12 @@ obj-$(CONFIG_S3C2410_DMA)   += dma-s3c2410.o
 obj-$(CONFIG_S3C2410_PLL)      += pll-s3c2410.o
 obj-$(CONFIG_S3C2410_PM)       += pm-s3c2410.o sleep-s3c2410.o
 
-obj-$(CONFIG_CPU_S3C2412)      += s3c2412.o clock-s3c2412.o
+obj-$(CONFIG_CPU_S3C2412)      += s3c2412.o
 obj-$(CONFIG_S3C2412_DMA)      += dma-s3c2412.o
 obj-$(CONFIG_S3C2412_PM)       += pm-s3c2412.o
 obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o
 
-obj-$(CONFIG_CPU_S3C2416)      += s3c2416.o clock-s3c2416.o
+obj-$(CONFIG_CPU_S3C2416)      += s3c2416.o
 obj-$(CONFIG_S3C2416_PM)       += pm-s3c2416.o
 
 obj-$(CONFIG_CPU_S3C2440)      += s3c2440.o clock-s3c2440.o
@@ -36,7 +36,7 @@ obj-$(CONFIG_S3C2440_DMA)     += dma-s3c2440.o
 obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o
 obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o
 
-obj-$(CONFIG_CPU_S3C2443)      += s3c2443.o clock-s3c2443.o
+obj-$(CONFIG_CPU_S3C2443)      += s3c2443.o
 
 # PM
 
@@ -53,7 +53,6 @@ obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += cpufreq-utils.o
 obj-$(CONFIG_S3C2410_IOTIMING) += iotiming-s3c2410.o
 obj-$(CONFIG_S3C2412_IOTIMING) += iotiming-s3c2412.o
 
-obj-$(CONFIG_S3C2443_COMMON)   += common-s3c2443.o
 obj-$(CONFIG_S3C2443_DMA)      += dma-s3c2443.o
 
 #
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2412.c b/arch/arm/mach-s3c24xx/clock-s3c2412.c
deleted file mode 100644 (file)
index 192a5b2..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/clock.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2412,S3C2413 Clock control support
- *
- * This program is free software; 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/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/serial_core.h>
-#include <linux/serial_s3c.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-
-/* We currently have to assume that the system is running
- * from the XTPll input, and that all ***REFCLKs are being
- * fed from it, as we cannot read the state of OM[4] from
- * software.
- *
- * It would be possible for each board initialisation to
- * set the correct muxing at initialisation
-*/
-
-static int s3c2412_clkcon_enable(struct clk *clk, int enable)
-{
-       unsigned int clocks = clk->ctrlbit;
-       unsigned long clkcon;
-
-       clkcon = __raw_readl(S3C2410_CLKCON);
-
-       if (enable)
-               clkcon |= clocks;
-       else
-               clkcon &= ~clocks;
-
-       __raw_writel(clkcon, S3C2410_CLKCON);
-
-       return 0;
-}
-
-static int s3c2412_upll_enable(struct clk *clk, int enable)
-{
-       unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
-       unsigned long orig = upllcon;
-
-       if (!enable)
-               upllcon |= S3C2412_PLLCON_OFF;
-       else
-               upllcon &= ~S3C2412_PLLCON_OFF;
-
-       __raw_writel(upllcon, S3C2410_UPLLCON);
-
-       /* allow ~150uS for the PLL to settle and lock */
-
-       if (enable && (orig & S3C2412_PLLCON_OFF))
-               udelay(150);
-
-       return 0;
-}
-
-/* clock selections */
-
-static struct clk clk_erefclk = {
-       .name           = "erefclk",
-};
-
-static struct clk clk_urefclk = {
-       .name           = "urefclk",
-};
-
-static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_urefclk)
-               clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
-       else if (parent == &clk_upll)
-               clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static struct clk clk_usysclk = {
-       .name           = "usysclk",
-       .parent         = &clk_xtal,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2412_setparent_usysclk,
-       },
-};
-
-static struct clk clk_mrefclk = {
-       .name           = "mrefclk",
-       .parent         = &clk_xtal,
-};
-
-static struct clk clk_mdivclk = {
-       .name           = "mdivclk",
-       .parent         = &clk_xtal,
-};
-
-static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_usysclk)
-               clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
-       else if (parent == &clk_h)
-               clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       int div;
-
-       if (rate > parent_rate)
-               return parent_rate;
-
-       div = parent_rate / rate;
-       if (div > 2)
-               div = 2;
-
-       return parent_rate / div;
-}
-
-static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
-}
-
-static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_usbsrc(clk, rate);
-
-       if ((parent_rate / rate) == 2)
-               clkdivn |= S3C2412_CLKDIVN_USB48DIV;
-       else
-               clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_usbsrc = {
-       .name           = "usbsrc",
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_usbsrc,
-               .set_rate       = s3c2412_setrate_usbsrc,
-               .round_rate     = s3c2412_roundrate_usbsrc,
-               .set_parent     = s3c2412_setparent_usbsrc,
-       },
-};
-
-static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_mdivclk)
-               clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
-       else if (parent == &clk_mpll)
-               clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static struct clk clk_msysclk = {
-       .name           = "msysclk",
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2412_setparent_msysclk,
-       },
-};
-
-static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long flags;
-       unsigned long clkdiv;
-       unsigned long dvs;
-
-       /* Note, we current equate fclk andf msysclk for S3C2412 */
-
-       if (parent == &clk_msysclk || parent == &clk_f)
-               dvs = 0;
-       else if (parent == &clk_h)
-               dvs = S3C2412_CLKDIVN_DVSEN;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       /* update this under irq lockdown, clkdivn is not protected
-        * by the clock system. */
-
-       local_irq_save(flags);
-
-       clkdiv  = __raw_readl(S3C2410_CLKDIVN);
-       clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
-       clkdiv |= dvs;
-       __raw_writel(clkdiv, S3C2410_CLKDIVN);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-static struct clk clk_armclk = {
-       .name           = "armclk",
-       .parent         = &clk_msysclk,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2412_setparent_armclk,
-       },
-};
-
-/* these next clocks have an divider immediately after them,
- * so we can register them with their divider and leave out the
- * intermediate clock stage
-*/
-static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       int div;
-
-       if (rate > parent_rate)
-               return parent_rate;
-
-       /* note, we remove the +/- 1 calculations as they cancel out */
-
-       div = (rate / parent_rate);
-
-       if (div < 1)
-               div = 1;
-       else if (div > 16)
-               div = 16;
-
-       return parent_rate / div;
-}
-
-static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_erefclk)
-               clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
-       else if (parent == &clk_mpll)
-               clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static unsigned long s3c2412_getrate_uart(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       div &= S3C2412_CLKDIVN_UARTDIV_MASK;
-       div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
-
-       return parent_rate / (div + 1);
-}
-
-static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_clksrc(clk, rate);
-
-       clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
-       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_uart = {
-       .name           = "uartclk",
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_uart,
-               .set_rate       = s3c2412_setrate_uart,
-               .set_parent     = s3c2412_setparent_uart,
-               .round_rate     = s3c2412_roundrate_clksrc,
-       },
-};
-
-static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_erefclk)
-               clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
-       else if (parent == &clk_mpll)
-               clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static unsigned long s3c2412_getrate_i2s(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       div &= S3C2412_CLKDIVN_I2SDIV_MASK;
-       div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
-
-       return parent_rate / (div + 1);
-}
-
-static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_clksrc(clk, rate);
-
-       clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
-       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_i2s = {
-       .name           = "i2sclk",
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_i2s,
-               .set_rate       = s3c2412_setrate_i2s,
-               .set_parent     = s3c2412_setparent_i2s,
-               .round_rate     = s3c2412_roundrate_clksrc,
-       },
-};
-
-static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_usysclk)
-               clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
-       else if (parent == &clk_h)
-               clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-static unsigned long s3c2412_getrate_cam(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       div &= S3C2412_CLKDIVN_CAMDIV_MASK;
-       div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
-
-       return parent_rate / (div + 1);
-}
-
-static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_clksrc(clk, rate);
-
-       clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
-       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_cam = {
-       .name           = "camif-upll", /* same as 2440 name */
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_cam,
-               .set_rate       = s3c2412_setrate_cam,
-               .set_parent     = s3c2412_setparent_cam,
-               .round_rate     = s3c2412_roundrate_clksrc,
-       },
-};
-
-/* standard clock definitions */
-
-static struct clk init_clocks_disable[] = {
-       {
-               .name           = "nand",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_NAND,
-       }, {
-               .name           = "sdi",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_SDI,
-       }, {
-               .name           = "adc",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_ADC,
-       }, {
-               .name           = "i2c",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_IIC,
-       }, {
-               .name           = "iis",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_IIS,
-       }, {
-               .name           = "spi",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_SPI,
-       }
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "dma.0",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA0,
-       }, {
-               .name           = "dma.1",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA1,
-       }, {
-               .name           = "dma.2",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA2,
-       }, {
-               .name           = "dma.3",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA3,
-       }, {
-               .name           = "lcd",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_LCDC,
-       }, {
-               .name           = "gpio",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_GPIO,
-       }, {
-               .name           = "usb-host",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USBH,
-       }, {
-               .name           = "usb-device",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USBD,
-       }, {
-               .name           = "timers",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_PWMT,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2412-uart.0",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_UART0,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2412-uart.1",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_UART1,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2412-uart.2",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_UART2,
-       }, {
-               .name           = "rtc",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_RTC,
-       }, {
-               .name           = "watchdog",
-               .parent         = &clk_p,
-               .ctrlbit        = 0,
-       }, {
-               .name           = "usb-bus-gadget",
-               .parent         = &clk_usb_bus,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USB_DEV48,
-       }, {
-               .name           = "usb-bus-host",
-               .parent         = &clk_usb_bus,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USB_HOST48,
-       }
-};
-
-/* clocks to add where we need to check their parentage */
-
-struct clk_init {
-       struct clk      *clk;
-       unsigned int     bit;
-       struct clk      *src_0;
-       struct clk      *src_1;
-};
-
-static struct clk_init clks_src[] __initdata = {
-       {
-               .clk    = &clk_usysclk,
-               .bit    = S3C2412_CLKSRC_USBCLK_HCLK,
-               .src_0  = &clk_urefclk,
-               .src_1  = &clk_upll,
-       }, {
-               .clk    = &clk_i2s,
-               .bit    = S3C2412_CLKSRC_I2SCLK_MPLL,
-               .src_0  = &clk_erefclk,
-               .src_1  = &clk_mpll,
-       }, {
-               .clk    = &clk_cam,
-               .bit    = S3C2412_CLKSRC_CAMCLK_HCLK,
-               .src_0  = &clk_usysclk,
-               .src_1  = &clk_h,
-       }, {
-               .clk    = &clk_msysclk,
-               .bit    = S3C2412_CLKSRC_MSYSCLK_MPLL,
-               .src_0  = &clk_mdivclk,
-               .src_1  = &clk_mpll,
-       }, {
-               .clk    = &clk_uart,
-               .bit    = S3C2412_CLKSRC_UARTCLK_MPLL,
-               .src_0  = &clk_erefclk,
-               .src_1  = &clk_mpll,
-       }, {
-               .clk    = &clk_usbsrc,
-               .bit    = S3C2412_CLKSRC_USBCLK_HCLK,
-               .src_0  = &clk_usysclk,
-               .src_1  = &clk_h,
-       /* here we assume  OM[4] select xtal */
-       }, {
-               .clk    = &clk_erefclk,
-               .bit    = S3C2412_CLKSRC_EREFCLK_EXTCLK,
-               .src_0  = &clk_xtal,
-               .src_1  = &clk_ext,
-       }, {
-               .clk    = &clk_urefclk,
-               .bit    = S3C2412_CLKSRC_UREFCLK_EXTCLK,
-               .src_0  = &clk_xtal,
-               .src_1  = &clk_ext,
-       },
-};
-
-/* s3c2412_clk_initparents
- *
- * Initialise the parents for the clocks that we get at start-time
-*/
-
-static void __init s3c2412_clk_initparents(void)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-       struct clk_init *cip = clks_src;
-       struct clk *src;
-       int ptr;
-       int ret;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
-               ret = s3c24xx_register_clock(cip->clk);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              cip->clk->name, ret);
-               }
-
-               src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
-
-               printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
-               clk_set_parent(cip->clk, src);
-       }
-}
-
-/* clocks to add straight away */
-
-static struct clk *clks[] __initdata = {
-       &clk_ext,
-       &clk_usb_bus,
-       &clk_mrefclk,
-       &clk_armclk,
-};
-
-static struct clk_lookup s3c2412_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
-       CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_usysclk),
-};
-
-int __init s3c2412_baseclk_add(void)
-{
-       unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
-       unsigned int dvs;
-       struct clk *clkp;
-       int ret;
-       int ptr;
-
-       clk_upll.enable = s3c2412_upll_enable;
-       clk_usb_bus.parent = &clk_usbsrc;
-       clk_usb_bus.rate = 0x0;
-
-       clk_f.parent = &clk_msysclk;
-
-       s3c2412_clk_initparents();
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
-               clkp = clks[ptr];
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
-
-       /* set the dvs state according to what we got at boot time */
-
-       dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
-
-       if (dvs)
-               clk_armclk.parent = &clk_h;
-
-       printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
-
-       /* ensure usb bus clock is within correct rate of 48MHz */
-
-       if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
-               printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
-
-               /* for the moment, let's use the UPLL, and see if we can
-                * get 48MHz */
-
-               clk_set_parent(&clk_usysclk, &clk_upll);
-               clk_set_parent(&clk_usbsrc, &clk_usysclk);
-               clk_set_rate(&clk_usbsrc, 48*1000*1000);
-       }
-
-       printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
-              (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
-              print_mhz(clk_get_rate(&clk_upll)),
-              print_mhz(clk_get_rate(&clk_usb_bus)));
-
-       /* register clocks from clock array */
-
-       clkp = init_clocks;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
-               /* ensure that we note the clock state */
-
-               clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
-
-       /* We must be careful disabling the clocks we are not intending to
-        * be using at boot time, as subsystems such as the LCD which do
-        * their own DMA requests to the bus can cause the system to lockup
-        * if they where in the middle of requesting bus access.
-        *
-        * Disabling the LCD clock if the LCD is active is very dangerous,
-        * and therefore the bootloader should be careful to not enable
-        * the LCD clock if it is not needed.
-       */
-
-       /* install (and disable) the clocks we do not need immediately */
-
-       clkp = init_clocks_disable;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-
-               s3c2412_clkcon_enable(clkp, 0);
-       }
-
-       clkdev_add_table(s3c2412_clk_lookup, ARRAY_SIZE(s3c2412_clk_lookup));
-       return 0;
-}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c
deleted file mode 100644 (file)
index d421a72..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/clock.c
- *
- * Copyright (c) 2010 Simtec Electronics
- * Copyright (c) 2010 Ben Dooks <ben-linux@fluff.org>
- *
- * S3C2416 Clock control support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/clk.h>
-
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/pll.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/regs-clock.h>
-#include <mach/regs-s3c2443-clock.h>
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[8] = {
-       [0] = 1,
-       [1] = 2,
-       [2] = 3,
-       [3] = 4,
-       [5] = 6,
-       [7] = 8,
-};
-
-static struct clksrc_clk hsspi_eplldiv = {
-       .clk = {
-               .name   = "hsspi-eplldiv",
-               .parent = &clk_esysclk.clk,
-               .ctrlbit = (1 << 14),
-               .enable = s3c2443_clkcon_enable_s,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 },
-};
-
-static struct clk *hsspi_sources[] = {
-       [0] = &hsspi_eplldiv.clk,
-       [1] = NULL, /* to fix */
-};
-
-static struct clksrc_clk hsspi_mux = {
-       .clk    = {
-               .name   = "hsspi-if",
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = hsspi_sources,
-               .nr_sources = ARRAY_SIZE(hsspi_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 },
-};
-
-static struct clksrc_clk hsmmc_div[] = {
-       [0] = {
-               .clk = {
-                       .name   = "hsmmc-div",
-                       .devname        = "s3c-sdhci.0",
-                       .parent = &clk_esysclk.clk,
-               },
-               .reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
-       },
-       [1] = {
-               .clk = {
-                       .name   = "hsmmc-div",
-                       .devname        = "s3c-sdhci.1",
-                       .parent = &clk_esysclk.clk,
-               },
-               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-       },
-};
-
-static struct clksrc_clk hsmmc_mux0 = {
-       .clk    = {
-               .name           = "hsmmc-if",
-               .devname        = "s3c-sdhci.0",
-               .ctrlbit        = (1 << 6),
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .sources        = &(struct clksrc_sources) {
-               .nr_sources     = 2,
-               .sources        = (struct clk * []) {
-                       [0]     = &hsmmc_div[0].clk,
-                       [1]     = NULL, /* to fix */
-               },
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
-};
-
-static struct clksrc_clk hsmmc_mux1 = {
-       .clk    = {
-               .name           = "hsmmc-if",
-               .devname        = "s3c-sdhci.1",
-               .ctrlbit        = (1 << 12),
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .sources        = &(struct clksrc_sources) {
-               .nr_sources     = 2,
-               .sources        = (struct clk * []) {
-                       [0]     = &hsmmc_div[1].clk,
-                       [1]     = NULL, /* to fix */
-               },
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
-};
-
-static struct clk hsmmc0_clk = {
-       .name           = "hsmmc",
-       .devname        = "s3c-sdhci.0",
-       .parent         = &clk_h,
-       .enable         = s3c2443_clkcon_enable_h,
-       .ctrlbit        = S3C2416_HCLKCON_HSMMC0,
-};
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-       &hsspi_eplldiv,
-       &hsspi_mux,
-       &hsmmc_div[0],
-       &hsmmc_div[1],
-       &hsmmc_mux0,
-       &hsmmc_mux1,
-};
-
-static struct clk_lookup s3c2416_clk_lookup[] = {
-       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
-       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
-       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
-       /* s3c2443-spi.0 is used on s3c2416 and s3c2450 as well */
-       CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &hsspi_mux.clk),
-};
-
-void __init s3c2416_init_clocks(int xtal)
-{
-       u32 epllcon = __raw_readl(S3C2443_EPLLCON);
-       u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4);
-       int ptr;
-
-       /* s3c2416 EPLL compatible with s3c64xx */
-       clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1);
-
-       clk_epll.parent = &clk_epllref.clk;
-
-       s3c2443_common_init_clocks(xtal, s3c2416_get_pll,
-                                  armdiv, ARRAY_SIZE(armdiv),
-                                  S3C2416_CLKDIV0_ARMDIV_MASK);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_register_clksrc(clksrcs[ptr], 1);
-
-       s3c24xx_register_clock(&hsmmc0_clk);
-       clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
-
-}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c
deleted file mode 100644 (file)
index 76cd31f..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/clock.c
- *
- * Copyright (c) 2007, 2010 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 Clock control support
- *
- * This program is free software; 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/init.h>
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/cpu-freq.h>
-
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-/* We currently have to assume that the system is running
- * from the XTPll input, and that all ***REFCLKs are being
- * fed from it, as we cannot read the state of OM[4] from
- * software.
- *
- * It would be possible for each board initialisation to
- * set the correct muxing at initialisation
-*/
-
-/* clock selections */
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[16] = {
-       [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 1,
-       [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 2,
-       [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 3,
-       [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 4,
-       [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 6,
-       [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 8,
-       [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 12,
-       [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 16,
-};
-
-/* hsspi
- *
- * high-speed spi clock, sourced from esysclk
-*/
-
-static struct clksrc_clk clk_hsspi = {
-       .clk    = {
-               .name           = "hsspi-if",
-               .parent         = &clk_esysclk.clk,
-               .ctrlbit        = S3C2443_SCLKCON_HSSPICLK,
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
-};
-
-
-/* clk_hsmcc_div
- *
- * this clock is sourced from epll, and is fed through a divider,
- * to a mux controlled by sclkcon where either it or a extclk can
- * be fed to the hsmmc block
-*/
-
-static struct clksrc_clk clk_hsmmc_div = {
-       .clk    = {
-               .name           = "hsmmc-div",
-               .devname        = "s3c-sdhci.1",
-               .parent         = &clk_esysclk.clk,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-};
-
-static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
-
-       clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
-                   S3C2443_SCLKCON_HSMMCCLK_EPLL);
-
-       if (parent == &clk_epll)
-               clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
-       else if (parent == &clk_ext)
-               clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
-       else
-               return -EINVAL;
-
-       if (clk->usage > 0) {
-               __raw_writel(clksrc, S3C2443_SCLKCON);
-       }
-
-       clk->parent = parent;
-       return 0;
-}
-
-static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
-{
-       return s3c2443_setparent_hsmmc(clk, clk->parent);
-}
-
-static struct clk clk_hsmmc = {
-       .name           = "hsmmc-if",
-       .devname        = "s3c-sdhci.1",
-       .parent         = &clk_hsmmc_div.clk,
-       .enable         = s3c2443_enable_hsmmc,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2443_setparent_hsmmc,
-       },
-};
-
-/* standard clock definitions */
-
-static struct clk init_clocks_off[] = {
-       {
-               .name           = "sdi",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_SDI,
-       }, {
-               .name           = "spi",
-               .devname        = "s3c2410-spi.0",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_SPI1,
-       }
-};
-
-/* clocks to add straight away */
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-       &clk_hsspi,
-       &clk_hsmmc_div,
-};
-
-static struct clk *clks[] __initdata = {
-       &clk_hsmmc,
-};
-
-static struct clk_lookup s3c2443_clk_lookup[] = {
-       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_hsmmc),
-       CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &clk_hsspi.clk),
-};
-
-void __init s3c2443_init_clocks(int xtal)
-{
-       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
-       int ptr;
-
-       clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
-       clk_epll.parent = &clk_epllref.clk;
-
-       s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
-                                  armdiv, ARRAY_SIZE(armdiv),
-                                  S3C2443_CLKDIV0_ARMDIV_MASK);
-
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_register_clksrc(clksrcs[ptr], 1);
-
-       /* We must be careful disabling the clocks we are not intending to
-        * be using at boot time, as subsystems such as the LCD which do
-        * their own DMA requests to the bus can cause the system to lockup
-        * if they where in the middle of requesting bus access.
-        *
-        * Disabling the LCD clock if the LCD is active is very dangerous,
-        * and therefore the bootloader should be careful to not enable
-        * the LCD clock if it is not needed.
-       */
-
-       /* install (and disable) the clocks we do not need immediately */
-
-       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
-}
diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c
deleted file mode 100644 (file)
index 65d3eef..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * Common code for SoCs starting with the S3C2443
- *
- * Copyright (c) 2007, 2010 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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/init.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-
-
-static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
-{
-       u32 ctrlbit = clk->ctrlbit;
-       u32 con = __raw_readl(reg);
-
-       if (enable)
-               con |= ctrlbit;
-       else
-               con &= ~ctrlbit;
-
-       __raw_writel(con, reg);
-       return 0;
-}
-
-int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
-{
-       return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
-}
-
-int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
-{
-       return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
-}
-
-int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
-{
-       return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
-}
-
-/* mpllref is a direct descendant of clk_xtal by default, but it is not
- * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
- * such directly equating the two source clocks is impossible.
- */
-static struct clk clk_mpllref = {
-       .name           = "mpllref",
-       .parent         = &clk_xtal,
-};
-
-static struct clk *clk_epllref_sources[] = {
-       [0] = &clk_mpllref,
-       [1] = &clk_mpllref,
-       [2] = &clk_xtal,
-       [3] = &clk_ext,
-};
-
-struct clksrc_clk clk_epllref = {
-       .clk    = {
-               .name           = "epllref",
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_epllref_sources,
-               .nr_sources = ARRAY_SIZE(clk_epllref_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
-};
-
-/* esysclk
- *
- * this is sourced from either the EPLL or the EPLLref clock
-*/
-
-static struct clk *clk_sysclk_sources[] = {
-       [0] = &clk_epllref.clk,
-       [1] = &clk_epll,
-};
-
-struct clksrc_clk clk_esysclk = {
-       .clk    = {
-               .name           = "esysclk",
-               .parent         = &clk_epll,
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_sysclk_sources,
-               .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
-};
-
-static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2443_CLKDIV0);
-
-       div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
-       div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);       /* x2 */
-
-       return parent_rate / (div + 1);
-}
-
-static struct clk clk_mdivclk = {
-       .name           = "mdivclk",
-       .parent         = &clk_mpllref,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2443_getrate_mdivclk,
-       },
-};
-
-static struct clk *clk_msysclk_sources[] = {
-       [0] = &clk_mpllref,
-       [1] = &clk_mpll,
-       [2] = &clk_mdivclk,
-       [3] = &clk_mpllref,
-};
-
-static struct clksrc_clk clk_msysclk = {
-       .clk    = {
-               .name           = "msysclk",
-               .parent         = &clk_xtal,
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_msysclk_sources,
-               .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
-};
-
-/* prediv
- *
- * this divides the msysclk down to pass to h/p/etc.
- */
-
-static unsigned long s3c2443_prediv_getrate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-
-       clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
-       clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
-
-       return rate / (clkdiv0 + 1);
-}
-
-static struct clk clk_prediv = {
-       .name           = "prediv",
-       .parent         = &clk_msysclk.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2443_prediv_getrate,
-       },
-};
-
-/* hclk divider
- *
- * divides the prediv and provides the hclk.
- */
-
-static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-
-       clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
-
-       return rate / (clkdiv0 + 1);
-}
-
-static struct clk_ops clk_h_ops = {
-       .get_rate       = s3c2443_hclkdiv_getrate,
-};
-
-/* pclk divider
- *
- * divides the hclk and provides the pclk.
- */
-
-static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-
-       clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0);
-
-       return rate / (clkdiv0 + 1);
-}
-
-static struct clk_ops clk_p_ops = {
-       .get_rate       = s3c2443_pclkdiv_getrate,
-};
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
-*/
-
-static unsigned int *armdiv;
-static int nr_armdiv;
-static int armdivmask;
-
-static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent = clk_get_rate(clk->parent);
-       unsigned long calc;
-       unsigned best = 256; /* bigger than any value */
-       unsigned div;
-       int ptr;
-
-       if (!nr_armdiv)
-               return -EINVAL;
-
-       for (ptr = 0; ptr < nr_armdiv; ptr++) {
-               div = armdiv[ptr];
-               if (div) {
-                       /* cpufreq provides 266mhz as 266666000 not 266666666 */
-                       calc = (parent / div / 1000) * 1000;
-                       if (calc <= rate && div < best)
-                               best = div;
-               }
-       }
-
-       return parent / best;
-}
-
-static unsigned long s3c2443_armclk_getrate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkcon0;
-       int val;
-
-       if (!nr_armdiv || !armdivmask)
-               return -EINVAL;
-
-       clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-       clkcon0 &= armdivmask;
-       val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
-
-       return rate / armdiv[val];
-}
-
-static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent = clk_get_rate(clk->parent);
-       unsigned long calc;
-       unsigned div;
-       unsigned best = 256; /* bigger than any value */
-       int ptr;
-       int val = -1;
-
-       if (!nr_armdiv || !armdivmask)
-               return -EINVAL;
-
-       for (ptr = 0; ptr < nr_armdiv; ptr++) {
-               div = armdiv[ptr];
-               if (div) {
-                       /* cpufreq provides 266mhz as 266666000 not 266666666 */
-                       calc = (parent / div / 1000) * 1000;
-                       if (calc <= rate && div < best) {
-                               best = div;
-                               val = ptr;
-                       }
-               }
-       }
-
-       if (val >= 0) {
-               unsigned long clkcon0;
-
-               clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-               clkcon0 &= ~armdivmask;
-               clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
-               __raw_writel(clkcon0, S3C2443_CLKDIV0);
-       }
-
-       return (val == -1) ? -EINVAL : 0;
-}
-
-static struct clk clk_armdiv = {
-       .name           = "armdiv",
-       .parent         = &clk_msysclk.clk,
-       .ops            = &(struct clk_ops) {
-               .round_rate = s3c2443_armclk_roundrate,
-               .get_rate = s3c2443_armclk_getrate,
-               .set_rate = s3c2443_armclk_setrate,
-       },
-};
-
-/* armclk
- *
- * this is the clock fed into the ARM core itself, from armdiv or from hclk.
- */
-
-static struct clk *clk_arm_sources[] = {
-       [0] = &clk_armdiv,
-       [1] = &clk_h,
-};
-
-static struct clksrc_clk clk_arm = {
-       .clk    = {
-               .name           = "armclk",
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_arm_sources,
-               .nr_sources = ARRAY_SIZE(clk_arm_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
-};
-
-/* usbhost
- *
- * usb host bus-clock, usually 48MHz to provide USB bus clock timing
-*/
-
-static struct clksrc_clk clk_usb_bus_host = {
-       .clk    = {
-               .name           = "usb-bus-host-parent",
-               .parent         = &clk_esysclk.clk,
-               .ctrlbit        = S3C2443_SCLKCON_USBHOST,
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
-};
-
-/* common clksrc clocks */
-
-static struct clksrc_clk clksrc_clks[] = {
-       {
-               /* camera interface bus-clock, divided down from esysclk */
-               .clk    = {
-                       .name           = "camif-upll", /* same as 2440 name */
-                       .parent         = &clk_esysclk.clk,
-                       .ctrlbit        = S3C2443_SCLKCON_CAMCLK,
-                       .enable         = s3c2443_clkcon_enable_s,
-               },
-               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
-       }, {
-               .clk    = {
-                       .name           = "display-if",
-                       .parent         = &clk_esysclk.clk,
-                       .ctrlbit        = S3C2443_SCLKCON_DISPCLK,
-                       .enable         = s3c2443_clkcon_enable_s,
-               },
-               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
-       },
-};
-
-static struct clksrc_clk clk_esys_uart = {
-       /* ART baud-rate clock sourced from esysclk via a divisor */
-       .clk    = {
-               .name           = "uartclk",
-               .parent         = &clk_esysclk.clk,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
-};
-
-static struct clk clk_i2s_ext = {
-       .name           = "i2s-ext",
-};
-
-/* i2s_eplldiv
- *
- * This clock is the output from the I2S divisor of ESYSCLK, and is separate
- * from the mux that comes after it (cannot merge into one single clock)
-*/
-
-static struct clksrc_clk clk_i2s_eplldiv = {
-       .clk    = {
-               .name           = "i2s-eplldiv",
-               .parent         = &clk_esysclk.clk,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
-};
-
-/* i2s-ref
- *
- * i2s bus reference clock, selectable from external, esysclk or epllref
- *
- * Note, this used to be two clocks, but was compressed into one.
-*/
-
-static struct clk *clk_i2s_srclist[] = {
-       [0] = &clk_i2s_eplldiv.clk,
-       [1] = &clk_i2s_ext,
-       [2] = &clk_epllref.clk,
-       [3] = &clk_epllref.clk,
-};
-
-static struct clksrc_clk clk_i2s = {
-       .clk    = {
-               .name           = "i2s-if",
-               .ctrlbit        = S3C2443_SCLKCON_I2SCLK,
-               .enable         = s3c2443_clkcon_enable_s,
-
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_i2s_srclist,
-               .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
-};
-
-static struct clk init_clocks_off[] = {
-       {
-               .name           = "iis",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_IIS,
-       }, {
-               .name           = "adc",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_ADC,
-       }, {
-               .name           = "i2c",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_IIC,
-       }
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "dma.0",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA0,
-       }, {
-               .name           = "dma.1",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA1,
-       }, {
-               .name           = "dma.2",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA2,
-       }, {
-               .name           = "dma.3",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA3,
-       }, {
-               .name           = "dma.4",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA4,
-       }, {
-               .name           = "dma.5",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA5,
-       }, {
-               .name           = "gpio",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_GPIO,
-       }, {
-               .name           = "usb-host",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_USBH,
-       }, {
-               .name           = "usb-device",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_USBD,
-       }, {
-               .name           = "lcd",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_LCDC,
-
-       }, {
-               .name           = "timers",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_PWMT,
-       }, {
-               .name           = "cfc",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_CFC,
-       }, {
-               .name           = "ssmc",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_SSMC,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.0",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART0,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.1",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART1,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.2",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART2,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.3",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART3,
-       }, {
-               .name           = "rtc",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_RTC,
-       }, {
-               .name           = "watchdog",
-               .parent         = &clk_p,
-               .ctrlbit        = S3C2443_PCLKCON_WDT,
-       }, {
-               .name           = "ac97",
-               .parent         = &clk_p,
-               .ctrlbit        = S3C2443_PCLKCON_AC97,
-       }, {
-               .name           = "nand",
-               .parent         = &clk_h,
-       }, {
-               .name           = "usb-bus-host",
-               .parent         = &clk_usb_bus_host.clk,
-       }
-};
-
-static struct clk hsmmc1_clk = {
-       .name           = "hsmmc",
-       .devname        = "s3c-sdhci.1",
-       .parent         = &clk_h,
-       .enable         = s3c2443_clkcon_enable_h,
-       .ctrlbit        = S3C2443_HCLKCON_HSMMC,
-};
-
-static struct clk hsspi_clk = {
-       .name           = "spi",
-       .devname        = "s3c2443-spi.0",
-       .parent         = &clk_p,
-       .enable         = s3c2443_clkcon_enable_p,
-       .ctrlbit        = S3C2443_PCLKCON_HSSPI,
-};
-
-/* EPLLCON compatible enough to get on/off information */
-
-void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll)
-{
-       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
-       unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
-       struct clk *xtal_clk;
-       unsigned long xtal;
-       unsigned long pll;
-       int ptr;
-
-       xtal_clk = clk_get(NULL, "xtal");
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       pll = get_mpll(mpllcon, xtal);
-       clk_msysclk.clk.rate = pll;
-       clk_mpll.rate = pll;
-
-       printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
-              (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on",
-              print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)),
-              print_mhz(clk_get_rate(&clk_h)),
-              print_mhz(clk_get_rate(&clk_p)));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
-               s3c_set_clksrc(&clksrc_clks[ptr], true);
-
-       /* ensure usb bus clock is within correct rate of 48MHz */
-
-       if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
-               printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
-               clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
-       }
-
-       printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
-              (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on",
-              print_mhz(clk_get_rate(&clk_epll)),
-              print_mhz(clk_get_rate(&clk_usb_bus)));
-}
-
-static struct clk *clks[] __initdata = {
-       &clk_prediv,
-       &clk_mpllref,
-       &clk_mdivclk,
-       &clk_ext,
-       &clk_epll,
-       &clk_usb_bus,
-       &clk_armdiv,
-       &hsmmc1_clk,
-       &hsspi_clk,
-};
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-       &clk_i2s_eplldiv,
-       &clk_i2s,
-       &clk_usb_bus_host,
-       &clk_epllref,
-       &clk_esysclk,
-       &clk_msysclk,
-       &clk_arm,
-};
-
-static struct clk_lookup s3c2443_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
-       CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
-       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
-       CLKDEV_INIT("s3c2443-spi.0", "spi_busclk0", &hsspi_clk),
-};
-
-void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
-                                      unsigned int *divs, int nr_divs,
-                                      int divmask)
-{
-       int ptr;
-
-       armdiv = divs;
-       nr_armdiv = nr_divs;
-       armdivmask = divmask;
-
-       /* s3c2443 parents h clock from prediv */
-       clk_h.parent = &clk_prediv;
-       clk_h.ops = &clk_h_ops;
-
-       /* and p clock from h clock */
-       clk_p.parent = &clk_h;
-       clk_p.ops = &clk_p_ops;
-
-       clk_usb_bus.parent = &clk_usb_bus_host.clk;
-       clk_epll.parent = &clk_epllref.clk;
-
-       s3c24xx_register_baseclocks(xtal);
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_register_clksrc(clksrcs[ptr], 1);
-
-       s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
-       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-       /* See s3c2443/etc notes on disabling clocks at init time */
-       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
-
-       s3c2443_common_setup_clocks(get_mpll);
-}
index 1bc8e73c94f9864d8d7cdfc715c33582f9718005..ad5b76bf4d51d9fcece4b6013e22f91f431bc07f 100644 (file)
@@ -127,7 +127,6 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idcode         = 0x32412001,
                .idmask         = 0xffffffff,
                .map_io         = s3c2412_map_io,
-               .init_clocks    = s3c2412_init_clocks,
                .init_uarts     = s3c2412_init_uarts,
                .init           = s3c2412_init,
                .name           = name_s3c2412,
@@ -136,7 +135,6 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idcode         = 0x32412003,
                .idmask         = 0xffffffff,
                .map_io         = s3c2412_map_io,
-               .init_clocks    = s3c2412_init_clocks,
                .init_uarts     = s3c2412_init_uarts,
                .init           = s3c2412_init,
                .name           = name_s3c2412,
@@ -145,7 +143,6 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idcode         = 0x32450003,
                .idmask         = 0xffffffff,
                .map_io         = s3c2416_map_io,
-               .init_clocks    = s3c2416_init_clocks,
                .init_uarts     = s3c2416_init_uarts,
                .init           = s3c2416_init,
                .name           = name_s3c2416,
@@ -154,7 +151,6 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idcode         = 0x32443001,
                .idmask         = 0xffffffff,
                .map_io         = s3c2443_map_io,
-               .init_clocks    = s3c2443_init_clocks,
                .init_uarts     = s3c2443_init_uarts,
                .init           = s3c2443_init,
                .name           = name_s3c2443,
@@ -318,6 +314,7 @@ struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {
 
 /* initialise all the clocks */
 
+#ifdef CONFIG_SAMSUNG_CLOCK
 void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
                                           unsigned long hclk,
                                           unsigned long pclk)
@@ -330,6 +327,7 @@ void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
        clk_p.rate = pclk;
        clk_f.rate = fclk;
 }
+#endif
 
 #if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \
        defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
@@ -534,3 +532,24 @@ struct platform_device s3c2443_device_dma = {
        },
 };
 #endif
+
+#ifdef CONFIG_CPU_S3C2412
+void __init s3c2412_init_clocks(int xtal)
+{
+       s3c2412_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR);
+}
+#endif
+
+#ifdef CONFIG_CPU_S3C2416
+void __init s3c2416_init_clocks(int xtal)
+{
+       s3c2443_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR);
+}
+#endif
+
+#ifdef CONFIG_CPU_S3C2443
+void __init s3c2443_init_clocks(int xtal)
+{
+       s3c2443_common_clk_init(NULL, xtal, 1, S3C24XX_VA_CLKPWR);
+}
+#endif
index e46c1041721669e3503555cadff0c6bbbcaaf3df..3fade6d796f96916571bf441e540e63f31b2ad72 100644 (file)
@@ -114,4 +114,14 @@ extern struct platform_device s3c2412_device_dma;
 extern struct platform_device s3c2440_device_dma;
 extern struct platform_device s3c2443_device_dma;
 
+#ifdef CONFIG_S3C2412_COMMON_CLK
+void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
+                               unsigned long ext_f, void __iomem *reg_base);
+#endif
+#ifdef CONFIG_S3C2443_COMMON_CLK
+void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
+                                   int current_soc,
+                                   void __iomem *reg_base);
+#endif
+
 #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
index 5faa7239e7d6d9ba0e02309ae9783215ad13941e..e81ea82c55f9de9269a680e4d84f7cb710648963 100644 (file)
@@ -507,11 +507,16 @@ static struct syscore_ops jive_pm_syscore_ops = {
 static void __init jive_map_io(void)
 {
        s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc));
-       s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(jive_uartcfgs, ARRAY_SIZE(jive_uartcfgs));
        samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 }
 
+static void __init jive_init_time(void)
+{
+       s3c2412_init_clocks(12000000);
+       samsung_timer_init();
+}
+
 static void jive_power_off(void)
 {
        printk(KERN_INFO "powering system down...\n");
@@ -665,6 +670,6 @@ MACHINE_START(JIVE, "JIVE")
        .init_irq       = s3c2412_init_irq,
        .map_io         = jive_map_io,
        .init_machine   = jive_machine_init,
-       .init_time      = samsung_timer_init,
+       .init_time      = jive_init_time,
        .restart        = s3c2412_restart,
 MACHINE_END
index 70f0900d4bcac263d04085933b996be9b3ec75e9..e4dcb9aa2ca29e508e179362ff2a2aebf67d7fdb 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/clocksource.h>
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
-#include <linux/serial_core.h>
 #include <linux/serial_s3c.h>
 
 #include <asm/mach/arch.h>
 
 #include "common.h"
 
-/*
- * The following lookup table is used to override device names when devices
- * are registered from device tree. This is temporarily added to enable
- * device tree support addition for the S3C2416 architecture.
- *
- * For drivers that require platform data to be provided from the machine
- * file, a platform data pointer can also be supplied along with the
- * devices names. Usually, the platform data elements that cannot be parsed
- * from the device tree by the drivers (example: function pointers) are
- * supplied. But it should be noted that this is a temporary mechanism and
- * at some point, the drivers should be capable of parsing all the platform
- * data from the device tree.
- */
-static const struct of_dev_auxdata s3c2416_auxdata_lookup[] __initconst = {
-       OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART,
-                               "s3c2440-uart.0", NULL),
-       OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART + 0x4000,
-                               "s3c2440-uart.1", NULL),
-       OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART + 0x8000,
-                               "s3c2440-uart.2", NULL),
-       OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART + 0xC000,
-                               "s3c2440-uart.3", NULL),
-       OF_DEV_AUXDATA("samsung,s3c6410-sdhci", S3C_PA_HSMMC0,
-                               "s3c-sdhci.0", NULL),
-       OF_DEV_AUXDATA("samsung,s3c6410-sdhci", S3C_PA_HSMMC1,
-                               "s3c-sdhci.1", NULL),
-       OF_DEV_AUXDATA("samsung,s3c2440-i2c", S3C_PA_IIC,
-                               "s3c2440-i2c.0", NULL),
-       {},
-};
-
 static void __init s3c2416_dt_map_io(void)
 {
        s3c24xx_init_io(NULL, 0);
-       s3c24xx_init_clocks(12000000);
 }
 
 static void __init s3c2416_dt_machine_init(void)
 {
-       of_platform_populate(NULL, of_default_bus_match_table,
-                               s3c2416_auxdata_lookup, NULL);
-
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
        s3c_pm_init();
 }
 
@@ -86,6 +51,5 @@ DT_MACHINE_START(S3C2416_DT, "Samsung S3C2416 (Flattened Device Tree)")
        .map_io         = s3c2416_dt_map_io,
        .init_irq       = irqchip_init,
        .init_machine   = s3c2416_dt_machine_init,
-        .init_time     = clocksource_of_init,
        .restart        = s3c2416_restart,
 MACHINE_END
index 233fe52d2015a549c3b6ef507de4019664306f32..a38f8a049e2268dcd109b9ea6432a885f856609f 100644 (file)
@@ -106,11 +106,16 @@ static void __init smdk2413_fixup(struct tag *tags, char **cmdline,
 static void __init smdk2413_map_io(void)
 {
        s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
-       s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
        samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 }
 
+static void __init smdk2413_init_time(void)
+{
+       s3c2412_init_clocks(12000000);
+       samsung_timer_init();
+}
+
 static void __init smdk2413_machine_init(void)
 {      /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
@@ -159,6 +164,6 @@ MACHINE_START(SMDK2413, "SMDK2413")
        .init_irq       = s3c2412_init_irq,
        .map_io         = smdk2413_map_io,
        .init_machine   = smdk2413_machine_init,
-       .init_time      = samsung_timer_init,
+       .init_time      = smdk2413_init_time,
        .restart        = s3c2412_restart,
 MACHINE_END
index b3b54d8e1410dc81a7f8c2c80723e6466f3d49e8..fa6f30d23601d24c46e4ca2925ce6e0f1c135db2 100644 (file)
@@ -219,10 +219,15 @@ static struct platform_device *smdk2416_devices[] __initdata = {
        &s3c2443_device_dma,
 };
 
+static void __init smdk2416_init_time(void)
+{
+       s3c2416_init_clocks(12000000);
+       samsung_timer_init();
+}
+
 static void __init smdk2416_map_io(void)
 {
        s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc));
-       s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs));
        samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 }
@@ -257,6 +262,6 @@ MACHINE_START(SMDK2416, "SMDK2416")
        .init_irq       = s3c2416_init_irq,
        .map_io         = smdk2416_map_io,
        .init_machine   = smdk2416_machine_init,
-       .init_time      = samsung_timer_init,
+       .init_time      = smdk2416_init_time,
        .restart        = s3c2416_restart,
 MACHINE_END
index 06c4d77de3a5572513558552675505c663107abf..ef5d5ea33182f797679406baa79d8a8cfe704e15 100644 (file)
@@ -121,11 +121,16 @@ static struct platform_device *smdk2443_devices[] __initdata = {
 static void __init smdk2443_map_io(void)
 {
        s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc));
-       s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs));
        samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 }
 
+static void __init smdk2443_init_time(void)
+{
+       s3c2443_init_clocks(12000000);
+       samsung_timer_init();
+}
+
 static void __init smdk2443_machine_init(void)
 {
        s3c_i2c0_set_platdata(NULL);
@@ -145,6 +150,6 @@ MACHINE_START(SMDK2443, "SMDK2443")
        .init_irq       = s3c2443_init_irq,
        .map_io         = smdk2443_map_io,
        .init_machine   = smdk2443_machine_init,
-       .init_time      = samsung_timer_init,
+       .init_time      = smdk2443_init_time,
        .restart        = s3c2443_restart,
 MACHINE_END
index 40868c0e0a683e673904c4c1a69db23448fef75f..6b706c915387b9f7555132ad04365583c3c2edf1 100644 (file)
@@ -142,11 +142,16 @@ static void __init vstms_fixup(struct tag *tags, char **cmdline,
 static void __init vstms_map_io(void)
 {
        s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
-       s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
        samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 }
 
+static void __init vstms_init_time(void)
+{
+       s3c2412_init_clocks(12000000);
+       samsung_timer_init();
+}
+
 static void __init vstms_init(void)
 {
        s3c_i2c0_set_platdata(NULL);
@@ -162,6 +167,6 @@ MACHINE_START(VSTMS, "VSTMS")
        .init_irq       = s3c2412_init_irq,
        .init_machine   = vstms_init,
        .map_io         = vstms_map_io,
-       .init_time      = samsung_timer_init,
+       .init_time      = vstms_init_time,
        .restart        = s3c2412_restart,
 MACHINE_END
index 68ea5b7e5dc7d57df5f06be4e44d5930b0a97ffb..16281bdc750a58e0e6326331e865a7442ae10cb6 100644 (file)
@@ -51,9 +51,6 @@
 #define PFX "s3c24xx-pm: "
 
 static struct sleep_save core_save[] = {
-       SAVE_ITEM(S3C2410_LOCKTIME),
-       SAVE_ITEM(S3C2410_CLKCON),
-
        /* we restore the timings here, with the proviso that the board
         * brings the system up in an slower, or equal frequency setting
         * to the original system.
@@ -70,6 +67,9 @@ static struct sleep_save core_save[] = {
        SAVE_ITEM(S3C2410_BANKCON4),
        SAVE_ITEM(S3C2410_BANKCON5),
 
+#ifdef CONFIG_SAMSUNG_CLOCK
+       SAVE_ITEM(S3C2410_LOCKTIME),
+       SAVE_ITEM(S3C2410_CLKCON),
 #ifndef CONFIG_CPU_FREQ
        SAVE_ITEM(S3C2410_CLKDIVN),
        SAVE_ITEM(S3C2410_MPLLCON),
@@ -77,11 +77,14 @@ static struct sleep_save core_save[] = {
 #endif
        SAVE_ITEM(S3C2410_UPLLCON),
        SAVE_ITEM(S3C2410_CLKSLOW),
+#endif /* CONFIG_SAMSUNG_CLOCK */
 };
 
+#ifdef CONFIG_SAMSUNG_CLOCK
 static struct sleep_save misc_save[] = {
        SAVE_ITEM(S3C2410_DCLKCON),
 };
+#endif
 
 /* s3c_pm_check_resume_pin
  *
@@ -140,12 +143,16 @@ void s3c_pm_configure_extint(void)
 void s3c_pm_restore_core(void)
 {
        s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+#ifdef CONFIG_SAMSUNG_CLOCK
        s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
+#endif
 }
 
 void s3c_pm_save_core(void)
 {
+#ifdef CONFIG_SAMSUNG_CLOCK
        s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
+#endif
        s3c_pm_do_save(core_save, ARRAY_SIZE(core_save));
 }
 
index 657cbaca80ac46cefbfb9c6baa9f7d46432efd43..d49f52fbc842d125082f81196e2b61f6db290b63 100644 (file)
@@ -173,49 +173,6 @@ void __init s3c2412_map_io(void)
 
 void __init_or_cpufreq s3c2412_setup_clocks(void)
 {
-       struct clk *xtal_clk;
-       unsigned long tmp;
-       unsigned long xtal;
-       unsigned long fclk;
-       unsigned long hclk;
-       unsigned long pclk;
-
-       xtal_clk = clk_get(NULL, "xtal");
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       /* now we've got our machine bits initialised, work out what
-        * clocks we've got */
-
-       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
-
-       clk_mpll.rate = fclk;
-
-       tmp = __raw_readl(S3C2410_CLKDIVN);
-
-       /* work out clock scalings */
-
-       hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
-       hclk /= ((tmp & S3C2412_CLKDIVN_ARMDIVN) ? 2 : 1);
-       pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
-
-       /* print brieft summary of clocks, etc */
-
-       printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-       s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-void __init s3c2412_init_clocks(int xtal)
-{
-       /* initialise the clocks here, to allow other things like the
-        * console to use them
-        */
-
-       s3c24xx_register_baseclocks(xtal);
-       s3c2412_setup_clocks();
-       s3c2412_baseclk_add();
 }
 
 /* need to register the subsystem before we actually register the device, and
index 0f92ba8e78841556c683ffaebbae8a8df13347db..037c00622de69f324aaab6f6ac36acbd0ef0f562 100644 (file)
@@ -108,6 +108,7 @@ config ARCH_R8A7778
        select SH_CLK_CPG
        select ARM_GIC
        select SYS_SUPPORTS_SH_TMU
+       select RENESAS_INTC_IRQPIN
 
 config ARCH_R8A7779
        bool "R-Car H1 (R8A77790)"
@@ -140,16 +141,6 @@ config ARCH_R8A7791
        select SYS_SUPPORTS_SH_CMT
        select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
 
-config ARCH_EMEV2
-       bool "Emma Mobile EV2"
-       select ARCH_WANT_OPTIONAL_GPIOLIB
-       select ARM_GIC
-       select CPU_V7
-       select MIGHT_HAVE_PCI
-       select USE_OF
-       select AUTO_ZRELADDR
-       select SYS_SUPPORTS_EM_STI
-
 config ARCH_R7S72100
        bool "RZ/A1H (R7S72100)"
        select ARCH_WANT_OPTIONAL_GPIOLIB
@@ -205,8 +196,8 @@ config MACH_ARMADILLO800EVA_REFERENCE
        select SND_SOC_WM8978 if SND_SIMPLE_CARD
        select USE_OF
        ---help---
-          Use reference implementation of Aramdillo800 EVA board support
-          which makes greater use of device tree at the expense
+          Use reference implementation of Armadillo800 EVA board support
+          which makes greater use of device tree at the expense
           of not supporting a number of devices.
 
           This is intended to aid developers
@@ -216,7 +207,6 @@ config MACH_BOCKW
        depends on ARCH_R8A7778
        select ARCH_REQUIRE_GPIOLIB
        select REGULATOR_FIXED_VOLTAGE if REGULATOR
-       select RENESAS_INTC_IRQPIN
        select SND_SOC_AK4554 if SND_SIMPLE_CARD
        select SND_SOC_AK4642 if SND_SIMPLE_CARD
        select USE_OF
@@ -225,7 +215,6 @@ 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---
index 4caffc912a81ccf442c6929d8f08018faff22fd6..9c5cd8c53a8568326fdc73bf12210252379b655e 100644 (file)
@@ -21,8 +21,8 @@ obj-$(CONFIG_ARCH_EMEV2)      += setup-emev2.o
 obj-$(CONFIG_ARCH_R7S72100)    += setup-r7s72100.o
 
 # Clock objects
-ifndef CONFIG_COMMON_CLK
 obj-y                          += clock.o
+ifndef CONFIG_COMMON_CLK
 obj-$(CONFIG_ARCH_SH7372)      += clock-sh7372.o
 obj-$(CONFIG_ARCH_SH73A0)      += clock-sh73a0.o
 obj-$(CONFIG_ARCH_R8A73A4)     += clock-r8a73a4.o
@@ -31,7 +31,6 @@ obj-$(CONFIG_ARCH_R8A7778)    += clock-r8a7778.o
 obj-$(CONFIG_ARCH_R8A7779)     += clock-r8a7779.o
 obj-$(CONFIG_ARCH_R8A7790)     += clock-r8a7790.o
 obj-$(CONFIG_ARCH_R8A7791)     += clock-r8a7791.o
-obj-$(CONFIG_ARCH_EMEV2)       += clock-emev2.o
 obj-$(CONFIG_ARCH_R7S72100)    += clock-r7s72100.o
 endif
 
index b4122f8cb8d9ff986b62948db81755a6a6ba0248..f444be2f241ed5ca7b1f38a970042272937ba246 100644 (file)
@@ -345,24 +345,39 @@ static struct rsnd_ssi_platform_info rsnd_ssi[] = {
        RSND_SSI_UNUSED, /* SSI 0 */
        RSND_SSI_UNUSED, /* SSI 1 */
        RSND_SSI_UNUSED, /* SSI 2 */
-       RSND_SSI_SET(1, HPBDMA_SLAVE_HPBIF3_TX, gic_iid(0x85), RSND_SSI_PLAY),
-       RSND_SSI_SET(2, HPBDMA_SLAVE_HPBIF4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE),
-       RSND_SSI_SET(0, HPBDMA_SLAVE_HPBIF5_TX, gic_iid(0x86), RSND_SSI_PLAY),
-       RSND_SSI_SET(0, HPBDMA_SLAVE_HPBIF6_RX, gic_iid(0x86), 0),
-       RSND_SSI_SET(3, HPBDMA_SLAVE_HPBIF7_TX, gic_iid(0x86), RSND_SSI_PLAY),
-       RSND_SSI_SET(4, HPBDMA_SLAVE_HPBIF8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE),
+       RSND_SSI(HPBDMA_SLAVE_HPBIF3_TX, gic_iid(0x85), 0),
+       RSND_SSI(HPBDMA_SLAVE_HPBIF4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE),
+       RSND_SSI(HPBDMA_SLAVE_HPBIF5_TX, gic_iid(0x86), 0),
+       RSND_SSI(HPBDMA_SLAVE_HPBIF6_RX, gic_iid(0x86), 0),
+       RSND_SSI(HPBDMA_SLAVE_HPBIF7_TX, gic_iid(0x86), 0),
+       RSND_SSI(HPBDMA_SLAVE_HPBIF8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE),
 };
 
-static struct rsnd_scu_platform_info rsnd_scu[9] = {
-       { .flags = 0, }, /* SRU 0 */
-       { .flags = 0, }, /* SRU 1 */
-       { .flags = 0, }, /* SRU 2 */
-       { .flags = RSND_SCU_USE_HPBIF, },
-       { .flags = RSND_SCU_USE_HPBIF, },
-       { .flags = RSND_SCU_USE_HPBIF, },
-       { .flags = RSND_SCU_USE_HPBIF, },
-       { .flags = RSND_SCU_USE_HPBIF, },
-       { .flags = RSND_SCU_USE_HPBIF, },
+static struct rsnd_src_platform_info rsnd_src[9] = {
+       RSND_SRC_UNUSED, /* SRU 0 */
+       RSND_SRC_UNUSED, /* SRU 1 */
+       RSND_SRC_UNUSED, /* SRU 2 */
+       RSND_SRC(0, 0),
+       RSND_SRC(0, 0),
+       RSND_SRC(0, 0),
+       RSND_SRC(0, 0),
+       RSND_SRC(0, 0),
+       RSND_SRC(0, 0),
+};
+
+static struct rsnd_dai_platform_info rsnd_dai[] = {
+       {
+               .playback = { .ssi = &rsnd_ssi[5], .src = &rsnd_src[5] },
+               .capture  = { .ssi = &rsnd_ssi[6], .src = &rsnd_src[6] },
+       }, {
+               .playback = { .ssi = &rsnd_ssi[3], .src = &rsnd_src[3] },
+       }, {
+               .capture  = { .ssi = &rsnd_ssi[4], .src = &rsnd_src[4] },
+       }, {
+               .playback = { .ssi = &rsnd_ssi[7], .src = &rsnd_src[7] },
+       }, {
+               .capture  = { .ssi = &rsnd_ssi[8], .src = &rsnd_src[8] },
+       },
 };
 
 enum {
@@ -437,8 +452,10 @@ static struct rcar_snd_info rsnd_info = {
        .flags          = RSND_GEN1,
        .ssi_info       = rsnd_ssi,
        .ssi_info_nr    = ARRAY_SIZE(rsnd_ssi),
-       .scu_info       = rsnd_scu,
-       .scu_info_nr    = ARRAY_SIZE(rsnd_scu),
+       .src_info       = rsnd_src,
+       .src_info_nr    = ARRAY_SIZE(rsnd_src),
+       .dai_info       = rsnd_dai,
+       .dai_info_nr    = ARRAY_SIZE(rsnd_dai),
        .start          = rsnd_start,
        .stop           = rsnd_stop,
 };
@@ -591,6 +608,7 @@ static void __init bockw_init(void)
 {
        void __iomem *base;
        struct clk *clk;
+       struct platform_device *pdev;
        int i;
 
        r8a7778_clock_init();
@@ -673,9 +691,6 @@ static void __init bockw_init(void)
        }
 
        /* for Audio */
-       clk = clk_get(NULL, "audio_clk_b");
-       clk_set_rate(clk, 24576000);
-       clk_put(clk);
        rsnd_codec_power(5, 1); /* enable ak4642 */
 
        platform_device_register_simple(
@@ -684,11 +699,15 @@ static void __init bockw_init(void)
        platform_device_register_simple(
                "ak4554-adc-dac", 1, NULL, 0);
 
-       platform_device_register_resndata(
+       pdev = platform_device_register_resndata(
                &platform_bus, "rcar_sound", -1,
                rsnd_resources, ARRAY_SIZE(rsnd_resources),
                &rsnd_info, sizeof(rsnd_info));
 
+       clk = clk_get(&pdev->dev, "clk_b");
+       clk_set_rate(clk, 24576000);
+       clk_put(clk);
+
        for (i = 0; i < ARRAY_SIZE(rsnd_card_info); i++) {
                struct platform_device_info cardinfo = {
                        .parent         = &platform_bus,
index a3fd30242bd87d2a8c77f2c6ade2a3c96259e039..941f8b394e84c2bab3fe71f3162275085ab753af 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/clk.h>
-#include <linux/clkdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/of_platform.h>
 #include <linux/platform_data/rcar-du.h>
+#include <mach/clock.h>
 #include <mach/common.h>
 #include <mach/irqs.h>
 #include <mach/rcar-gen2.h>
@@ -82,49 +81,50 @@ static void __init koelsch_add_du_device(void)
        platform_device_register_full(&info);
 }
 
-static void __init koelsch_add_standard_devices(void)
-{
-       /*
-        * This is a really crude hack to provide clkdev support to the CMT and
-        * DU devices until they get moved to DT.
-        */
-       static const struct clk_name {
-               const char *clk;
-               const char *con_id;
-               const char *dev_id;
-       } clk_names[] = {
-               { "cmt0", NULL, "sh_cmt.0" },
-               { "scifa0", NULL, "sh-sci.0" },
-               { "scifa1", NULL, "sh-sci.1" },
-               { "scifb0", NULL, "sh-sci.2" },
-               { "scifb1", NULL, "sh-sci.3" },
-               { "scifb2", NULL, "sh-sci.4" },
-               { "scifa2", NULL, "sh-sci.5" },
-               { "scif0", NULL, "sh-sci.6" },
-               { "scif1", NULL, "sh-sci.7" },
-               { "scif2", NULL, "sh-sci.8" },
-               { "scif3", NULL, "sh-sci.9" },
-               { "scif4", NULL, "sh-sci.10" },
-               { "scif5", NULL, "sh-sci.11" },
-               { "scifa3", NULL, "sh-sci.12" },
-               { "scifa4", NULL, "sh-sci.13" },
-               { "scifa5", NULL, "sh-sci.14" },
-               { "du0", "du.0", "rcar-du-r8a7791" },
-               { "du1", "du.1", "rcar-du-r8a7791" },
-               { "lvds0", "lvds.0", "rcar-du-r8a7791" },
-       };
-       struct clk *clk;
-       unsigned int i;
+/*
+ * This is a really crude hack to provide clkdev support to platform
+ * devices until they get moved to DT.
+ */
+static const struct clk_name clk_names[] __initconst = {
+       { "cmt0", NULL, "sh_cmt.0" },
+       { "scifa0", NULL, "sh-sci.0" },
+       { "scifa1", NULL, "sh-sci.1" },
+       { "scifb0", NULL, "sh-sci.2" },
+       { "scifb1", NULL, "sh-sci.3" },
+       { "scifb2", NULL, "sh-sci.4" },
+       { "scifa2", NULL, "sh-sci.5" },
+       { "scif0", NULL, "sh-sci.6" },
+       { "scif1", NULL, "sh-sci.7" },
+       { "scif2", NULL, "sh-sci.8" },
+       { "scif3", NULL, "sh-sci.9" },
+       { "scif4", NULL, "sh-sci.10" },
+       { "scif5", NULL, "sh-sci.11" },
+       { "scifa3", NULL, "sh-sci.12" },
+       { "scifa4", NULL, "sh-sci.13" },
+       { "scifa5", NULL, "sh-sci.14" },
+       { "du0", "du.0", "rcar-du-r8a7791" },
+       { "du1", "du.1", "rcar-du-r8a7791" },
+       { "lvds0", "lvds.0", "rcar-du-r8a7791" },
+};
 
-       for (i = 0; i < ARRAY_SIZE(clk_names); ++i) {
-               clk = clk_get(NULL, clk_names[i].clk);
-               if (!IS_ERR(clk)) {
-                       clk_register_clkdev(clk, clk_names[i].con_id,
-                                           clk_names[i].dev_id);
-                       clk_put(clk);
-               }
-       }
+/*
+ * This is a really crude hack to work around core platform clock issues
+ */
+static const struct clk_name clk_enables[] __initconst = {
+       { "ether", NULL, "ee700000.ethernet" },
+       { "i2c2", NULL, "e6530000.i2c" },
+       { "msiof0", NULL, "e6e20000.spi" },
+       { "qspi_mod", NULL, "e6b10000.spi" },
+       { "sdhi0", NULL, "ee100000.sd" },
+       { "sdhi1", NULL, "ee140000.sd" },
+       { "sdhi2", NULL, "ee160000.sd" },
+       { "thermal", NULL, "e61f0000.thermal" },
+};
 
+static void __init koelsch_add_standard_devices(void)
+{
+       shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
+       shmobile_clk_workaround(clk_enables, ARRAY_SIZE(clk_enables), true);
        r8a7791_add_dt_devices();
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 
index 5a034ff405d001c82e9c79872296719691f4a378..a12a9d3b4b6e3c29d99a6db9bc7b91559aedd26a 100644 (file)
@@ -216,7 +216,7 @@ static const struct spi_board_info spi_info[] __initconst = {
        {
                .modalias       = "m25p80",
                .platform_data  = &spi_flash_data,
-               .mode           = SPI_MODE_0,
+               .mode           = SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD,
                .max_speed_hz   = 30000000,
                .bus_num        = 0,
                .chip_select    = 0,
index 440aac36d6938d1e58b78618d1d1f599665d1f96..1eb48cffb4c583e05749721d0e79427aab805be7 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/clk.h>
-#include <linux/clkdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <linux/platform_data/rcar-du.h>
+#include <mach/clock.h>
 #include <mach/common.h>
 #include <mach/irqs.h>
 #include <mach/rcar-gen2.h>
@@ -86,46 +85,46 @@ static void __init lager_add_du_device(void)
        platform_device_register_full(&info);
 }
 
-static void __init lager_add_standard_devices(void)
-{
-       /*
-        * This is a really crude hack to provide clkdev support to platform
-        * devices until they get moved to DT.
-        */
-       static const struct clk_name {
-               const char *clk;
-               const char *con_id;
-               const char *dev_id;
-       } clk_names[] = {
-               { "cmt0", NULL, "sh_cmt.0" },
-               { "scifa0", NULL, "sh-sci.0" },
-               { "scifa1", NULL, "sh-sci.1" },
-               { "scifb0", NULL, "sh-sci.2" },
-               { "scifb1", NULL, "sh-sci.3" },
-               { "scifb2", NULL, "sh-sci.4" },
-               { "scifa2", NULL, "sh-sci.5" },
-               { "scif0", NULL, "sh-sci.6" },
-               { "scif1", NULL, "sh-sci.7" },
-               { "hscif0", NULL, "sh-sci.8" },
-               { "hscif1", NULL, "sh-sci.9" },
-               { "du0", "du.0", "rcar-du-r8a7790" },
-               { "du1", "du.1", "rcar-du-r8a7790" },
-               { "du2", "du.2", "rcar-du-r8a7790" },
-               { "lvds0", "lvds.0", "rcar-du-r8a7790" },
-               { "lvds1", "lvds.1", "rcar-du-r8a7790" },
-       };
-       struct clk *clk;
-       unsigned int i;
+/*
+ * This is a really crude hack to provide clkdev support to platform
+ * devices until they get moved to DT.
+ */
+static const struct clk_name clk_names[] __initconst = {
+       { "cmt0", NULL, "sh_cmt.0" },
+       { "scifa0", NULL, "sh-sci.0" },
+       { "scifa1", NULL, "sh-sci.1" },
+       { "scifb0", NULL, "sh-sci.2" },
+       { "scifb1", NULL, "sh-sci.3" },
+       { "scifb2", NULL, "sh-sci.4" },
+       { "scifa2", NULL, "sh-sci.5" },
+       { "scif0", NULL, "sh-sci.6" },
+       { "scif1", NULL, "sh-sci.7" },
+       { "hscif0", NULL, "sh-sci.8" },
+       { "hscif1", NULL, "sh-sci.9" },
+       { "du0", "du.0", "rcar-du-r8a7790" },
+       { "du1", "du.1", "rcar-du-r8a7790" },
+       { "du2", "du.2", "rcar-du-r8a7790" },
+       { "lvds0", "lvds.0", "rcar-du-r8a7790" },
+       { "lvds1", "lvds.1", "rcar-du-r8a7790" },
+};
 
-       for (i = 0; i < ARRAY_SIZE(clk_names); ++i) {
-               clk = clk_get(NULL, clk_names[i].clk);
-               if (!IS_ERR(clk)) {
-                       clk_register_clkdev(clk, clk_names[i].con_id,
-                                           clk_names[i].dev_id);
-                       clk_put(clk);
-               }
-       }
+/*
+ * This is a really crude hack to work around core platform clock issues
+ */
+static const struct clk_name clk_enables[] __initconst = {
+       { "ether", NULL, "ee700000.ethernet" },
+       { "msiof1", NULL, "e6e10000.spi" },
+       { "mmcif1", NULL, "ee220000.mmc" },
+       { "qspi_mod", NULL, "e6b10000.spi" },
+       { "sdhi0", NULL, "ee100000.sd" },
+       { "sdhi2", NULL, "ee140000.sd" },
+       { "thermal", NULL, "e61f0000.thermal" },
+};
 
+static void __init lager_add_standard_devices(void)
+{
+       shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
+       shmobile_clk_workaround(clk_enables, ARRAY_SIZE(clk_enables), true);
        r8a7790_add_dt_devices();
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 
index 18c7e0311aa679c60a634963a3f64ddf7484dffd..f8b1e05463ccde8e0c835affdb1fe7b49b13038c 100644 (file)
@@ -325,12 +325,12 @@ static const struct rspi_plat_data qspi_pdata __initconst = {
 
 static const struct spi_board_info spi_info[] __initconst = {
        {
-               .modalias               = "m25p80",
-               .platform_data          = &spi_flash_data,
-               .mode                   = SPI_MODE_0,
-               .max_speed_hz           = 30000000,
-               .bus_num                = 0,
-               .chip_select            = 0,
+               .modalias       = "m25p80",
+               .platform_data  = &spi_flash_data,
+               .mode           = SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD,
+               .max_speed_hz   = 30000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
        },
 };
 
@@ -567,20 +567,27 @@ static struct resource rsnd_resources[] __initdata = {
 };
 
 static struct rsnd_ssi_platform_info rsnd_ssi[] = {
-       RSND_SSI_SET(0, 0, gic_spi(370), RSND_SSI_PLAY),
-       RSND_SSI_SET(0, 0, gic_spi(371), RSND_SSI_CLK_PIN_SHARE),
+       RSND_SSI(0, gic_spi(370), 0),
+       RSND_SSI(0, gic_spi(371), RSND_SSI_CLK_PIN_SHARE),
 };
 
-static struct rsnd_scu_platform_info rsnd_scu[2] = {
+static struct rsnd_src_platform_info rsnd_src[2] = {
        /* no member at this point */
 };
 
+static struct rsnd_dai_platform_info rsnd_dai = {
+       .playback = { .ssi = &rsnd_ssi[0], },
+       .capture  = { .ssi = &rsnd_ssi[1], },
+};
+
 static struct rcar_snd_info rsnd_info = {
        .flags          = RSND_GEN2,
        .ssi_info       = rsnd_ssi,
        .ssi_info_nr    = ARRAY_SIZE(rsnd_ssi),
-       .scu_info       = rsnd_scu,
-       .scu_info_nr    = ARRAY_SIZE(rsnd_scu),
+       .src_info       = rsnd_src,
+       .src_info_nr    = ARRAY_SIZE(rsnd_src),
+       .dai_info       = &rsnd_dai,
+       .dai_info_nr    = 1,
 };
 
 static struct asoc_simple_card_info rsnd_card_info = {
diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c
deleted file mode 100644 (file)
index 5ac13ba..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Emma Mobile EV2 clock framework support
- *
- * Copyright (C) 2012  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/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/sh_clk.h>
-#include <linux/clkdev.h>
-#include <mach/common.h>
-
-#define EMEV2_SMU_BASE 0xe0110000
-
-/* EMEV2 SMU registers */
-#define USIAU0_RSTCTRL 0x094
-#define USIBU1_RSTCTRL 0x0ac
-#define USIBU2_RSTCTRL 0x0b0
-#define USIBU3_RSTCTRL 0x0b4
-#define STI_RSTCTRL 0x124
-#define USIAU0GCLKCTRL 0x4a0
-#define USIBU1GCLKCTRL 0x4b8
-#define USIBU2GCLKCTRL 0x4bc
-#define USIBU3GCLKCTRL 0x04c0
-#define STIGCLKCTRL 0x528
-#define USIAU0SCLKDIV 0x61c
-#define USIB2SCLKDIV 0x65c
-#define USIB3SCLKDIV 0x660
-#define STI_CLKSEL 0x688
-
-/* not pretty, but hey */
-static void __iomem *smu_base;
-
-static void emev2_smu_write(unsigned long value, int offs)
-{
-       BUG_ON(!smu_base || (offs >= PAGE_SIZE));
-       iowrite32(value, smu_base + offs);
-}
-
-static struct clk_mapping smu_mapping = {
-       .phys   = EMEV2_SMU_BASE,
-       .len    = PAGE_SIZE,
-};
-
-/* Fixed 32 KHz root clock from C32K pin */
-static struct clk c32k_clk = {
-       .rate           = 32768,
-       .mapping        = &smu_mapping,
-};
-
-/* PLL3 multiplies C32K with 7000 */
-static unsigned long pll3_recalc(struct clk *clk)
-{
-       return clk->parent->rate * 7000;
-}
-
-static struct sh_clk_ops pll3_clk_ops = {
-       .recalc         = pll3_recalc,
-};
-
-static struct clk pll3_clk = {
-       .ops            = &pll3_clk_ops,
-       .parent         = &c32k_clk,
-};
-
-static struct clk *main_clks[] = {
-       &c32k_clk,
-       &pll3_clk,
-};
-
-enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
-       SCLKDIV_NR };
-
-#define SCLKDIV(_reg, _shift)                  \
-{                                                              \
-       .parent         = &pll3_clk,                            \
-       .enable_reg     = IOMEM(EMEV2_SMU_BASE + (_reg)),       \
-       .enable_bit     = _shift,                               \
-}
-
-static struct clk sclkdiv_clks[SCLKDIV_NR] = {
-       [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
-       [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
-       [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
-       [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
-};
-
-enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
-       GCLK_STI_SCLK,
-       GCLK_NR };
-
-#define GCLK_SCLK(_parent, _reg) \
-{                                                              \
-       .parent         = _parent,                              \
-       .enable_reg     = IOMEM(EMEV2_SMU_BASE + (_reg)),       \
-       .enable_bit     = 1, /* SCLK_GCC */                     \
-}
-
-static struct clk gclk_clks[GCLK_NR] = {
-       [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
-                                      USIAU0GCLKCTRL),
-       [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
-                                      USIBU1GCLKCTRL),
-       [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
-                                      USIBU2GCLKCTRL),
-       [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
-                                      USIBU3GCLKCTRL),
-       [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
-};
-
-static int emev2_gclk_enable(struct clk *clk)
-{
-       iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
-                 clk->mapped_reg);
-       return 0;
-}
-
-static void emev2_gclk_disable(struct clk *clk)
-{
-       iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
-                 clk->mapped_reg);
-}
-
-static struct sh_clk_ops emev2_gclk_clk_ops = {
-       .enable         = emev2_gclk_enable,
-       .disable        = emev2_gclk_disable,
-       .recalc         = followparent_recalc,
-};
-
-static int __init emev2_gclk_register(struct clk *clks, int nr)
-{
-       struct clk *clkp;
-       int ret = 0;
-       int k;
-
-       for (k = 0; !ret && (k < nr); k++) {
-               clkp = clks + k;
-               clkp->ops = &emev2_gclk_clk_ops;
-               ret |= clk_register(clkp);
-       }
-
-       return ret;
-}
-
-static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
-{
-       unsigned int sclk_div;
-
-       sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
-
-       return clk->parent->rate / (sclk_div + 1);
-}
-
-static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
-       .recalc         = emev2_sclkdiv_recalc,
-};
-
-static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
-{
-       struct clk *clkp;
-       int ret = 0;
-       int k;
-
-       for (k = 0; !ret && (k < nr); k++) {
-               clkp = clks + k;
-               clkp->ops = &emev2_sclkdiv_clk_ops;
-               ret |= clk_register(clkp);
-       }
-
-       return ret;
-}
-
-static struct clk_lookup lookups[] = {
-       CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
-       CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
-       CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
-       CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
-       CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
-       CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
-       CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
-       CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
-       CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
-       CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
-};
-
-void __init emev2_clock_init(void)
-{
-       int k, ret = 0;
-
-       smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
-       BUG_ON(!smu_base);
-
-       /* setup STI timer to run on 32.768 kHz and deassert reset */
-       emev2_smu_write(0, STI_CLKSEL);
-       emev2_smu_write(1, STI_RSTCTRL);
-
-       /* deassert reset for UART0->UART3 */
-       emev2_smu_write(2, USIAU0_RSTCTRL);
-       emev2_smu_write(2, USIBU1_RSTCTRL);
-       emev2_smu_write(2, USIBU2_RSTCTRL);
-       emev2_smu_write(2, USIBU3_RSTCTRL);
-
-       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
-               ret = clk_register(main_clks[k]);
-
-       if (!ret)
-               ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
-
-       if (!ret)
-               ret = emev2_gclk_register(gclk_clks, GCLK_NR);
-
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
-       if (!ret)
-               shmobile_clk_init();
-       else
-               panic("failed to setup emev2 clocks\n");
-}
index 9989b1b06ffd7dae363552e4d1b973f99f423f0a..6609beb9b9b4d6516b0af89f1d3f1c66c4028e94 100644 (file)
@@ -175,10 +175,6 @@ static struct clk mstp_clks[MSTP_NR] = {
 
 static struct clk_lookup lookups[] = {
        /* main */
-       CLKDEV_CON_ID("audio_clk_a",    &audio_clk_a),
-       CLKDEV_CON_ID("audio_clk_b",    &audio_clk_b),
-       CLKDEV_CON_ID("audio_clk_c",    &audio_clk_c),
-       CLKDEV_CON_ID("audio_clk_internal",     &s1_clk),
        CLKDEV_CON_ID("shyway_clk",     &s_clk),
        CLKDEV_CON_ID("peripheral_clk", &p_clk),
 
@@ -234,15 +230,15 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("ssi.6", "rcar_sound", &mstp_clks[MSTP309]),
        CLKDEV_ICK_ID("ssi.7", "rcar_sound", &mstp_clks[MSTP308]),
        CLKDEV_ICK_ID("ssi.8", "rcar_sound", &mstp_clks[MSTP307]),
-       CLKDEV_ICK_ID("scu.0", "rcar_sound", &mstp_clks[MSTP531]),
-       CLKDEV_ICK_ID("scu.1", "rcar_sound", &mstp_clks[MSTP530]),
-       CLKDEV_ICK_ID("scu.2", "rcar_sound", &mstp_clks[MSTP529]),
-       CLKDEV_ICK_ID("scu.3", "rcar_sound", &mstp_clks[MSTP528]),
-       CLKDEV_ICK_ID("scu.4", "rcar_sound", &mstp_clks[MSTP527]),
-       CLKDEV_ICK_ID("scu.5", "rcar_sound", &mstp_clks[MSTP526]),
-       CLKDEV_ICK_ID("scu.6", "rcar_sound", &mstp_clks[MSTP525]),
-       CLKDEV_ICK_ID("scu.7", "rcar_sound", &mstp_clks[MSTP524]),
-       CLKDEV_ICK_ID("scu.8", "rcar_sound", &mstp_clks[MSTP523]),
+       CLKDEV_ICK_ID("src.0", "rcar_sound", &mstp_clks[MSTP531]),
+       CLKDEV_ICK_ID("src.1", "rcar_sound", &mstp_clks[MSTP530]),
+       CLKDEV_ICK_ID("src.2", "rcar_sound", &mstp_clks[MSTP529]),
+       CLKDEV_ICK_ID("src.3", "rcar_sound", &mstp_clks[MSTP528]),
+       CLKDEV_ICK_ID("src.4", "rcar_sound", &mstp_clks[MSTP527]),
+       CLKDEV_ICK_ID("src.5", "rcar_sound", &mstp_clks[MSTP526]),
+       CLKDEV_ICK_ID("src.6", "rcar_sound", &mstp_clks[MSTP525]),
+       CLKDEV_ICK_ID("src.7", "rcar_sound", &mstp_clks[MSTP524]),
+       CLKDEV_ICK_ID("src.8", "rcar_sound", &mstp_clks[MSTP523]),
 };
 
 void __init r8a7778_clock_init(void)
index 3f93503f5b96f123fc2441abcd37eccc09972dc4..a936ae7de0838602eddb2fe80690c0f009f7089c 100644 (file)
@@ -249,10 +249,10 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP1007] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 7, MSTPSR10, 0), /* SSI8 */
        [MSTP1006] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 6, MSTPSR10, 0), /* SSI9 */
        [MSTP1005] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 5, MSTPSR10, 0), /* SSI ALL */
-       [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */
-       [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */
-       [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */
-       [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */
+       [MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */
+       [MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */
+       [MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */
+       [MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */
        [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */
        [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */
        [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */
@@ -294,10 +294,6 @@ static struct clk mstp_clks[MSTP_NR] = {
 static struct clk_lookup lookups[] = {
 
        /* main clocks */
-       CLKDEV_CON_ID("audio_clk_a",    &audio_clk_a),
-       CLKDEV_CON_ID("audio_clk_b",    &audio_clk_b),
-       CLKDEV_CON_ID("audio_clk_c",    &audio_clk_c),
-       CLKDEV_CON_ID("audio_clk_internal",     &m2_clk),
        CLKDEV_CON_ID("extal",          &extal_clk),
        CLKDEV_CON_ID("extal_div2",     &extal_div2_clk),
        CLKDEV_CON_ID("main",           &main_clk),
@@ -381,16 +377,16 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("clk_b", "rcar_sound", &audio_clk_b),
        CLKDEV_ICK_ID("clk_c", "rcar_sound", &audio_clk_c),
        CLKDEV_ICK_ID("clk_i", "rcar_sound", &m2_clk),
-       CLKDEV_ICK_ID("scu.0", "rcar_sound", &mstp_clks[MSTP1031]),
-       CLKDEV_ICK_ID("scu.1", "rcar_sound", &mstp_clks[MSTP1030]),
-       CLKDEV_ICK_ID("scu.2", "rcar_sound", &mstp_clks[MSTP1029]),
-       CLKDEV_ICK_ID("scu.3", "rcar_sound", &mstp_clks[MSTP1028]),
-       CLKDEV_ICK_ID("scu.4", "rcar_sound", &mstp_clks[MSTP1027]),
-       CLKDEV_ICK_ID("scu.5", "rcar_sound", &mstp_clks[MSTP1026]),
-       CLKDEV_ICK_ID("scu.6", "rcar_sound", &mstp_clks[MSTP1025]),
-       CLKDEV_ICK_ID("scu.7", "rcar_sound", &mstp_clks[MSTP1024]),
-       CLKDEV_ICK_ID("scu.8", "rcar_sound", &mstp_clks[MSTP1023]),
-       CLKDEV_ICK_ID("scu.9", "rcar_sound", &mstp_clks[MSTP1022]),
+       CLKDEV_ICK_ID("src.0", "rcar_sound", &mstp_clks[MSTP1031]),
+       CLKDEV_ICK_ID("src.1", "rcar_sound", &mstp_clks[MSTP1030]),
+       CLKDEV_ICK_ID("src.2", "rcar_sound", &mstp_clks[MSTP1029]),
+       CLKDEV_ICK_ID("src.3", "rcar_sound", &mstp_clks[MSTP1028]),
+       CLKDEV_ICK_ID("src.4", "rcar_sound", &mstp_clks[MSTP1027]),
+       CLKDEV_ICK_ID("src.5", "rcar_sound", &mstp_clks[MSTP1026]),
+       CLKDEV_ICK_ID("src.6", "rcar_sound", &mstp_clks[MSTP1025]),
+       CLKDEV_ICK_ID("src.7", "rcar_sound", &mstp_clks[MSTP1024]),
+       CLKDEV_ICK_ID("src.8", "rcar_sound", &mstp_clks[MSTP1023]),
+       CLKDEV_ICK_ID("src.9", "rcar_sound", &mstp_clks[MSTP1022]),
        CLKDEV_ICK_ID("ssi.0", "rcar_sound", &mstp_clks[MSTP1015]),
        CLKDEV_ICK_ID("ssi.1", "rcar_sound", &mstp_clks[MSTP1014]),
        CLKDEV_ICK_ID("ssi.2", "rcar_sound", &mstp_clks[MSTP1013]),
index 701383fe32674141434f08767d375e05e00e8174..3b26c7eee873fbee4ddd281811247154f1659f3e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/clkdev.h>
 #include <mach/clock.h>
 #include <mach/common.h>
+#include <mach/rcar-gen2.h>
 
 /*
  *   MD                EXTAL           PLL0    PLL1    PLL3
@@ -43,8 +44,6 @@
  *     see "p1 / 2" on R8A7791_CLOCK_ROOT() below
  */
 
-#define MD(nr) (1 << nr)
-
 #define CPG_BASE 0xe6150000
 #define CPG_LEN 0x1000
 
@@ -68,7 +67,6 @@
 #define MSTPSR9                IOMEM(0xe61509a4)
 #define MSTPSR11       IOMEM(0xe61509ac)
 
-#define MODEMR         0xE6160060
 #define SDCKCR         0xE6150074
 #define SD1CKCR                0xE6150078
 #define SD2CKCR                0xE615026c
@@ -190,12 +188,12 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP1108] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 8, MSTPSR11, 0), /* SCIFA5 */
        [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA4 */
        [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA3 */
-       [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */
-       [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */
-       [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */
-       [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */
-       [MSTP927] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */
-       [MSTP925] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */
+       [MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */
+       [MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */
+       [MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */
+       [MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */
+       [MSTP927] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */
+       [MSTP925] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */
        [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */
        [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */
        [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */
@@ -295,14 +293,9 @@ static struct clk_lookup lookups[] = {
 
 void __init r8a7791_clock_init(void)
 {
-       void __iomem *modemr = ioremap_nocache(MODEMR, PAGE_SIZE);
-       u32 mode;
+       u32 mode = rcar_gen2_read_mode_pins();
        int k, ret = 0;
 
-       BUG_ON(!modemr);
-       mode = ioread32(modemr);
-       iounmap(modemr);
-
        switch (mode & (MD(14) | MD(13))) {
        case 0:
                R8A7791_CLOCK_ROOT(15, &extal_clk, 172, 208, 106, 88);
index ad7df629d995413d7e73338e9a984dbf5870c7e8..e7232a0373b9f51719f8391bff63d0bb40e1ab65 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
+
+#ifdef CONFIG_COMMON_CLK
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <mach/clock.h>
+
+void __init shmobile_clk_workaround(const struct clk_name *clks,
+                                   int nr_clks, bool enable)
+{
+       const struct clk_name *clkn;
+       struct clk *clk;
+       unsigned int i;
+
+       for (i = 0; i < nr_clks; ++i) {
+               clkn = clks + i;
+               clk = clk_get(NULL, clkn->clk);
+               if (!IS_ERR(clk)) {
+                       clk_register_clkdev(clk, clkn->con_id, clkn->dev_id);
+                       if (enable)
+                               clk_prepare_enable(clk);
+                       clk_put(clk);
+               }
+       }
+}
+
+#else /* CONFIG_COMMON_CLK */
 #include <linux/sh_clk.h>
 #include <linux/export.h>
 #include <mach/clock.h>
@@ -58,3 +84,5 @@ void __clk_put(struct clk *clk)
 {
 }
 EXPORT_SYMBOL(__clk_put);
+
+#endif /* CONFIG_COMMON_CLK */
index 03e56074928c23fcb053b22b0ac523240e3976d8..9a93cf924b9cf09ef28f1ea4d25451025ccabed2 100644 (file)
@@ -1,6 +1,21 @@
 #ifndef CLOCK_H
 #define CLOCK_H
 
+#ifdef CONFIG_COMMON_CLK
+/* temporary clock configuration helper for platform devices */
+
+struct clk_name {
+       const char *clk;
+       const char *con_id;
+       const char *dev_id;
+};
+
+void shmobile_clk_workaround(const struct clk_name *clks, int nr_clks,
+                            bool enable);
+
+#else /* CONFIG_COMMON_CLK */
+/* legacy clock implementation */
+
 unsigned long shmobile_fixed_ratio_clk_recalc(struct clk *clk);
 extern struct sh_clk_ops shmobile_fixed_ratio_clk_ops;
 
@@ -36,4 +51,5 @@ do {                  \
        (p)->div = d;   \
 } while (0)
 
+#endif /* CONFIG_COMMON_CLK */
 #endif
index cb8e32deb2a3c6cadf7efba9f6cb478daa92c241..f7a360edcc3531b3ed62b38458e1d1b296986853 100644 (file)
@@ -4,6 +4,7 @@
 extern void shmobile_earlytimer_init(void);
 extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz,
                         unsigned int mult, unsigned int div);
+extern void shmobile_init_delay(void);
 struct twd_local_timer;
 extern void shmobile_setup_console(void);
 extern void shmobile_boot_vector(void);
diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h
deleted file mode 100644 (file)
index fcb142a..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __ASM_EMEV2_H__
-#define __ASM_EMEV2_H__
-
-extern void emev2_map_io(void);
-extern void emev2_init_delay(void);
-extern void emev2_clock_init(void);
-extern struct smp_operations emev2_smp_ops;
-
-#endif /* __ASM_EMEV2_H__ */
index 1fc05d9453d026df07a1fb383a81f97d6f8d460e..f710235aff2fad5addfb2f0a65363ccf26bfa93f 100644 (file)
@@ -99,39 +99,7 @@ static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
 
 static bool rmobile_pd_active_wakeup(struct device *dev)
 {
-       bool (*active_wakeup)(struct device *dev);
-
-       active_wakeup = dev_gpd_data(dev)->ops.active_wakeup;
-       return active_wakeup ? active_wakeup(dev) : true;
-}
-
-static int rmobile_pd_stop_dev(struct device *dev)
-{
-       int (*stop)(struct device *dev);
-
-       stop = dev_gpd_data(dev)->ops.stop;
-       if (stop) {
-               int ret = stop(dev);
-               if (ret)
-                       return ret;
-       }
-       return pm_clk_suspend(dev);
-}
-
-static int rmobile_pd_start_dev(struct device *dev)
-{
-       int (*start)(struct device *dev);
-       int ret;
-
-       ret = pm_clk_resume(dev);
-       if (ret)
-               return ret;
-
-       start = dev_gpd_data(dev)->ops.start;
-       if (start)
-               ret = start(dev);
-
-       return ret;
+       return true;
 }
 
 static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
@@ -140,8 +108,8 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
        struct dev_power_governor *gov = rmobile_pd->gov;
 
        pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
-       genpd->dev_ops.stop             = rmobile_pd_stop_dev;
-       genpd->dev_ops.start            = rmobile_pd_start_dev;
+       genpd->dev_ops.stop             = pm_clk_suspend;
+       genpd->dev_ops.start            = pm_clk_resume;
        genpd->dev_ops.active_wakeup    = rmobile_pd_active_wakeup;
        genpd->dev_irq_safe             = true;
        genpd->power_off                = rmobile_pd_power_down;
index c71d667007b8e4e79811da67513ff3b06b6c38c4..d953ff6e78a29d884754548f9ea6af974ae74b20 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <mach/common.h>
-#include <mach/emev2.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -38,23 +37,19 @@ static struct map_desc emev2_io_desc[] __initdata = {
 #endif
 };
 
-void __init emev2_map_io(void)
+static void __init emev2_map_io(void)
 {
        iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
 }
 
-void __init emev2_init_delay(void)
+static void __init emev2_init_delay(void)
 {
        shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
 }
 
 static void __init emev2_add_standard_devices_dt(void)
 {
-#ifdef CONFIG_COMMON_CLK
        of_clk_init(NULL);
-#else
-       emev2_clock_init();
-#endif
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
@@ -63,6 +58,8 @@ static const char *emev2_boards_compat_dt[] __initconst = {
        NULL,
 };
 
+extern struct smp_operations emev2_smp_ops;
+
 DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
        .smp            = smp_ops(emev2_smp_ops),
        .map_io         = emev2_map_io,
index 8f3c68101d59d7f3423e59ee98eb361e73b6a856..a177a7b3bdbd9bfecb281b90a5dc1087a7492ad3 100644 (file)
@@ -765,7 +765,7 @@ static struct platform_device *r8a7740_late_devices[] __initdata = {
  *     "Media RAM (MERAM)" on r8a7740 documentation
  */
 #define MEBUFCNTR      0xFE950098
-void r8a7740_meram_workaround(void)
+void __init r8a7740_meram_workaround(void)
 {
        void __iomem *reg;
 
@@ -869,17 +869,6 @@ void __init r8a7740_add_early_devices(void)
 
 #ifdef CONFIG_USE_OF
 
-void __init r8a7740_add_early_devices_dt(void)
-{
-       shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */
-
-       early_platform_add_devices(r8a7740_early_devices,
-                                  ARRAY_SIZE(r8a7740_early_devices));
-
-       /* setup early console here as well */
-       shmobile_setup_console();
-}
-
 void __init r8a7740_add_standard_devices_dt(void)
 {
        platform_add_devices(r8a7740_devices_dt,
index c4616f0698c6dcfefc3934cace5fd6c16c37e257..a901d9ef53f61c3f6a891f4ea3f4876ec83a6a3a 100644 (file)
@@ -185,12 +185,6 @@ void __init r8a7790_pinmux_init(void)
        r8a7790_register_gpio(3);
        r8a7790_register_gpio(4);
        r8a7790_register_gpio(5);
-       r8a7790_register_i2c(0);
-       r8a7790_register_i2c(1);
-       r8a7790_register_i2c(2);
-       r8a7790_register_i2c(3);
-       r8a7790_register_audio_dmac(0);
-       r8a7790_register_audio_dmac(1);
 }
 
 #define __R8A7790_SCIF(scif_type, _scscr, index, baseaddr, irq)                \
@@ -308,6 +302,12 @@ void __init r8a7790_add_standard_devices(void)
        r8a7790_add_dt_devices();
        r8a7790_register_irqc(0);
        r8a7790_register_thermal();
+       r8a7790_register_i2c(0);
+       r8a7790_register_i2c(1);
+       r8a7790_register_i2c(2);
+       r8a7790_register_i2c(3);
+       r8a7790_register_audio_dmac(0);
+       r8a7790_register_audio_dmac(1);
 }
 
 void __init r8a7790_init_early(void)
index e28404e43860ac371a766dbf97c0f9f47902ec50..a7e4966f5e189e4e6ef25fc0153723953bcfd073 100644 (file)
@@ -213,7 +213,7 @@ void __init r8a7791_add_standard_devices(void)
 void __init r8a7791_init_early(void)
 {
 #ifndef CONFIG_ARM_ARCH_TIMER
-       shmobile_setup_delay(1300, 2, 4); /* Cortex-A15 @ 1300MHz */
+       shmobile_setup_delay(1500, 2, 4); /* Cortex-A15 @ 1500MHz */
 #endif
 }
 
index 10604480f325296347cdfc7a31ed5d40135fd7b1..542c5a47173f9e8a9794a07d39b765704b9c0d75 100644 (file)
 
 u32 rcar_gen2_read_mode_pins(void)
 {
-       void __iomem *modemr = ioremap_nocache(MODEMR, 4);
-       u32 mode;
-
-       BUG_ON(!modemr);
-       mode = ioread32(modemr);
-       iounmap(modemr);
+       static u32 mode;
+       static bool mode_valid;
+
+       if (!mode_valid) {
+               void __iomem *modemr = ioremap_nocache(MODEMR, 4);
+               BUG_ON(!modemr);
+               mode = ioread32(modemr);
+               iounmap(modemr);
+               mode_valid = true;
+       }
 
        return mode;
 }
index 27301278c20840064c7e88d857660e2dbb216015..f8176b051be485b4c242b29f2c281ac1275a8571 100644 (file)
@@ -1037,11 +1037,7 @@ void __init sh7372_add_early_devices_dt(void)
 {
        shmobile_setup_delay(800, 1, 3); /* Cortex-A8 @ 800MHz */
 
-       early_platform_add_devices(sh7372_early_devices,
-                                  ARRAY_SIZE(sh7372_early_devices));
-
-       /* setup early console here as well */
-       shmobile_setup_console();
+       sh7372_add_early_devices();
 }
 
 void __init sh7372_add_standard_devices_dt(void)
index f2ca92308f7568f851289626fddd9c25c6064fee..2dfd748da7f374156e13374251bcdd9fe4a65f31 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <mach/common.h>
-#include <mach/emev2.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
 
index 2df5bd190fe4ce3ca4f40a8bd119d45af4aac1a1..ec979529f30f5b00c3cc94030d67fb5b27efb9c8 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/smp_plat.h>
 #include <mach/common.h>
 #include <mach/r8a7791.h>
+#include <mach/rcar-gen2.h>
 
 #define RST            0xe6160000
 #define CA15BAR                0x0020
@@ -51,9 +52,21 @@ static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus)
        iounmap(p);
 }
 
+static int r8a7791_smp_boot_secondary(unsigned int cpu,
+                                     struct task_struct *idle)
+{
+       /* Error out when hardware debug mode is enabled */
+       if (rcar_gen2_read_mode_pins() & BIT(21)) {
+               pr_warn("Unable to boot CPU%u when MD21 is set\n", cpu);
+               return -ENOTSUPP;
+       }
+
+       return shmobile_smp_apmu_boot_secondary(cpu, idle);
+}
+
 struct smp_operations r8a7791_smp_ops __initdata = {
        .smp_prepare_cpus       = r8a7791_smp_prepare_cpus,
-       .smp_boot_secondary     = shmobile_smp_apmu_boot_secondary,
+       .smp_boot_secondary     = r8a7791_smp_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
        .cpu_disable            = shmobile_smp_cpu_disable,
        .cpu_die                = shmobile_smp_apmu_cpu_die,
index 62d7052d6f215f7679d88f12365dc8fb048de253..ccecde9a3362e457e92d37d16facaae1993ff080 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/clocksource.h>
 #include <linux/delay.h>
+#include <linux/of_address.h>
 
 void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz,
                                 unsigned int mult, unsigned int div)
@@ -39,6 +40,33 @@ void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz,
                preset_lpj = max_cpu_core_mhz * value;
 }
 
+void __init shmobile_init_delay(void)
+{
+       struct device_node *np, *parent;
+       u32 max_freq, freq;
+
+       max_freq = 0;
+
+       parent = of_find_node_by_path("/cpus");
+       if (parent) {
+               for_each_child_of_node(parent, np) {
+                       if (!of_property_read_u32(np, "clock-frequency", &freq))
+                               max_freq = max(max_freq, freq);
+               }
+               of_node_put(parent);
+       }
+
+       if (max_freq) {
+               if (of_find_compatible_node(NULL, NULL, "arm,cortex-a8"))
+                       shmobile_setup_delay(max_freq, 1, 3);
+               else if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
+                       shmobile_setup_delay(max_freq, 1, 3);
+               else if (of_find_compatible_node(NULL, NULL, "arm,cortex-a15"))
+                       if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
+                               shmobile_setup_delay(max_freq, 2, 4);
+       }
+}
+
 static void __init shmobile_late_time_init(void)
 {
        /*
index f2c89fb8fca9d6bf6d2324404b45fad1869288f8..be83ba25f81b7e75064befef4dd4b599d63d91e2 100644 (file)
@@ -310,6 +310,21 @@ static struct platform_device char_lcd_device = {
        .resource       =       char_lcd_resources,
 };
 
+static struct resource leds_resources[] = {
+       {
+               .start  = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET,
+               .end    = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET + 4,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device leds_device = {
+       .name           = "versatile-leds",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(leds_resources),
+       .resource       = leds_resources,
+};
+
 /*
  * Clock handling
  */
@@ -795,6 +810,7 @@ void __init versatile_init(void)
        platform_device_register(&versatile_i2c_device);
        platform_device_register(&smc91x_device);
        platform_device_register(&char_lcd_device);
+       platform_device_register(&leds_device);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
index 21b9e1bf9b7714106b13ea7a3f3606875fb25ae3..45aeaaca9052f237322cf91a247a69fdb2d1571e 100644 (file)
 #include <asm/tlbflush.h>
 #include "mm.h"
 
+pte_t *fixmap_page_table;
+
+static inline void set_fixmap_pte(int idx, pte_t pte)
+{
+       unsigned long vaddr = __fix_to_virt(idx);
+       set_pte_ext(fixmap_page_table + idx, pte, 0);
+       local_flush_tlb_kernel_page(vaddr);
+}
+
+static inline pte_t get_fixmap_pte(unsigned long vaddr)
+{
+       unsigned long idx = __virt_to_fix(vaddr);
+       return *(fixmap_page_table + idx);
+}
+
 void *kmap(struct page *page)
 {
        might_sleep();
@@ -63,20 +78,20 @@ void *kmap_atomic(struct page *page)
        type = kmap_atomic_idx_push();
 
        idx = type + KM_TYPE_NR * smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+       vaddr = __fix_to_virt(idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
        /*
         * With debugging enabled, kunmap_atomic forces that entry to 0.
         * Make sure it was indeed properly unmapped.
         */
-       BUG_ON(!pte_none(get_top_pte(vaddr)));
+       BUG_ON(!pte_none(*(fixmap_page_table + idx)));
 #endif
        /*
         * When debugging is off, kunmap_atomic leaves the previous mapping
         * in place, so the contained TLB flush ensures the TLB is updated
         * with the new mapping.
         */
-       set_top_pte(vaddr, mk_pte(page, kmap_prot));
+       set_fixmap_pte(idx, mk_pte(page, kmap_prot));
 
        return (void *)vaddr;
 }
@@ -94,8 +109,8 @@ void __kunmap_atomic(void *kvaddr)
                if (cache_is_vivt())
                        __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
 #ifdef CONFIG_DEBUG_HIGHMEM
-               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
-               set_top_pte(vaddr, __pte(0));
+               BUG_ON(vaddr != __fix_to_virt(idx));
+               set_fixmap_pte(idx, __pte(0));
 #else
                (void) idx;  /* to kill a warning */
 #endif
@@ -117,11 +132,11 @@ void *kmap_atomic_pfn(unsigned long pfn)
 
        type = kmap_atomic_idx_push();
        idx = type + KM_TYPE_NR * smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+       vaddr = __fix_to_virt(idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
-       BUG_ON(!pte_none(get_top_pte(vaddr)));
+       BUG_ON(!pte_none(*(fixmap_page_table + idx)));
 #endif
-       set_top_pte(vaddr, pfn_pte(pfn, kmap_prot));
+       set_fixmap_pte(idx, pfn_pte(pfn, kmap_prot));
 
        return (void *)vaddr;
 }
@@ -133,5 +148,5 @@ struct page *kmap_atomic_to_page(const void *ptr)
        if (vaddr < FIXADDR_START)
                return virt_to_page(ptr);
 
-       return pte_page(get_top_pte(vaddr));
+       return pte_page(get_fixmap_pte(vaddr));
 }
index b68c6b22e1c80f263d46555064b1c1c13f48586c..09c0a16165dcd6325ed4fcd0ba3ab979f1639968 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/pci.h>
+#include <asm/fixmap.h>
 
 #include "mm.h"
 #include "tcm.h"
@@ -1359,6 +1360,9 @@ static void __init kmap_init(void)
 #ifdef CONFIG_HIGHMEM
        pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
                PKMAP_BASE, _PAGE_KERNEL_TABLE);
+
+       fixmap_page_table = early_pte_alloc(pmd_off_k(FIXADDR_START),
+               FIXADDR_START, _PAGE_KERNEL_TABLE);
 #endif
 }
 
index 01a719e18bb047c655694c336d5a42e1388d1062..22e3ad63500c0e79f4eaf54555ca6c7aa13c57ff 100644 (file)
@@ -64,6 +64,14 @@ ENTRY(cpu_v7_switch_mm)
        mov     pc, lr
 ENDPROC(cpu_v7_switch_mm)
 
+#ifdef __ARMEB__
+#define rl r3
+#define rh r2
+#else
+#define rl r2
+#define rh r3
+#endif
+
 /*
  * cpu_v7_set_pte_ext(ptep, pte)
  *
@@ -73,13 +81,13 @@ ENDPROC(cpu_v7_switch_mm)
  */
 ENTRY(cpu_v7_set_pte_ext)
 #ifdef CONFIG_MMU
-       tst     r2, #L_PTE_VALID
+       tst     rl, #L_PTE_VALID
        beq     1f
-       tst     r3, #1 << (57 - 32)             @ L_PTE_NONE
-       bicne   r2, #L_PTE_VALID
+       tst     rh, #1 << (57 - 32)             @ L_PTE_NONE
+       bicne   rl, #L_PTE_VALID
        bne     1f
-       tst     r3, #1 << (55 - 32)             @ L_PTE_DIRTY
-       orreq   r2, #L_PTE_RDONLY
+       tst     rh, #1 << (55 - 32)             @ L_PTE_DIRTY
+       orreq   rl, #L_PTE_RDONLY
 1:     strd    r2, r3, [r0]
        ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
index 195731d3813bb5c0ecba68c5c82ead71b4fbe532..b74ea60891d501333f745b10d4f7a4d40353c513 100644 (file)
@@ -169,9 +169,31 @@ ENDPROC(cpu_pj4b_do_idle)
        globl_equ       cpu_pj4b_do_idle,       cpu_v7_do_idle
 #endif
        globl_equ       cpu_pj4b_dcache_clean_area,     cpu_v7_dcache_clean_area
-       globl_equ       cpu_pj4b_do_suspend,    cpu_v7_do_suspend
-       globl_equ       cpu_pj4b_do_resume,     cpu_v7_do_resume
-       globl_equ       cpu_pj4b_suspend_size,  cpu_v7_suspend_size
+#ifdef CONFIG_ARM_CPU_SUSPEND
+ENTRY(cpu_pj4b_do_suspend)
+       stmfd   sp!, {r6 - r10}
+       mrc     p15, 1, r6, c15, c1, 0  @ save CP15 - extra features
+       mrc     p15, 1, r7, c15, c2, 0  @ save CP15 - Aux Func Modes Ctrl 0
+       mrc     p15, 1, r8, c15, c1, 2  @ save CP15 - Aux Debug Modes Ctrl 2
+       mrc     p15, 1, r9, c15, c1, 1  @ save CP15 - Aux Debug Modes Ctrl 1
+       mrc     p15, 0, r10, c9, c14, 0  @ save CP15 - PMC
+       stmia   r0!, {r6 - r10}
+       ldmfd   sp!, {r6 - r10}
+       b cpu_v7_do_suspend
+ENDPROC(cpu_pj4b_do_suspend)
+
+ENTRY(cpu_pj4b_do_resume)
+       ldmia   r0!, {r6 - r10}
+       mcr     p15, 1, r6, c15, c1, 0  @ save CP15 - extra features
+       mcr     p15, 1, r7, c15, c2, 0  @ save CP15 - Aux Func Modes Ctrl 0
+       mcr     p15, 1, r8, c15, c1, 2  @ save CP15 - Aux Debug Modes Ctrl 2
+       mcr     p15, 1, r9, c15, c1, 1  @ save CP15 - Aux Debug Modes Ctrl 1
+       mcr     p15, 0, r10, c9, c14, 0  @ save CP15 - PMC
+       b cpu_v7_do_resume
+ENDPROC(cpu_pj4b_do_resume)
+#endif
+.globl cpu_pj4b_suspend_size
+.equ   cpu_pj4b_suspend_size, 4 * 14
 
 #endif
 
index 6816192a7561b41941b403964008f46da0803da5..b61a3bcc2fa83bb028933edc80d934e5d1222386 100644 (file)
@@ -597,51 +597,3 @@ void __init orion_gpio_init(struct device_node *np,
 
        orion_gpio_chip_count++;
 }
-
-#ifdef CONFIG_OF
-static void __init orion_gpio_of_init_one(struct device_node *np,
-                                         int irq_gpio_base)
-{
-       int ngpio, gpio_base, mask_offset;
-       void __iomem *base;
-       int ret, i;
-       int irqs[4];
-       int secondary_irq_base;
-
-       ret = of_property_read_u32(np, "ngpio", &ngpio);
-       if (ret)
-               goto out;
-       ret = of_property_read_u32(np, "mask-offset", &mask_offset);
-       if (ret == -EINVAL)
-               mask_offset = 0;
-       else
-               goto out;
-       base = of_iomap(np, 0);
-       if (!base)
-               goto out;
-
-       secondary_irq_base = irq_gpio_base + (32 * orion_gpio_chip_count);
-       gpio_base = 32 * orion_gpio_chip_count;
-
-       /* Get the interrupt numbers. Each chip can have up to 4
-        * interrupt handlers, with each handler dealing with 8 GPIO
-        * pins. */
-
-       for (i = 0; i < 4; i++)
-               irqs[i] = irq_of_parse_and_map(np, i);
-
-       orion_gpio_init(np, gpio_base, ngpio, base, mask_offset,
-                       secondary_irq_base, irqs);
-       return;
-out:
-       pr_err("%s: %s: missing mandatory property\n", __func__, np->name);
-}
-
-void __init orion_gpio_of_init(int irq_gpio_base)
-{
-       struct device_node *np;
-
-       for_each_compatible_node(np, NULL, "marvell,orion-gpio")
-               orion_gpio_of_init_one(np, irq_gpio_base);
-}
-#endif
index 50547e41793601042a4342aebec12186163d9e00..96be19e9bd93dfd2da0a70d7fd0c2c67f9ba1b6f 100644 (file)
@@ -12,5 +12,4 @@
 #define __PLAT_IRQ_H
 
 void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr);
-void __init orion_dt_init_irq(void);
 #endif
index 614dcac9dc5298bb42fb18183eb98d10789c8088..e763988b04b9cbd216d22e74a8854b598719b257 100644 (file)
@@ -33,5 +33,4 @@ void __init orion_gpio_init(struct device_node *np,
                            int secondary_irq_base,
                            int irq[4]);
 
-void __init orion_gpio_of_init(int irq_gpio_base);
 #endif
index 807df142444b4fefe854f5d7421f7221b5417b87..8c1fc06007c0c36c10ae1cf9aefeffe119bee8ca 100644 (file)
 #include <plat/orion-gpio.h>
 #include <mach/bridge-regs.h>
 
-#ifdef CONFIG_MULTI_IRQ_HANDLER
-/*
- * Compiling with both non-DT and DT support enabled, will
- * break asm irq handler used by non-DT boards. Therefore,
- * we provide a C-style irq handler even for non-DT boards,
- * if MULTI_IRQ_HANDLER is set.
- *
- * Notes:
- * - this is prepared for Kirkwood and Dove only, update
- *   accordingly if you add Orion5x or MV78x00.
- * - Orion5x uses different macro names and has only one
- *   set of CAUSE/MASK registers.
- * - MV78x00 uses the same macro names but has a third
- *   set of CAUSE/MASK registers.
- *
- */
-
-static void __iomem *orion_irq_base = IRQ_VIRT_BASE;
-
-asmlinkage void
-__exception_irq_entry orion_legacy_handle_irq(struct pt_regs *regs)
-{
-       u32 stat;
-
-       stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_LOW_OFF);
-       stat &= readl_relaxed(orion_irq_base + IRQ_MASK_LOW_OFF);
-       if (stat) {
-               unsigned int hwirq = __fls(stat);
-               handle_IRQ(hwirq, regs);
-               return;
-       }
-       stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_HIGH_OFF);
-       stat &= readl_relaxed(orion_irq_base + IRQ_MASK_HIGH_OFF);
-       if (stat) {
-               unsigned int hwirq = 32 + __fls(stat);
-               handle_IRQ(hwirq, regs);
-               return;
-       }
-}
-#endif
-
 void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
 {
        struct irq_chip_generic *gc;
@@ -78,40 +37,4 @@ void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
        ct->chip.irq_unmask = irq_gc_mask_set_bit;
        irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE,
                               IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
-
-#ifdef CONFIG_MULTI_IRQ_HANDLER
-       set_handle_irq(orion_legacy_handle_irq);
-#endif
-}
-
-#ifdef CONFIG_OF
-static int __init orion_add_irq_domain(struct device_node *np,
-                                      struct device_node *interrupt_parent)
-{
-       int i = 0;
-       void __iomem *base;
-
-       do {
-               base = of_iomap(np, i);
-               if (base) {
-                       orion_irq_init(i * 32, base + 0x04);
-                       i++;
-               }
-       } while (base);
-
-       irq_domain_add_legacy(np, i * 32, 0, 0,
-                             &irq_domain_simple_ops, NULL);
-       return 0;
-}
-
-static const struct of_device_id orion_irq_match[] = {
-       { .compatible = "marvell,orion-intc",
-         .data = orion_add_irq_domain, },
-       {},
-};
-
-void __init orion_dt_init_irq(void)
-{
-       of_irq_init(orion_irq_match);
 }
-#endif
index 2c4332b9f9484883a00ab6b7af2a3edc0ccd88ac..fce41e93b6a4e74d9b4fb7622d12a80b1734dc36 100644 (file)
@@ -6,12 +6,6 @@ config PLAT_VERSATILE_CLOCK
 config PLAT_VERSATILE_CLCD
        bool
 
-config PLAT_VERSATILE_LEDS
-       def_bool y if NEW_LEDS
-       depends on ARCH_REALVIEW || ARCH_VERSATILE
-       select LEDS_CLASS
-       select LEDS_TRIGGERS
-
 config PLAT_VERSATILE_SCHED_CLOCK
        def_bool y
 
index f88d448b629caa43171f63b5c9bd9d9cf4bd1df0..2e0c472958ae42b0e175a65ea566f793ef07cd3d 100644 (file)
@@ -2,6 +2,5 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
 
 obj-$(CONFIG_PLAT_VERSATILE_CLOCK) += clock.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
-obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
 obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
index f0759e70fb865b4d24370a46b58b37564e49f871..fe6ca574d0931dc93d5114f2995ae553e769242b 100644 (file)
 @  r9  = normal "successful" return address
 @  r10 = this threads thread_info structure
 @  lr  = unrecognised instruction return address
-@  IRQs disabled.
+@  IRQs enabled.
 @
 ENTRY(do_vfp)
        inc_preempt_count r10, r4
-       enable_irq
        ldr     r4, .LCvfp
        ldr     r11, [r10, #TI_CPU]     @ CPU number
        add     r10, r10, #TI_VFPSTATE  @ r10 = workspace
index 93f4b2dd92484863e8015da4a622a0c17745de5a..f8c40a66e65ddb3d3a4c327379d0eec2b234ce50 100644 (file)
                              <0x0 0x1f21e000 0x0 0x1000>,
                              <0x0 0x1f217000 0x0 0x1000>;
                        interrupts = <0x0 0x86 0x4>;
+                       dma-coherent;
                        status = "disabled";
                        clocks = <&sata01clk 0>;
                        phys = <&phy1 0>;
                              <0x0 0x1f22e000 0x0 0x1000>,
                              <0x0 0x1f227000 0x0 0x1000>;
                        interrupts = <0x0 0x87 0x4>;
+                       dma-coherent;
                        status = "ok";
                        clocks = <&sata23clk 0>;
                        phys = <&phy2 0>;
                              <0x0 0x1f23d000 0x0 0x1000>,
                              <0x0 0x1f23e000 0x0 0x1000>;
                        interrupts = <0x0 0x88 0x4>;
+                       dma-coherent;
                        status = "ok";
                        clocks = <&sata45clk 0>;
                        phys = <&phy3 0>;
index ffbbdde7aba10480c12b41d552d1fb41da6097df..2dc36d00addffad4a4bd10ef0a6b1bac21170a49 100644 (file)
@@ -143,10 +143,8 @@ static int __init setup_early_printk(char *buf)
        }
        /* no options parsing yet */
 
-       if (paddr) {
-               set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr);
-               early_base = (void __iomem *)fix_to_virt(FIX_EARLYCON_MEM_BASE);
-       }
+       if (paddr)
+               early_base = (void __iomem *)set_fixmap_offset_io(FIX_EARLYCON_MEM_BASE, paddr);
 
        printch = match->printch;
        early_console = &early_console_dev;
index 93e7df8968fe123d40ce7ad2a017ac88aef7e118..7ec784653b29fad2b1eba1c49a21e9e499a6c167 100644 (file)
@@ -396,7 +396,7 @@ static int __init arm64_device_init(void)
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
        return 0;
 }
-arch_initcall(arm64_device_init);
+arch_initcall_sync(arm64_device_init);
 
 static DEFINE_PER_CPU(struct cpu, cpu_data);
 
index 0ba347e59f06a7dbfe3fe7dcc884f9435c791d6e..c851eb44dc505f8b250b7e1205b1a5ccb35afc8c 100644 (file)
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
 #include <linux/vmalloc.h>
 #include <linux/swiotlb.h>
+#include <linux/amba/bus.h>
 
 #include <asm/cacheflush.h>
 
@@ -305,17 +308,45 @@ struct dma_map_ops coherent_swiotlb_dma_ops = {
 };
 EXPORT_SYMBOL(coherent_swiotlb_dma_ops);
 
+static int dma_bus_notifier(struct notifier_block *nb,
+                           unsigned long event, void *_dev)
+{
+       struct device *dev = _dev;
+
+       if (event != BUS_NOTIFY_ADD_DEVICE)
+               return NOTIFY_DONE;
+
+       if (of_property_read_bool(dev->of_node, "dma-coherent"))
+               set_dma_ops(dev, &coherent_swiotlb_dma_ops);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block platform_bus_nb = {
+       .notifier_call = dma_bus_notifier,
+};
+
+static struct notifier_block amba_bus_nb = {
+       .notifier_call = dma_bus_notifier,
+};
+
 extern int swiotlb_late_init_with_default_size(size_t default_size);
 
 static int __init swiotlb_late_init(void)
 {
        size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
 
-       dma_ops = &coherent_swiotlb_dma_ops;
+       /*
+        * These must be registered before of_platform_populate().
+        */
+       bus_register_notifier(&platform_bus_type, &platform_bus_nb);
+       bus_register_notifier(&amba_bustype, &amba_bus_nb);
+
+       dma_ops = &noncoherent_swiotlb_dma_ops;
 
        return swiotlb_late_init_with_default_size(swiotlb_size);
 }
-subsys_initcall(swiotlb_late_init);
+arch_initcall(swiotlb_late_init);
 
 #define PREALLOC_DMA_DEBUG_ENTRIES     4096
 
index 6b7e89569a3a9ff8518e7c6ee856603f1e9fb93b..0a472c41a67fa9dc33e9c746c24a402d6f306289 100644 (file)
@@ -374,6 +374,9 @@ int kern_addr_valid(unsigned long addr)
        if (pmd_none(*pmd))
                return 0;
 
+       if (pmd_sect(*pmd))
+               return pfn_valid(pmd_pfn(*pmd));
+
        pte = pte_offset_kernel(pmd, addr);
        if (pte_none(*pte))
                return 0;
diff --git a/arch/hexagon/include/asm/barrier.h b/arch/hexagon/include/asm/barrier.h
deleted file mode 100644 (file)
index 4e863da..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Memory barrier definitions for the Hexagon architecture
- *
- * Copyright (c) 2010-2011, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#ifndef _ASM_BARRIER_H
-#define _ASM_BARRIER_H
-
-#define rmb()                          barrier()
-#define read_barrier_depends()         barrier()
-#define wmb()                          barrier()
-#define mb()                           barrier()
-#define smp_rmb()                      barrier()
-#define smp_read_barrier_depends()     barrier()
-#define smp_wmb()                      barrier()
-#define smp_mb()                       barrier()
-
-/*  Set a value and use a memory barrier.  Used by the scheduler somewhere.  */
-#define set_mb(var, value) \
-       do { var = value; mb(); } while (0)
-
-#endif /* _ASM_BARRIER_H */
index 5b16f5d61b44cb4f2cbcb7372d4f98061bef6da0..88c27d94a7214c959c6d75a3ac992a4c95b13b2e 100644 (file)
@@ -58,17 +58,16 @@ void (*mach_halt)(void);
 void (*mach_power_off)(void);
 
 #ifdef CONFIG_M68000
-#define CPU_NAME       "MC68000"
-#endif
-#ifdef CONFIG_M68328
+#if defined(CONFIG_M68328)
 #define CPU_NAME       "MC68328"
-#endif
-#ifdef CONFIG_M68EZ328
+#elif defined(CONFIG_M68EZ328)
 #define CPU_NAME       "MC68EZ328"
-#endif
-#ifdef CONFIG_M68VZ328
+#elif defined(CONFIG_M68VZ328)
 #define CPU_NAME       "MC68VZ328"
+#else
+#define CPU_NAME       "MC68000"
 #endif
+#endif /* CONFIG_M68000 */
 #ifdef CONFIG_M68360
 #define CPU_NAME       "MC68360"
 #endif
index 332b5e8605fcdf2d81772babc7b54bde55dd802d..21952906e9e218b1be13abec33429e0f2d4c8752 100644 (file)
@@ -69,7 +69,8 @@ void __init config_BSP(char *command, int len)
   if (p) strcpy(p,command);
   else command[0] = 0;
 #endif
+
+  mach_sched_init = hw_timer_init;
   mach_hwclk = m68328_hwclk;
   mach_reset = m68ez328_reset;
 }
index fd6658358af1aa00c95848bf62f7aed8cf8d15c6..0e5e5a10a02126b69f609ac6d4b1590fe2064495 100644 (file)
@@ -182,6 +182,7 @@ void __init config_BSP(char *command, int size)
 
        init_hardware(command, size);
 
+       mach_sched_init = hw_timer_init;
        mach_hwclk = m68328_hwclk;
        mach_reset = m68vz328_reset;
 }
index d2cfe45f332b419b5c463b78eb4f44a40e0386c4..cc39966ca63d55632cc72551fc2032d1d2d2f4b8 100644 (file)
@@ -16,7 +16,6 @@ obj- := $(platform-)
 
 obj-y += kernel/
 obj-y += mm/
-obj-y += math-emu/
 
 ifdef CONFIG_KVM
 obj-y += kvm/
index 5cd695f905a1c424b02fed524a9169eaaa5d63f3..45e75b6173b5c5392d7d1bfe338478989fe26987 100644 (file)
@@ -83,6 +83,7 @@ config AR7
        select SYS_HAS_EARLY_PRINTK
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_MIPS16
        select SYS_SUPPORTS_ZBOOT_UART16550
        select ARCH_REQUIRE_GPIOLIB
        select VLYNQ
@@ -106,6 +107,7 @@ config ATH79
        select SYS_HAS_EARLY_PRINTK
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_MIPS16
        help
          Support for the Atheros AR71XX/AR724X/AR913X SoCs.
 
@@ -122,6 +124,7 @@ config BCM47XX
        select NO_EXCEPT_FILL
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_MIPS16
        select SYS_HAS_EARLY_PRINTK
        select USE_GENERIC_EARLY_PRINTK_8250
        help
@@ -248,6 +251,7 @@ config LANTIQ
        select SYS_HAS_CPU_MIPS32_R2
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_MIPS16
        select SYS_SUPPORTS_MULTITHREADING
        select SYS_HAS_EARLY_PRINTK
        select ARCH_REQUIRE_GPIOLIB
@@ -330,6 +334,7 @@ config MIPS_MALTA
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_MIPS_CMP
        select SYS_SUPPORTS_MIPS_CPS
+       select SYS_SUPPORTS_MIPS16
        select SYS_SUPPORTS_MULTITHREADING
        select SYS_SUPPORTS_SMARTMIPS
        select SYS_SUPPORTS_ZBOOT
@@ -361,6 +366,7 @@ config MIPS_SEAD3
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_SMARTMIPS
        select SYS_SUPPORTS_MICROMIPS
+       select SYS_SUPPORTS_MIPS16
        select USB_EHCI_BIG_ENDIAN_DESC
        select USB_EHCI_BIG_ENDIAN_MMIO
        select USE_OF
@@ -380,6 +386,7 @@ config MACH_VR41XX
        select CEVT_R4K
        select CSRC_R4K
        select SYS_HAS_CPU_VR41XX
+       select SYS_SUPPORTS_MIPS16
        select ARCH_REQUIRE_GPIOLIB
 
 config NXP_STB220
@@ -407,6 +414,7 @@ config PMC_MSP
        select SYS_HAS_CPU_MIPS32_R2
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_MIPS16
        select IRQ_CPU
        select SERIAL_8250
        select SERIAL_8250_CONSOLE
@@ -430,6 +438,7 @@ config RALINK
        select SYS_HAS_CPU_MIPS32_R2
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_MIPS16
        select SYS_HAS_EARLY_PRINTK
        select HAVE_MACH_CLKDEV
        select CLKDEV_LOOKUP
@@ -1059,6 +1068,7 @@ config SOC_PNX833X
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_MIPS16
        select CPU_MIPSR2_IRQ_VI
 
 config SOC_PNX8335
@@ -2199,6 +2209,13 @@ config SYS_SUPPORTS_SMARTMIPS
 config SYS_SUPPORTS_MICROMIPS
        bool
 
+config SYS_SUPPORTS_MIPS16
+       bool
+       help
+         This option must be set if a kernel might be executed on a MIPS16-
+         enabled CPU even if MIPS16 is not actually being used.  In other
+         words, it makes the kernel MIPS16-tolerant.
+
 config CPU_SUPPORTS_MSA
        bool
 
index 1a5b4032cb662b4db660acebba0cacb7752a66f6..4852ae97e7df1a345895056aa176a868633b7b94 100644 (file)
@@ -251,6 +251,7 @@ OBJCOPYFLAGS                += --remove-section=.reginfo
 head-y := arch/mips/kernel/head.o
 
 libs-y                 += arch/mips/lib/
+libs-y                 += arch/mips/math-emu/
 
 # See arch/mips/Kbuild for content of core part of the kernel
 core-y += arch/mips/
index 5abf4e894216ac4b683772f6b187e4e9337eb2d5..2a66e908f6a9d9a276cad042ac793f692630255e 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
+#include <asm/cpu-type.h>
 #include <asm/irq_regs.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
index f434b759e3b9aaa0f6eb9ab07f85fb783de4a6ad..ec606363b80677fd464b92c13d5a905871b21466 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
+#include <asm/cpu-type.h>
 #include <asm/irq_regs.h>
 #include <asm/ptrace.h>
 #include <asm/traps.h>
index 064ae7a76bdc204c28e0c8e92ccd63400fbbf403..ae73e42ac20b163331a77439a75270320a77dfa8 100644 (file)
@@ -6,4 +6,3 @@
 lib-y                  += init.o memory.o cmdline.o identify.o console.o
 
 lib-$(CONFIG_32BIT)    += locore.o
-lib-$(CONFIG_64BIT)    += call_o32.o
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S
deleted file mode 100644 (file)
index 8c84981..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *     O32 interface for the 64 (or N32) ABI.
- *
- *     Copyright (C) 2002  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
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- */
-
-#include <asm/asm.h>
-#include <asm/regdef.h>
-
-/* Maximum number of arguments supported.  Must be even!  */
-#define O32_ARGC       32
-/* Number of static registers we save.  */
-#define O32_STATC      11
-/* Frame size for both of the above.  */
-#define O32_FRAMESZ    (4 * O32_ARGC + SZREG * O32_STATC)
-
-               .text
-
-/*
- * O32 function call dispatcher, for interfacing 32-bit ROM routines.
- *
- * The standard 64 (N32) calling sequence is supported, with a0
- * holding a function pointer, a1-a7 -- its first seven arguments
- * and the stack -- remaining ones (up to O32_ARGC, including a1-a7).
- * Static registers, gp and fp are preserved, v0 holds a result.
- * This code relies on the called o32 function for sp and ra
- * restoration and thus both this dispatcher and the current stack
- * have to be placed in a KSEGx (or KUSEG) address space.  Any
- * pointers passed have to point to addresses within one of these
- * spaces as well.
- */
-NESTED(call_o32, O32_FRAMESZ, ra)
-               REG_SUBU        sp,O32_FRAMESZ
-
-               REG_S           ra,O32_FRAMESZ-1*SZREG(sp)
-               REG_S           fp,O32_FRAMESZ-2*SZREG(sp)
-               REG_S           gp,O32_FRAMESZ-3*SZREG(sp)
-               REG_S           s7,O32_FRAMESZ-4*SZREG(sp)
-               REG_S           s6,O32_FRAMESZ-5*SZREG(sp)
-               REG_S           s5,O32_FRAMESZ-6*SZREG(sp)
-               REG_S           s4,O32_FRAMESZ-7*SZREG(sp)
-               REG_S           s3,O32_FRAMESZ-8*SZREG(sp)
-               REG_S           s2,O32_FRAMESZ-9*SZREG(sp)
-               REG_S           s1,O32_FRAMESZ-10*SZREG(sp)
-               REG_S           s0,O32_FRAMESZ-11*SZREG(sp)
-
-               move            jp,a0
-
-               sll             a0,a1,zero
-               sll             a1,a2,zero
-               sll             a2,a3,zero
-               sll             a3,a4,zero
-               sw              a5,0x10(sp)
-               sw              a6,0x14(sp)
-               sw              a7,0x18(sp)
-
-               PTR_LA          t0,O32_FRAMESZ(sp)
-               PTR_LA          t1,0x1c(sp)
-               li              t2,O32_ARGC-7
-1:
-               lw              t3,(t0)
-               REG_ADDU        t0,SZREG
-               sw              t3,(t1)
-               REG_SUBU        t2,1
-               REG_ADDU        t1,4
-               bnez            t2,1b
-
-               jalr            jp
-
-               REG_L           s0,O32_FRAMESZ-11*SZREG(sp)
-               REG_L           s1,O32_FRAMESZ-10*SZREG(sp)
-               REG_L           s2,O32_FRAMESZ-9*SZREG(sp)
-               REG_L           s3,O32_FRAMESZ-8*SZREG(sp)
-               REG_L           s4,O32_FRAMESZ-7*SZREG(sp)
-               REG_L           s5,O32_FRAMESZ-6*SZREG(sp)
-               REG_L           s6,O32_FRAMESZ-5*SZREG(sp)
-               REG_L           s7,O32_FRAMESZ-4*SZREG(sp)
-               REG_L           gp,O32_FRAMESZ-3*SZREG(sp)
-               REG_L           fp,O32_FRAMESZ-2*SZREG(sp)
-               REG_L           ra,O32_FRAMESZ-1*SZREG(sp)
-
-               REG_ADDU        sp,O32_FRAMESZ
-               jr              ra
-END(call_o32)
index b308b2a0613e210c1f7b068dfc6a7589f1ad2afb..4703fe4dbd9a7b6c192ce3e86d0c5bceada460f1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     O32 interface for the 64 (or N32) ABI.
  *
- *     Copyright (C) 2002  Maciej W. Rozycki
+ *     Copyright (C) 2002, 2014  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
 #include <asm/asm.h>
 #include <asm/regdef.h>
 
+/* O32 register size.  */
+#define O32_SZREG      4
 /* Maximum number of arguments supported.  Must be even!  */
 #define O32_ARGC       32
-/* Number of static registers we save. */
+/* Number of static registers we save.  */
 #define O32_STATC      11
-/* Frame size for static register  */
-#define O32_FRAMESZ    (SZREG * O32_STATC)
-/* Frame size on new stack */
-#define O32_FRAMESZ_NEW (SZREG + 4 * O32_ARGC)
+/* Argument area frame size.  */
+#define O32_ARGSZ      (O32_SZREG * O32_ARGC)
+/* Static register save area frame size.  */
+#define O32_STATSZ     (SZREG * O32_STATC)
+/* Stack pointer register save area frame size.  */
+#define O32_SPSZ       SZREG
+/* Combined area frame size.  */
+#define O32_FRAMESZ    (O32_ARGSZ + O32_SPSZ + O32_STATSZ)
+/* Switched stack frame size.  */
+#define O32_NFRAMESZ   (O32_ARGSZ + O32_SPSZ)
 
                .text
 
 /*
  * O32 function call dispatcher, for interfacing 32-bit ROM routines.
  *
- * The standard 64 (N32) calling sequence is supported, with a0
- * holding a function pointer, a1 a new stack pointer, a2-a7 -- its
- * first six arguments and the stack -- remaining ones (up to O32_ARGC,
- * including a2-a7). Static registers, gp and fp are preserved, v0 holds
- * a result. This code relies on the called o32 function for sp and ra
- * restoration and this dispatcher has to be placed in a KSEGx (or KUSEG)
- * address space.  Any pointers passed have to point to addresses within
- * one of these spaces as well.
+ * The standard 64 (N32) calling sequence is supported, with a0 holding
+ * a function pointer, a1 a pointer to the new stack to call the
+ * function with or 0 if no stack switching is requested, a2-a7 -- the
+ * function call's first six arguments, and the stack -- the remaining
+ * arguments (up to O32_ARGC, including a2-a7).  Static registers, gp
+ * and fp are preserved, v0 holds the result.  This code relies on the
+ * called o32 function for sp and ra restoration and this dispatcher has
+ * to be placed in a KSEGx (or KUSEG) address space.  Any pointers
+ * passed have to point to addresses within one of these spaces as well.
  */
 NESTED(call_o32, O32_FRAMESZ, ra)
                REG_SUBU        sp,O32_FRAMESZ
@@ -51,32 +60,36 @@ NESTED(call_o32, O32_FRAMESZ, ra)
                REG_S           s0,O32_FRAMESZ-11*SZREG(sp)
 
                move            jp,a0
-               REG_SUBU        s0,a1,O32_FRAMESZ_NEW
-               REG_S           sp,O32_FRAMESZ_NEW-1*SZREG(s0)
+
+               move            fp,sp
+               beqz            a1,0f
+               REG_SUBU        fp,a1,O32_NFRAMESZ
+0:
+               REG_S           sp,O32_NFRAMESZ-1*SZREG(fp)
 
                sll             a0,a2,zero
                sll             a1,a3,zero
                sll             a2,a4,zero
                sll             a3,a5,zero
-               sw              a6,0x10(s0)
-               sw              a7,0x14(s0)
+               sw              a6,4*O32_SZREG(fp)
+               sw              a7,5*O32_SZREG(fp)
 
                PTR_LA          t0,O32_FRAMESZ(sp)
-               PTR_LA          t1,0x18(s0)
+               PTR_LA          t1,6*O32_SZREG(fp)
                li              t2,O32_ARGC-6
 1:
                lw              t3,(t0)
                REG_ADDU        t0,SZREG
                sw              t3,(t1)
                REG_SUBU        t2,1
-               REG_ADDU        t1,4
+               REG_ADDU        t1,O32_SZREG
                bnez            t2,1b
 
-               move            sp,s0
+               move            sp,fp
 
                jalr            jp
 
-               REG_L           sp,O32_FRAMESZ_NEW-1*SZREG(sp)
+               REG_L           sp,O32_NFRAMESZ-1*SZREG(sp)
 
                REG_L           s0,O32_FRAMESZ-11*SZREG(sp)
                REG_L           s1,O32_FRAMESZ-10*SZREG(sp)
index 2c2cb182af4edd8673dc54c00c39aded85a6ed30..6aa264b9856ac99b71b88d54fae19cea27d782de 100644 (file)
@@ -40,7 +40,8 @@
 
 #ifdef CONFIG_64BIT
 
-static u8 o32_stk[16384];
+/* O32 stack has to be 8-byte aligned. */
+static u64 o32_stk[4096];
 #define O32_STK          &o32_stk[sizeof(o32_stk)]
 
 #define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
index e28a3e0eb3cb6407b4ad6d6ac649e20a876ab69d..0171ffc80eb01e51bd58ec8ecf2e71e2696cee36 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _ASM_BRANCH_H
 #define _ASM_BRANCH_H
 
+#include <asm/cpu-features.h>
+#include <asm/mipsregs.h>
 #include <asm/ptrace.h>
 #include <asm/inst.h>
 
@@ -18,12 +20,40 @@ extern int __compute_return_epc_for_insn(struct pt_regs *regs,
 extern int __microMIPS_compute_return_epc(struct pt_regs *regs);
 extern int __MIPS16e_compute_return_epc(struct pt_regs *regs);
 
+/*
+ * microMIPS bitfields
+ */
+#define MM_POOL32A_MINOR_MASK  0x3f
+#define MM_POOL32A_MINOR_SHIFT 0x6
+#define MM_MIPS32_COND_FC      0x30
+
+extern int __mm_isBranchInstr(struct pt_regs *regs,
+       const struct mm_decoded_insn * const dec_insn, unsigned long *contpc);
+
+static inline int mm_isBranchInstr(struct pt_regs *regs,
+       const struct mm_decoded_insn * const dec_insn, unsigned long *contpc)
+{
+       if (!cpu_has_mmips)
+               return 0;
+
+       return __mm_isBranchInstr(regs, dec_insn, contpc);
+}
 
 static inline int delay_slot(struct pt_regs *regs)
 {
        return regs->cp0_cause & CAUSEF_BD;
 }
 
+static inline void clear_delay_slot(struct pt_regs *regs)
+{
+       regs->cp0_cause &= ~CAUSEF_BD;
+}
+
+static inline void set_delay_slot(struct pt_regs *regs)
+{
+       regs->cp0_cause |= CAUSEF_BD;
+}
+
 static inline unsigned long exception_epc(struct pt_regs *regs)
 {
        if (likely(!delay_slot(regs)))
index f56cc975b92f8522ca37e344a9e0146ba6f80bf1..f75dd70555081f2eb1c19cff3546914a218f5eb9 100644 (file)
 /*
  * Shortcuts ...
  */
+#define cpu_has_mips_2_3_4_5   (cpu_has_mips_2 | cpu_has_mips_3_4_5)
+#define cpu_has_mips_3_4_5     (cpu_has_mips_3 | cpu_has_mips_4_5)
+#define cpu_has_mips_4_5       (cpu_has_mips_4 | cpu_has_mips_5)
+
+#define cpu_has_mips_2_3_4_5_r (cpu_has_mips_2 | cpu_has_mips_3_4_5_r)
+#define cpu_has_mips_3_4_5_r   (cpu_has_mips_3 | cpu_has_mips_4_5_r)
+#define cpu_has_mips_4_5_r     (cpu_has_mips_4 | cpu_has_mips_5_r)
+#define cpu_has_mips_5_r       (cpu_has_mips_5 | cpu_has_mips_r)
+
+#define cpu_has_mips_4_5_r2    (cpu_has_mips_4_5 | cpu_has_mips_r2)
+
 #define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2)
 #define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2)
 #define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1)
index c0ead63138453c04d3b20918fbcfb1e1c02c5c3c..b59a2103b61a3f64efd75b29f034e8208c155012 100644 (file)
@@ -113,31 +113,31 @@ extern int (*__pmax_close)(int);
 #define __DEC_PROM_O32(fun, arg) fun arg __asm__(#fun); \
                                 __asm__(#fun " = call_o32")
 
-int __DEC_PROM_O32(_rex_bootinit, (int (*)(void)));
-int __DEC_PROM_O32(_rex_bootread, (int (*)(void)));
-int __DEC_PROM_O32(_rex_getbitmap, (int (*)(memmap *), memmap *));
+int __DEC_PROM_O32(_rex_bootinit, (int (*)(void), void *));
+int __DEC_PROM_O32(_rex_bootread, (int (*)(void), void *));
+int __DEC_PROM_O32(_rex_getbitmap, (int (*)(memmap *), void *, memmap *));
 unsigned long *__DEC_PROM_O32(_rex_slot_address,
-                            (unsigned long *(*)(int), int));
-void *__DEC_PROM_O32(_rex_gettcinfo, (void *(*)(void)));
-int __DEC_PROM_O32(_rex_getsysid, (int (*)(void)));
-void __DEC_PROM_O32(_rex_clear_cache, (void (*)(void)));
-
-int __DEC_PROM_O32(_prom_getchar, (int (*)(void)));
-char *__DEC_PROM_O32(_prom_getenv, (char *(*)(char *), char *));
-int __DEC_PROM_O32(_prom_printf, (int (*)(char *, ...), char *, ...));
-
-
-#define rex_bootinit()         _rex_bootinit(__rex_bootinit)
-#define rex_bootread()         _rex_bootread(__rex_bootread)
-#define rex_getbitmap(x)       _rex_getbitmap(__rex_getbitmap, x)
-#define rex_slot_address(x)    _rex_slot_address(__rex_slot_address, x)
-#define rex_gettcinfo()                _rex_gettcinfo(__rex_gettcinfo)
-#define rex_getsysid()         _rex_getsysid(__rex_getsysid)
-#define rex_clear_cache()      _rex_clear_cache(__rex_clear_cache)
-
-#define prom_getchar()         _prom_getchar(__prom_getchar)
-#define prom_getenv(x)         _prom_getenv(__prom_getenv, x)
-#define prom_printf(x...)      _prom_printf(__prom_printf, x)
+                            (unsigned long *(*)(int), void *, int));
+void *__DEC_PROM_O32(_rex_gettcinfo, (void *(*)(void), void *));
+int __DEC_PROM_O32(_rex_getsysid, (int (*)(void), void *));
+void __DEC_PROM_O32(_rex_clear_cache, (void (*)(void), void *));
+
+int __DEC_PROM_O32(_prom_getchar, (int (*)(void), void *));
+char *__DEC_PROM_O32(_prom_getenv, (char *(*)(char *), void *, char *));
+int __DEC_PROM_O32(_prom_printf, (int (*)(char *, ...), void *, char *, ...));
+
+
+#define rex_bootinit()         _rex_bootinit(__rex_bootinit, NULL)
+#define rex_bootread()         _rex_bootread(__rex_bootread, NULL)
+#define rex_getbitmap(x)       _rex_getbitmap(__rex_getbitmap, NULL, x)
+#define rex_slot_address(x)    _rex_slot_address(__rex_slot_address, NULL, x)
+#define rex_gettcinfo()                _rex_gettcinfo(__rex_gettcinfo, NULL)
+#define rex_getsysid()         _rex_getsysid(__rex_getsysid, NULL)
+#define rex_clear_cache()      _rex_clear_cache(__rex_clear_cache, NULL)
+
+#define prom_getchar()         _prom_getchar(__prom_getchar, NULL)
+#define prom_getenv(x)         _prom_getenv(__prom_getenv, NULL, x)
+#define prom_printf(x...)      _prom_printf(__prom_printf, NULL, x)
 
 #else /* !CONFIG_64BIT */
 
index 4d86b72750c701701f597387cce73b2a274f5bbf..a939574f829387c800b4b57de09f94b00c8ef745 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/mipsregs.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <asm/fpu_emulator.h>
 #include <asm/hazards.h>
 #include <asm/processor.h>
 #include <asm/current.h>
@@ -28,7 +29,6 @@
 struct sigcontext;
 struct sigcontext32;
 
-extern void fpu_emulator_init_fpu(void);
 extern void _init_fpu(void);
 extern void _save_fp(struct task_struct *);
 extern void _restore_fp(struct task_struct *);
@@ -156,15 +156,16 @@ static inline int init_fpu(void)
        int ret = 0;
 
        preempt_disable();
+
        if (cpu_has_fpu) {
                ret = __own_fpu();
                if (!ret)
                        _init_fpu();
-       } else {
+       } else
                fpu_emulator_init_fpu();
-       }
 
        preempt_enable();
+
        return ret;
 }
 
index 2abb587d5ab40fd41aa950d1987d5f854f60e531..0a7e76d4ba67a8fd94994e3b4389e69614d35d9e 100644 (file)
 #ifndef _ASM_FPU_EMULATOR_H
 #define _ASM_FPU_EMULATOR_H
 
+#include <linux/sched.h>
 #include <asm/break.h>
+#include <asm/thread_info.h>
 #include <asm/inst.h>
 #include <asm/local.h>
+#include <asm/processor.h>
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -58,8 +61,6 @@ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
                                    struct mips_fpu_struct *ctx, int has_fpu,
                                    void *__user *fault_addr);
 int process_fpemu_return(int sig, void __user *fault_addr);
-int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
-                    unsigned long *contpc);
 
 /*
  * Instruction inserted following the badinst to further tag the sequence
@@ -71,4 +72,19 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
  */
 #define BREAK_MATH (0x0000000d | (BRK_MEMU << 16))
 
+#define SIGNALLING_NAN 0x7ff800007ff80000LL
+
+static inline void fpu_emulator_init_fpu(void)
+{
+       struct task_struct *t = current;
+       int i;
+
+       t->thread.fpu.fcr31 = 0;
+
+       for (i = 0; i < 32; i++)
+               set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
+}
+
+extern int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr);
+
 #endif /* _ASM_FPU_EMULATOR_H */
index 1bcb6421205e3d92913a93f7dcdb04c726c0f447..1dfe47453ea41322ab5a971e64d6c9203adefad8 100644 (file)
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
 
+#define cpu_has_mips_2         1
+#define cpu_has_mips_3         1
+#define cpu_has_mips_5         0
+
 #define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
 #define cpu_has_mips64r1       0
index 509cd58280444d3f0c6da634dde6d007ba86fca2..14ecc5313d2d3238e4cf85248f0abe729d3f26c1 100644 (file)
@@ -22,8 +22,6 @@ enum jz4740_dma_request_type {
        JZ4740_DMA_TYPE_UART_RECEIVE    = 21,
        JZ4740_DMA_TYPE_SPI_TRANSMIT    = 22,
        JZ4740_DMA_TYPE_SPI_RECEIVE     = 23,
-       JZ4740_DMA_TYPE_AIC_TRANSMIT    = 24,
-       JZ4740_DMA_TYPE_AIC_RECEIVE     = 25,
        JZ4740_DMA_TYPE_MMC_TRANSMIT    = 26,
        JZ4740_DMA_TYPE_MMC_RECEIVE     = 27,
        JZ4740_DMA_TYPE_TCU             = 28,
index 3e025b5311db72306be7890c25f88737649de3d2..2e48a680426314576d507e768927a4140a87ae06 100644 (file)
 #ifndef __ASSEMBLY__
 
 /*
- * Macros for handling the ISA mode bit for microMIPS.
+ * Macros for handling the ISA mode bit for MIPS16 and microMIPS.
  */
+#if defined(CONFIG_SYS_SUPPORTS_MIPS16) || defined(SYS_SUPPORTS_MICROMIPS)
 #define get_isa16_mode(x)              ((x) & 0x1)
 #define msk_isa16_mode(x)              ((x) & ~0x1)
 #define set_isa16_mode(x)              do { (x) |= 0x1; } while(0)
+#else
+#define get_isa16_mode(x)              0
+#define msk_isa16_mode(x)              (x)
+#define set_isa16_mode(x)              do { } while(0)
+#endif
 
 /*
  * microMIPS instructions can be 16-bit or 32-bit in length. This
diff --git a/arch/mips/include/asm/rm9k-ocd.h b/arch/mips/include/asm/rm9k-ocd.h
deleted file mode 100644 (file)
index b0b80d9..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  Copyright (C) 2004 by Basler Vision Technologies AG
- *  Author: Thomas Koeller <thomas.koeller@baslerweb.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
- */
-
-#if !defined(_ASM_RM9K_OCD_H)
-#define _ASM_RM9K_OCD_H
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-extern volatile void __iomem * const ocd_base;
-extern volatile void __iomem * const titan_base;
-
-#define ocd_addr(__x__)                (ocd_base + (__x__))
-#define titan_addr(__x__)      (titan_base + (__x__))
-#define scram_addr(__x__)      (scram_base + (__x__))
-
-/* OCD register access */
-#define ocd_readl(__offs__) __raw_readl(ocd_addr(__offs__))
-#define ocd_readw(__offs__) __raw_readw(ocd_addr(__offs__))
-#define ocd_readb(__offs__) __raw_readb(ocd_addr(__offs__))
-#define ocd_writel(__val__, __offs__) \
-       __raw_writel((__val__), ocd_addr(__offs__))
-#define ocd_writew(__val__, __offs__) \
-       __raw_writew((__val__), ocd_addr(__offs__))
-#define ocd_writeb(__val__, __offs__) \
-       __raw_writeb((__val__), ocd_addr(__offs__))
-
-/* TITAN register access - 32 bit-wide only */
-#define titan_readl(__offs__) __raw_readl(titan_addr(__offs__))
-#define titan_writel(__val__, __offs__) \
-       __raw_writel((__val__), titan_addr(__offs__))
-
-/* Protect access to shared TITAN registers */
-extern spinlock_t titan_lock;
-extern int titan_irqflags;
-#define lock_titan_regs() spin_lock_irqsave(&titan_lock, titan_irqflags)
-#define unlock_titan_regs() spin_unlock_irqrestore(&titan_lock, titan_irqflags)
-
-#endif /* !defined(_ASM_RM9K_OCD_H) */
index be7196eacb8890a1875123a6473ee620d65f5514..96fe7395ed8dc8df6d2675bf31626b45133c15e4 100644 (file)
@@ -4,6 +4,7 @@ include include/uapi/asm-generic/Kbuild.asm
 generic-y += auxvec.h
 generic-y += ipcbuf.h
 
+header-y += bitfield.h
 header-y += bitsperlong.h
 header-y += break.h
 header-y += byteorder.h
diff --git a/arch/mips/include/uapi/asm/bitfield.h b/arch/mips/include/uapi/asm/bitfield.h
new file mode 100644 (file)
index 0000000..ad98613
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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) 2014 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __UAPI_ASM_BITFIELD_H
+#define __UAPI_ASM_BITFIELD_H
+
+/*
+ *  * Damn ...  bitfields depend from byteorder :-(
+ *   */
+#ifdef __MIPSEB__
+#define __BITFIELD_FIELD(field, more)                                  \
+       field;                                                          \
+       more
+
+#elif defined(__MIPSEL__)
+
+#define __BITFIELD_FIELD(field, more)                                  \
+       more                                                            \
+       field;
+
+#else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */
+#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
+#endif
+
+#endif /* __UAPI_ASM_BITFIELD_H */
index df6e775f3fef524e8d049c24433eff06dade0fd7..fce8367da245eb9c8450e315804855df5123a8f4 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _UAPI_ASM_INST_H
 #define _UAPI_ASM_INST_H
 
+#include <asm/bitfield.h>
+
 /*
  * Major opcodes; before MIPS IV cop1x was called cop3.
  */
@@ -480,131 +482,113 @@ enum MIPS6e_i8_func {
  */
 #define MM_NOP16       0x0c00
 
-/*
- * Damn ...  bitfields depend from byteorder :-(
- */
-#ifdef __MIPSEB__
-#define BITFIELD_FIELD(field, more)                                    \
-       field;                                                          \
-       more
-
-#elif defined(__MIPSEL__)
-
-#define BITFIELD_FIELD(field, more)                                    \
-       more                                                            \
-       field;
-
-#else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */
-#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
-#endif
-
 struct j_format {
-       BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */
-       BITFIELD_FIELD(unsigned int target : 26,
+       __BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */
+       __BITFIELD_FIELD(unsigned int target : 26,
        ;))
 };
 
 struct i_format {                      /* signed immediate format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(signed int simmediate : 16,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(signed int simmediate : 16,
        ;))))
 };
 
 struct u_format {                      /* unsigned immediate format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int uimmediate : 16,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int uimmediate : 16,
        ;))))
 };
 
 struct c_format {                      /* Cache (>= R6000) format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(unsigned int c_op : 3,
-       BITFIELD_FIELD(unsigned int cache : 2,
-       BITFIELD_FIELD(unsigned int simmediate : 16,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int c_op : 3,
+       __BITFIELD_FIELD(unsigned int cache : 2,
+       __BITFIELD_FIELD(unsigned int simmediate : 16,
        ;)))))
 };
 
 struct r_format {                      /* Register format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int rd : 5,
-       BITFIELD_FIELD(unsigned int re : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int re : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct p_format {              /* Performance counter format (R10000) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int rd : 5,
-       BITFIELD_FIELD(unsigned int re : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int re : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct f_format {                      /* FPU register format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int : 1,
-       BITFIELD_FIELD(unsigned int fmt : 4,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int rd : 5,
-       BITFIELD_FIELD(unsigned int re : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int : 1,
+       __BITFIELD_FIELD(unsigned int fmt : 4,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int re : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;)))))))
 };
 
 struct ma_format {             /* FPU multiply and add format (MIPS IV) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int fr : 5,
-       BITFIELD_FIELD(unsigned int ft : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int func : 4,
-       BITFIELD_FIELD(unsigned int fmt : 2,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int fr : 5,
+       __BITFIELD_FIELD(unsigned int ft : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int func : 4,
+       __BITFIELD_FIELD(unsigned int fmt : 2,
        ;)))))))
 };
 
 struct b_format {                      /* BREAK and SYSCALL */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int code : 20,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int code : 20,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;)))
 };
 
 struct ps_format {                     /* MIPS-3D / paired single format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(unsigned int ft : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int ft : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct v_format {                              /* MDMX vector format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int sel : 4,
-       BITFIELD_FIELD(unsigned int fmt : 1,
-       BITFIELD_FIELD(unsigned int vt : 5,
-       BITFIELD_FIELD(unsigned int vs : 5,
-       BITFIELD_FIELD(unsigned int vd : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int sel : 4,
+       __BITFIELD_FIELD(unsigned int fmt : 1,
+       __BITFIELD_FIELD(unsigned int vt : 5,
+       __BITFIELD_FIELD(unsigned int vs : 5,
+       __BITFIELD_FIELD(unsigned int vd : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;)))))))
 };
 
 struct spec3_format {   /* SPEC3 */
-       BITFIELD_FIELD(unsigned int opcode:6,
-       BITFIELD_FIELD(unsigned int rs:5,
-       BITFIELD_FIELD(unsigned int rt:5,
-       BITFIELD_FIELD(signed int simmediate:9,
-       BITFIELD_FIELD(unsigned int func:7,
+       __BITFIELD_FIELD(unsigned int opcode:6,
+       __BITFIELD_FIELD(unsigned int rs:5,
+       __BITFIELD_FIELD(unsigned int rt:5,
+       __BITFIELD_FIELD(signed int simmediate:9,
+       __BITFIELD_FIELD(unsigned int func:7,
        ;)))))
 };
 
@@ -616,141 +600,141 @@ struct spec3_format {   /* SPEC3 */
  *     if it is MIPS32 instruction re-encoded for use in the microMIPS ASE.
  */
 struct fb_format {             /* FPU branch format (MIPS32) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int bc : 5,
-       BITFIELD_FIELD(unsigned int cc : 3,
-       BITFIELD_FIELD(unsigned int flag : 2,
-       BITFIELD_FIELD(signed int simmediate : 16,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int bc : 5,
+       __BITFIELD_FIELD(unsigned int cc : 3,
+       __BITFIELD_FIELD(unsigned int flag : 2,
+       __BITFIELD_FIELD(signed int simmediate : 16,
        ;)))))
 };
 
 struct fp0_format {            /* FPU multiply and add format (MIPS32) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int fmt : 5,
-       BITFIELD_FIELD(unsigned int ft : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int fmt : 5,
+       __BITFIELD_FIELD(unsigned int ft : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct mm_fp0_format {         /* FPU multipy and add format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int ft : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int fmt : 3,
-       BITFIELD_FIELD(unsigned int op : 2,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int ft : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int fmt : 3,
+       __BITFIELD_FIELD(unsigned int op : 2,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;)))))))
 };
 
 struct fp1_format {            /* FPU mfc1 and cfc1 format (MIPS32) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int op : 5,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int op : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct mm_fp1_format {         /* FPU mfc1 and cfc1 format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fmt : 2,
-       BITFIELD_FIELD(unsigned int op : 8,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fmt : 2,
+       __BITFIELD_FIELD(unsigned int op : 8,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct mm_fp2_format {         /* FPU movt and movf format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int cc : 3,
-       BITFIELD_FIELD(unsigned int zero : 2,
-       BITFIELD_FIELD(unsigned int fmt : 2,
-       BITFIELD_FIELD(unsigned int op : 3,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int cc : 3,
+       __BITFIELD_FIELD(unsigned int zero : 2,
+       __BITFIELD_FIELD(unsigned int fmt : 2,
+       __BITFIELD_FIELD(unsigned int op : 3,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))))
 };
 
 struct mm_fp3_format {         /* FPU abs and neg format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fmt : 3,
-       BITFIELD_FIELD(unsigned int op : 7,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fmt : 3,
+       __BITFIELD_FIELD(unsigned int op : 7,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct mm_fp4_format {         /* FPU c.cond format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int cc : 3,
-       BITFIELD_FIELD(unsigned int fmt : 3,
-       BITFIELD_FIELD(unsigned int cond : 4,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int cc : 3,
+       __BITFIELD_FIELD(unsigned int fmt : 3,
+       __BITFIELD_FIELD(unsigned int cond : 4,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;)))))))
 };
 
 struct mm_fp5_format {         /* FPU lwxc1 and swxc1 format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int index : 5,
-       BITFIELD_FIELD(unsigned int base : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int op : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int index : 5,
+       __BITFIELD_FIELD(unsigned int base : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int op : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct fp6_format {            /* FPU madd and msub format (MIPS IV) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int fr : 5,
-       BITFIELD_FIELD(unsigned int ft : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int fr : 5,
+       __BITFIELD_FIELD(unsigned int ft : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct mm_fp6_format {         /* FPU madd and msub format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int ft : 5,
-       BITFIELD_FIELD(unsigned int fs : 5,
-       BITFIELD_FIELD(unsigned int fd : 5,
-       BITFIELD_FIELD(unsigned int fr : 5,
-       BITFIELD_FIELD(unsigned int func : 6,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int ft : 5,
+       __BITFIELD_FIELD(unsigned int fs : 5,
+       __BITFIELD_FIELD(unsigned int fd : 5,
+       __BITFIELD_FIELD(unsigned int fr : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
        ;))))))
 };
 
 struct mm_i_format {           /* Immediate format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(unsigned int rs : 5,
-       BITFIELD_FIELD(signed int simmediate : 16,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(signed int simmediate : 16,
        ;))))
 };
 
 struct mm_m_format {           /* Multi-word load/store format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rd : 5,
-       BITFIELD_FIELD(unsigned int base : 5,
-       BITFIELD_FIELD(unsigned int func : 4,
-       BITFIELD_FIELD(signed int simmediate : 12,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int base : 5,
+       __BITFIELD_FIELD(unsigned int func : 4,
+       __BITFIELD_FIELD(signed int simmediate : 12,
        ;)))))
 };
 
 struct mm_x_format {           /* Scaled indexed load format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int index : 5,
-       BITFIELD_FIELD(unsigned int base : 5,
-       BITFIELD_FIELD(unsigned int rd : 5,
-       BITFIELD_FIELD(unsigned int func : 11,
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int index : 5,
+       __BITFIELD_FIELD(unsigned int base : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int func : 11,
        ;)))))
 };
 
@@ -758,51 +742,51 @@ struct mm_x_format {              /* Scaled indexed load format (microMIPS) */
  * microMIPS instruction formats (16-bit length)
  */
 struct mm_b0_format {          /* Unconditional branch format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(signed int simmediate : 10,
-       BITFIELD_FIELD(unsigned int : 16, /* Ignored */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(signed int simmediate : 10,
+       __BITFIELD_FIELD(unsigned int : 16, /* Ignored */
        ;)))
 };
 
 struct mm_b1_format {          /* Conditional branch format (microMIPS) */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rs : 3,
-       BITFIELD_FIELD(signed int simmediate : 7,
-       BITFIELD_FIELD(unsigned int : 16, /* Ignored */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 3,
+       __BITFIELD_FIELD(signed int simmediate : 7,
+       __BITFIELD_FIELD(unsigned int : 16, /* Ignored */
        ;))))
 };
 
 struct mm16_m_format {         /* Multi-word load/store format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int func : 4,
-       BITFIELD_FIELD(unsigned int rlist : 2,
-       BITFIELD_FIELD(unsigned int imm : 4,
-       BITFIELD_FIELD(unsigned int : 16, /* Ignored */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int func : 4,
+       __BITFIELD_FIELD(unsigned int rlist : 2,
+       __BITFIELD_FIELD(unsigned int imm : 4,
+       __BITFIELD_FIELD(unsigned int : 16, /* Ignored */
        ;)))))
 };
 
 struct mm16_rb_format {                /* Signed immediate format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 3,
-       BITFIELD_FIELD(unsigned int base : 3,
-       BITFIELD_FIELD(signed int simmediate : 4,
-       BITFIELD_FIELD(unsigned int : 16, /* Ignored */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 3,
+       __BITFIELD_FIELD(unsigned int base : 3,
+       __BITFIELD_FIELD(signed int simmediate : 4,
+       __BITFIELD_FIELD(unsigned int : 16, /* Ignored */
        ;)))))
 };
 
 struct mm16_r3_format {                /* Load from global pointer format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 3,
-       BITFIELD_FIELD(signed int simmediate : 7,
-       BITFIELD_FIELD(unsigned int : 16, /* Ignored */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 3,
+       __BITFIELD_FIELD(signed int simmediate : 7,
+       __BITFIELD_FIELD(unsigned int : 16, /* Ignored */
        ;))))
 };
 
 struct mm16_r5_format {                /* Load/store from stack pointer format */
-       BITFIELD_FIELD(unsigned int opcode : 6,
-       BITFIELD_FIELD(unsigned int rt : 5,
-       BITFIELD_FIELD(signed int simmediate : 5,
-       BITFIELD_FIELD(unsigned int : 16, /* Ignored */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(signed int simmediate : 5,
+       __BITFIELD_FIELD(unsigned int : 16, /* Ignored */
        ;))))
 };
 
@@ -810,57 +794,57 @@ struct mm16_r5_format {           /* Load/store from stack pointer format */
  * MIPS16e instruction formats (16-bit length)
  */
 struct m16e_rr {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int rx : 3,
-       BITFIELD_FIELD(unsigned int nd : 1,
-       BITFIELD_FIELD(unsigned int l : 1,
-       BITFIELD_FIELD(unsigned int ra : 1,
-       BITFIELD_FIELD(unsigned int func : 5,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int rx : 3,
+       __BITFIELD_FIELD(unsigned int nd : 1,
+       __BITFIELD_FIELD(unsigned int l : 1,
+       __BITFIELD_FIELD(unsigned int ra : 1,
+       __BITFIELD_FIELD(unsigned int func : 5,
        ;))))))
 };
 
 struct m16e_jal {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int x : 1,
-       BITFIELD_FIELD(unsigned int imm20_16 : 5,
-       BITFIELD_FIELD(signed int imm25_21 : 5,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int x : 1,
+       __BITFIELD_FIELD(unsigned int imm20_16 : 5,
+       __BITFIELD_FIELD(signed int imm25_21 : 5,
        ;))))
 };
 
 struct m16e_i64 {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int func : 3,
-       BITFIELD_FIELD(unsigned int imm : 8,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int func : 3,
+       __BITFIELD_FIELD(unsigned int imm : 8,
        ;)))
 };
 
 struct m16e_ri64 {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int func : 3,
-       BITFIELD_FIELD(unsigned int ry : 3,
-       BITFIELD_FIELD(unsigned int imm : 5,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int func : 3,
+       __BITFIELD_FIELD(unsigned int ry : 3,
+       __BITFIELD_FIELD(unsigned int imm : 5,
        ;))))
 };
 
 struct m16e_ri {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int rx : 3,
-       BITFIELD_FIELD(unsigned int imm : 8,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int rx : 3,
+       __BITFIELD_FIELD(unsigned int imm : 8,
        ;)))
 };
 
 struct m16e_rri {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int rx : 3,
-       BITFIELD_FIELD(unsigned int ry : 3,
-       BITFIELD_FIELD(unsigned int imm : 5,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int rx : 3,
+       __BITFIELD_FIELD(unsigned int ry : 3,
+       __BITFIELD_FIELD(unsigned int imm : 5,
        ;))))
 };
 
 struct m16e_i8 {
-       BITFIELD_FIELD(unsigned int opcode : 5,
-       BITFIELD_FIELD(unsigned int func : 3,
-       BITFIELD_FIELD(unsigned int imm : 8,
+       __BITFIELD_FIELD(unsigned int opcode : 5,
+       __BITFIELD_FIELD(unsigned int func : 3,
+       __BITFIELD_FIELD(unsigned int imm : 8,
        ;)))
 };
 
index c01900e5d0788633c44c28558fe3cae80c42dd49..088e92a79ae600eedea11884018e24046acadcb4 100644 (file)
@@ -425,6 +425,15 @@ static struct platform_device qi_lb60_audio_device = {
        .id = -1,
 };
 
+static struct gpiod_lookup_table qi_lb60_audio_gpio_table = {
+       .dev_id = "qi-lb60-audio",
+       .table = {
+               GPIO_LOOKUP("Bank B", 29, "snd", 0),
+               GPIO_LOOKUP("Bank D", 4, "amp", 0),
+               { },
+       },
+};
+
 static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_udc_device,
        &jz4740_udc_xceiv_device,
@@ -461,6 +470,8 @@ static int __init qi_lb60_init_platform_devices(void)
        jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
        jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
 
+       gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
+
        jz4740_serial_device_register();
 
        spi_register_board_info(qi_lb60_spi_board_info,
index 4d78bf445a9cd2e7397898ac32e24b4ee1bac8dd..8af8b7769e597ddc13722363d5c266b70691fa64 100644 (file)
@@ -48,6 +48,202 @@ int __isa_exception_epc(struct pt_regs *regs)
        return epc;
 }
 
+/* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */
+static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7};
+
+int __mm_isBranchInstr(struct pt_regs *regs,
+       const struct mm_decoded_insn * const dec_insn, unsigned long *contpc)
+{
+       union mips_instruction insn = (union mips_instruction)dec_insn->insn;
+       int bc_false = 0;
+       unsigned int fcr31;
+       unsigned int bit;
+
+       if (!cpu_has_mmips)
+               return 0;
+
+       switch (insn.mm_i_format.opcode) {
+       case mm_pool32a_op:
+               if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) ==
+                   mm_pool32axf_op) {
+                       switch (insn.mm_i_format.simmediate >>
+                               MM_POOL32A_MINOR_SHIFT) {
+                       case mm_jalr_op:
+                       case mm_jalrhb_op:
+                       case mm_jalrs_op:
+                       case mm_jalrshb_op:
+                               if (insn.mm_i_format.rt != 0)   /* Not mm_jr */
+                                       regs->regs[insn.mm_i_format.rt] =
+                                               regs->cp0_epc +
+                                               dec_insn->pc_inc +
+                                               dec_insn->next_pc_inc;
+                               *contpc = regs->regs[insn.mm_i_format.rs];
+                               return 1;
+                       }
+               }
+               break;
+       case mm_pool32i_op:
+               switch (insn.mm_i_format.rt) {
+               case mm_bltzals_op:
+               case mm_bltzal_op:
+                       regs->regs[31] = regs->cp0_epc +
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
+                       /* Fall through */
+               case mm_bltz_op:
+                       if ((long)regs->regs[insn.mm_i_format.rs] < 0)
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       (insn.mm_i_format.simmediate << 1);
+                       else
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
+                       return 1;
+               case mm_bgezals_op:
+               case mm_bgezal_op:
+                       regs->regs[31] = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
+                       /* Fall through */
+               case mm_bgez_op:
+                       if ((long)regs->regs[insn.mm_i_format.rs] >= 0)
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       (insn.mm_i_format.simmediate << 1);
+                       else
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
+                       return 1;
+               case mm_blez_op:
+                       if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       (insn.mm_i_format.simmediate << 1);
+                       else
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
+                       return 1;
+               case mm_bgtz_op:
+                       if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       (insn.mm_i_format.simmediate << 1);
+                       else
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
+                       return 1;
+               case mm_bc2f_op:
+               case mm_bc1f_op:
+                       bc_false = 1;
+                       /* Fall through */
+               case mm_bc2t_op:
+               case mm_bc1t_op:
+                       preempt_disable();
+                       if (is_fpu_owner())
+                               asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+                       else
+                               fcr31 = current->thread.fpu.fcr31;
+                       preempt_enable();
+
+                       if (bc_false)
+                               fcr31 = ~fcr31;
+
+                       bit = (insn.mm_i_format.rs >> 2);
+                       bit += (bit != 0);
+                       bit += 23;
+                       if (fcr31 & (1 << bit))
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc +
+                                       (insn.mm_i_format.simmediate << 1);
+                       else
+                               *contpc = regs->cp0_epc +
+                                       dec_insn->pc_inc + dec_insn->next_pc_inc;
+                       return 1;
+               }
+               break;
+       case mm_pool16c_op:
+               switch (insn.mm_i_format.rt) {
+               case mm_jalr16_op:
+               case mm_jalrs16_op:
+                       regs->regs[31] = regs->cp0_epc +
+                               dec_insn->pc_inc + dec_insn->next_pc_inc;
+                       /* Fall through */
+               case mm_jr16_op:
+                       *contpc = regs->regs[insn.mm_i_format.rs];
+                       return 1;
+               }
+               break;
+       case mm_beqz16_op:
+               if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0)
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc +
+                               (insn.mm_b1_format.simmediate << 1);
+               else
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc + dec_insn->next_pc_inc;
+               return 1;
+       case mm_bnez16_op:
+               if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0)
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc +
+                               (insn.mm_b1_format.simmediate << 1);
+               else
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc + dec_insn->next_pc_inc;
+               return 1;
+       case mm_b16_op:
+               *contpc = regs->cp0_epc + dec_insn->pc_inc +
+                        (insn.mm_b0_format.simmediate << 1);
+               return 1;
+       case mm_beq32_op:
+               if (regs->regs[insn.mm_i_format.rs] ==
+                   regs->regs[insn.mm_i_format.rt])
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc +
+                               (insn.mm_i_format.simmediate << 1);
+               else
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
+               return 1;
+       case mm_bne32_op:
+               if (regs->regs[insn.mm_i_format.rs] !=
+                   regs->regs[insn.mm_i_format.rt])
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc +
+                               (insn.mm_i_format.simmediate << 1);
+               else
+                       *contpc = regs->cp0_epc +
+                               dec_insn->pc_inc + dec_insn->next_pc_inc;
+               return 1;
+       case mm_jalx32_op:
+               regs->regs[31] = regs->cp0_epc +
+                       dec_insn->pc_inc + dec_insn->next_pc_inc;
+               *contpc = regs->cp0_epc + dec_insn->pc_inc;
+               *contpc >>= 28;
+               *contpc <<= 28;
+               *contpc |= (insn.j_format.target << 2);
+               return 1;
+       case mm_jals32_op:
+       case mm_jal32_op:
+               regs->regs[31] = regs->cp0_epc +
+                       dec_insn->pc_inc + dec_insn->next_pc_inc;
+               /* Fall through */
+       case mm_j32_op:
+               *contpc = regs->cp0_epc + dec_insn->pc_inc;
+               *contpc >>= 27;
+               *contpc <<= 27;
+               *contpc |= (insn.j_format.target << 1);
+               set_isa16_mode(*contpc);
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * Compute return address and emulate branch in microMIPS mode after an
  * exception only. It does not handle compact branches/jumps and cannot
@@ -95,7 +291,7 @@ int __microMIPS_compute_return_epc(struct pt_regs *regs)
        }
        mminsn.next_insn = word;
 
-       mm_isBranchInstr(regs, mminsn, &contpc);
+       mm_isBranchInstr(regs, &mminsn, &contpc);
 
        regs->cp0_epc = contpc;
 
index e40971b51d2f0bf47e3eb217f43c652c732e7a09..037a44d962f37e1b94251f13b054103e6cbb1ff5 100644 (file)
@@ -124,14 +124,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        seq_printf(m, "kscratch registers\t: %d\n",
                      hweight8(cpu_data[n].kscratch_mask));
        seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core);
-#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
-       if (cpu_has_mipsmt) {
-               seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
-#if defined(CONFIG_MIPS_MT_SMTC)
-               seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id);
-#endif
-       }
-#endif
+
        sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
                      cpu_has_vce ? "%u" : "not available");
        seq_printf(m, fmt, 'D', vced_count);
index 2b3517214d6d8cbdbe6a7bbc31187e1abcc893a5..27ceff224805a1dfe174afe91d2499f6955c3c27 100644 (file)
@@ -825,7 +825,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
        mminsn.next_insn = word;
 
        insn = (union mips_instruction)(mminsn.insn);
-       if (mm_isBranchInstr(regs, mminsn, &contpc))
+       if (mm_isBranchInstr(regs, &mminsn, &contpc))
                insn = (union mips_instruction)(mminsn.next_insn);
 
        /*  Parse instruction to find what to do */
index 2e4825e483882b217046caf4a847a99c3db56afe..9901237563c58922d213b9af10b9ed3c504b18e5 100644 (file)
 #define UNIT(unit)  ((unit)*NBYTES)
 
 #define ADDC(sum,reg)                                          \
+       .set    push;                                           \
+       .set    noat;                                           \
        ADD     sum, reg;                                       \
        sltu    v1, sum, reg;                                   \
        ADD     sum, v1;                                        \
+       .set    pop
 
 #define ADDC32(sum,reg)                                                \
+       .set    push;                                           \
+       .set    noat;                                           \
        addu    sum, reg;                                       \
        sltu    v1, sum, reg;                                   \
        addu    sum, v1;                                        \
+       .set    pop
 
 #define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)   \
        LOAD    _t0, (offset + UNIT(0))(src);                   \
@@ -710,6 +716,8 @@ LEAF(csum_partial)
        ADDC(sum, t2)
 .Ldone\@:
        /* fold checksum */
+       .set    push
+       .set    noat
 #ifdef USE_DOUBLE
        dsll32  v1, sum, 0
        daddu   sum, v1
@@ -732,6 +740,7 @@ LEAF(csum_partial)
        or      sum, sum, t0
 1:
 #endif
+       .set    pop
        .set reorder
        ADDC32(sum, psum)
        jr      ra
index 44713af15a62bc60ebc53ffcbc9e73ad10d87380..705cfb7c1a74e0843e40567219024882ab932ac9 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 1994 by Waldorf Electronics
  * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2007  Maciej W. Rozycki
+ * Copyright (C) 2007, 2014 Maciej W. Rozycki
  */
 #include <linux/module.h>
 #include <linux/param.h>
 #include <asm/compiler.h>
 #include <asm/war.h>
 
+#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
+#define GCC_DADDI_IMM_ASM() "I"
+#else
+#define GCC_DADDI_IMM_ASM() "r"
+#endif
+
 void __delay(unsigned long loops)
 {
        __asm__ __volatile__ (
@@ -22,13 +28,13 @@ void __delay(unsigned long loops)
        "       .align  3                                       \n"
        "1:     bnez    %0, 1b                                  \n"
 #if BITS_PER_LONG == 32
-       "       subu    %0,                                   \n"
+       "       subu    %0, %1                                  \n"
 #else
-       "       dsubu   %0,                                   \n"
+       "       dsubu   %0, %1                                  \n"
 #endif
        "       .set    reorder                                 \n"
        : "=r" (loops)
-       : "0" (loops));
+       : GCC_DADDI_IMM_ASM() (1), "0" (loops));
 }
 EXPORT_SYMBOL(__delay);
 
index d3301cd1e9a51b4c387a7f8c3d4a46e2632761e2..3c32baf8b49447a591e6e552e634eafe5be8d09e 100644 (file)
@@ -35,7 +35,6 @@ LEAF(__strncpy_from_\func\()_asm)
        bnez            v0, .Lfault\@
 
 FEXPORT(__strncpy_from_\func\()_nocheck_asm)
-       .set            noreorder
        move            t0, zero
        move            v1, a1
 .ifeqs "\func","kernel"
@@ -45,21 +44,21 @@ FEXPORT(__strncpy_from_\func\()_nocheck_asm)
 .endif
        PTR_ADDIU       v1, 1
        R10KCBARRIER(0(ra))
+       sb              v0, (a0)
        beqz            v0, 2f
-        sb             v0, (a0)
        PTR_ADDIU       t0, 1
+       PTR_ADDIU       a0, 1
        bne             t0, a2, 1b
-        PTR_ADDIU      a0, 1
 2:     PTR_ADDU        v0, a1, t0
        xor             v0, a1
        bltz            v0, .Lfault\@
-        nop
+       move            v0, t0
        jr              ra                      # return n
-        move           v0, t0
        END(__strncpy_from_\func\()_asm)
 
-.Lfault\@: jr          ra
-         li            v0, -EFAULT
+.Lfault\@:
+       li              v0, -EFAULT
+       jr              ra
 
        .section        __ex_table,"a"
        PTR             1b, .Lfault\@
index 7397be226a06a2a7d0481fac7b2dd476d4fe6d3a..603d79a95f4778e40d5ec94b78f1efa9750cd214 100644 (file)
@@ -64,7 +64,6 @@ config LEMOTE_MACH3A
        bool "Lemote Loongson 3A family machines"
        select ARCH_SPARSEMEM_ENABLE
        select GENERIC_ISA_DMA_SUPPORT_BROKEN
-       select GENERIC_HARDIRQS_NO__DO_IRQ
        select BOOT_ELF32
        select BOARD_SCACHE
        select CSRC_R4K
index e1f427f4f5f3fed4985bb370054421d7d2f91cdc..ebfb9cd71ca1b92939346071356792df63b7a2ff 100644 (file)
@@ -91,9 +91,10 @@ EXPORT_SYMBOL(clk_put);
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
+       unsigned int rate_khz = rate / 1000;
+       struct cpufreq_frequency_table *pos;
        int ret = 0;
        int regval;
-       int i;
 
        if (likely(clk->ops && clk->ops->set_rate)) {
                unsigned long flags;
@@ -106,22 +107,16 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
                propagate_rate(clk);
 
-       for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;
-            i++) {
-               if (loongson2_clockmod_table[i].frequency ==
-                   CPUFREQ_ENTRY_INVALID)
-                       continue;
-               if (rate == loongson2_clockmod_table[i].frequency)
+       cpufreq_for_each_valid_entry(pos, loongson2_clockmod_table)
+               if (rate_khz == pos->frequency)
                        break;
-       }
-       if (rate != loongson2_clockmod_table[i].frequency)
+       if (rate_khz != pos->frequency)
                return -ENOTSUPP;
 
        clk->rate = rate;
 
        regval = LOONGSON_CHIPCFG0;
-       regval = (regval & ~0x7) |
-               (loongson2_clockmod_table[i].driver_data - 1);
+       regval = (regval & ~0x7) | (pos->driver_data - 1);
        LOONGSON_CHIPCFG0 = regval;
 
        return ret;
index fbf75f635798cd99c628e3259df40a52f4293446..e23c25d0996318d543f5337abe0c4dde4cf8021d 100644 (file)
@@ -14,6 +14,7 @@ config LOONGSON1_LS1B
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_MIPS16
        select SYS_HAS_EARLY_PRINTK
        select COMMON_CLK
 
index 121a848a35945d57292c072d45c4cfe7cc0cc12f..e068c5e8a3f2f69e9a07b3333ca694b94f786c65 100644 (file)
@@ -2,10 +2,14 @@
 # Makefile for the Linux/MIPS kernel FPU emulation.
 #
 
-obj-y  := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
-          ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \
-          dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \
-          dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
-          sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
-          sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
-          dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o
+obj-y  += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o dp_div.o dp_mul.o \
+          dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o dp_tint.o \
+          dp_fint.o dp_tlong.o dp_flong.o sp_div.o sp_mul.o sp_sub.o \
+          sp_add.o sp_fdp.o sp_cmp.o sp_simple.o sp_tint.o sp_fint.o \
+          sp_tlong.o sp_flong.o dsemul.o
+
+obj-$(CONFIG_SYS_SUPPORTS_MICROMIPS)   += me-micromips.o
+
+lib-y  += ieee754d.o dp_sqrt.o sp_sqrt.o
+
+obj-$(CONFIG_DEBUG_FS) += me-debugfs.o
index 7b3c9acae6895120e751dc4efe19b7ee8a6572ea..4d784dc393cf26fc81794e47683f95b6d3f5af88 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
+ * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator
  *
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
  *  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.
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  *
  * A complete emulator for MIPS coprocessor 1 instructions.  This is
  * required for #float(switch) or #float(trap), where it catches all
  * COP1 instructions via the "CoProcessor Unusable" exception.
  *
  * More surprisingly it is also required for #float(ieee), to help out
- * the hardware fpu at the boundaries of the IEEE-754 representation
+ * the hardware FPU at the boundaries of the IEEE-754 representation
  * (denormalised values, infinities, underflow, etc).  It is made
  * quite nasty because emulation of some non-COP1 instructions is
  * required, e.g. in branch delay slots.
  *
- * Note if you know that you won't have an fpu, then you'll get much
+ * Note if you know that you won't have an FPU, then you'll get much
  * better performance by compiling with -msoft-float!
  */
 #include <linux/sched.h>
-#include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/kconfig.h>
+#include <linux/percpu-defs.h>
 #include <linux/perf_event.h>
 
+#include <asm/branch.h>
 #include <asm/inst.h>
-#include <asm/bootinfo.h>
-#include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/signal.h>
-#include <asm/mipsregs.h>
+#include <asm/uaccess.h>
+
+#include <asm/processor.h>
 #include <asm/fpu_emulator.h>
 #include <asm/fpu.h>
-#include <asm/uaccess.h>
-#include <asm/branch.h>
 
 #include "ieee754.h"
 
-/* Strap kernel emulator for full MIPS IV emulation */
-
-#ifdef __mips
-#undef __mips
-#endif
-#define __mips 4
-
 /* Function which emulates a floating point instruction. */
 
 static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
        mips_instruction);
 
-#if __mips >= 4 && __mips != 32
 static int fpux_emu(struct pt_regs *,
        struct mips_fpu_struct *, mips_instruction, void *__user *);
-#endif
-
-/* Further private data for which no space exists in mips_fpu_struct */
-
-#ifdef CONFIG_DEBUG_FS
-DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
-#endif
 
 /* Control registers */
 
@@ -82,27 +67,6 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
 /* Determine rounding mode from the RM bits of the FCSR */
 #define modeindex(v) ((v) & FPU_CSR_RM)
 
-/* microMIPS bitfields */
-#define MM_POOL32A_MINOR_MASK  0x3f
-#define MM_POOL32A_MINOR_SHIFT 0x6
-#define MM_MIPS32_COND_FC      0x30
-
-/* Convert Mips rounding mode (0..3) to IEEE library modes. */
-static const unsigned char ieee_rm[4] = {
-       [FPU_CSR_RN] = IEEE754_RN,
-       [FPU_CSR_RZ] = IEEE754_RZ,
-       [FPU_CSR_RU] = IEEE754_RU,
-       [FPU_CSR_RD] = IEEE754_RD,
-};
-/* Convert IEEE library modes to Mips rounding mode (0..3). */
-static const unsigned char mips_rm[4] = {
-       [IEEE754_RN] = FPU_CSR_RN,
-       [IEEE754_RZ] = FPU_CSR_RZ,
-       [IEEE754_RD] = FPU_CSR_RD,
-       [IEEE754_RU] = FPU_CSR_RU,
-};
-
-#if __mips >= 4
 /* convert condition code register number to csr bit */
 static const unsigned int fpucondbit[8] = {
        FPU_CSR_COND0,
@@ -114,550 +78,6 @@ static const unsigned int fpucondbit[8] = {
        FPU_CSR_COND6,
        FPU_CSR_COND7
 };
-#endif
-
-/* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */
-static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7};
-
-/* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */
-static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0};
-static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0};
-static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0};
-static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0};
-
-/*
- * This functions translates a 32-bit microMIPS instruction
- * into a 32-bit MIPS32 instruction. Returns 0 on success
- * and SIGILL otherwise.
- */
-static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
-{
-       union mips_instruction insn = *insn_ptr;
-       union mips_instruction mips32_insn = insn;
-       int func, fmt, op;
-
-       switch (insn.mm_i_format.opcode) {
-       case mm_ldc132_op:
-               mips32_insn.mm_i_format.opcode = ldc1_op;
-               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
-               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
-               break;
-       case mm_lwc132_op:
-               mips32_insn.mm_i_format.opcode = lwc1_op;
-               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
-               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
-               break;
-       case mm_sdc132_op:
-               mips32_insn.mm_i_format.opcode = sdc1_op;
-               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
-               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
-               break;
-       case mm_swc132_op:
-               mips32_insn.mm_i_format.opcode = swc1_op;
-               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
-               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
-               break;
-       case mm_pool32i_op:
-               /* NOTE: offset is << by 1 if in microMIPS mode. */
-               if ((insn.mm_i_format.rt == mm_bc1f_op) ||
-                   (insn.mm_i_format.rt == mm_bc1t_op)) {
-                       mips32_insn.fb_format.opcode = cop1_op;
-                       mips32_insn.fb_format.bc = bc_op;
-                       mips32_insn.fb_format.flag =
-                               (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0;
-               } else
-                       return SIGILL;
-               break;
-       case mm_pool32f_op:
-               switch (insn.mm_fp0_format.func) {
-               case mm_32f_01_op:
-               case mm_32f_11_op:
-               case mm_32f_02_op:
-               case mm_32f_12_op:
-               case mm_32f_41_op:
-               case mm_32f_51_op:
-               case mm_32f_42_op:
-               case mm_32f_52_op:
-                       op = insn.mm_fp0_format.func;
-                       if (op == mm_32f_01_op)
-                               func = madd_s_op;
-                       else if (op == mm_32f_11_op)
-                               func = madd_d_op;
-                       else if (op == mm_32f_02_op)
-                               func = nmadd_s_op;
-                       else if (op == mm_32f_12_op)
-                               func = nmadd_d_op;
-                       else if (op == mm_32f_41_op)
-                               func = msub_s_op;
-                       else if (op == mm_32f_51_op)
-                               func = msub_d_op;
-                       else if (op == mm_32f_42_op)
-                               func = nmsub_s_op;
-                       else
-                               func = nmsub_d_op;
-                       mips32_insn.fp6_format.opcode = cop1x_op;
-                       mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr;
-                       mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft;
-                       mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs;
-                       mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd;
-                       mips32_insn.fp6_format.func = func;
-                       break;
-               case mm_32f_10_op:
-                       func = -1;      /* Invalid */
-                       op = insn.mm_fp5_format.op & 0x7;
-                       if (op == mm_ldxc1_op)
-                               func = ldxc1_op;
-                       else if (op == mm_sdxc1_op)
-                               func = sdxc1_op;
-                       else if (op == mm_lwxc1_op)
-                               func = lwxc1_op;
-                       else if (op == mm_swxc1_op)
-                               func = swxc1_op;
-
-                       if (func != -1) {
-                               mips32_insn.r_format.opcode = cop1x_op;
-                               mips32_insn.r_format.rs =
-                                       insn.mm_fp5_format.base;
-                               mips32_insn.r_format.rt =
-                                       insn.mm_fp5_format.index;
-                               mips32_insn.r_format.rd = 0;
-                               mips32_insn.r_format.re = insn.mm_fp5_format.fd;
-                               mips32_insn.r_format.func = func;
-                       } else
-                               return SIGILL;
-                       break;
-               case mm_32f_40_op:
-                       op = -1;        /* Invalid */
-                       if (insn.mm_fp2_format.op == mm_fmovt_op)
-                               op = 1;
-                       else if (insn.mm_fp2_format.op == mm_fmovf_op)
-                               op = 0;
-                       if (op != -1) {
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt =
-                                       sdps_format[insn.mm_fp2_format.fmt];
-                               mips32_insn.fp0_format.ft =
-                                       (insn.mm_fp2_format.cc<<2) + op;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp2_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp2_format.fd;
-                               mips32_insn.fp0_format.func = fmovc_op;
-                       } else
-                               return SIGILL;
-                       break;
-               case mm_32f_60_op:
-                       func = -1;      /* Invalid */
-                       if (insn.mm_fp0_format.op == mm_fadd_op)
-                               func = fadd_op;
-                       else if (insn.mm_fp0_format.op == mm_fsub_op)
-                               func = fsub_op;
-                       else if (insn.mm_fp0_format.op == mm_fmul_op)
-                               func = fmul_op;
-                       else if (insn.mm_fp0_format.op == mm_fdiv_op)
-                               func = fdiv_op;
-                       if (func != -1) {
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt =
-                                       sdps_format[insn.mm_fp0_format.fmt];
-                               mips32_insn.fp0_format.ft =
-                                       insn.mm_fp0_format.ft;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp0_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp0_format.fd;
-                               mips32_insn.fp0_format.func = func;
-                       } else
-                               return SIGILL;
-                       break;
-               case mm_32f_70_op:
-                       func = -1;      /* Invalid */
-                       if (insn.mm_fp0_format.op == mm_fmovn_op)
-                               func = fmovn_op;
-                       else if (insn.mm_fp0_format.op == mm_fmovz_op)
-                               func = fmovz_op;
-                       if (func != -1) {
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt =
-                                       sdps_format[insn.mm_fp0_format.fmt];
-                               mips32_insn.fp0_format.ft =
-                                       insn.mm_fp0_format.ft;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp0_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp0_format.fd;
-                               mips32_insn.fp0_format.func = func;
-                       } else
-                               return SIGILL;
-                       break;
-               case mm_32f_73_op:    /* POOL32FXF */
-                       switch (insn.mm_fp1_format.op) {
-                       case mm_movf0_op:
-                       case mm_movf1_op:
-                       case mm_movt0_op:
-                       case mm_movt1_op:
-                               if ((insn.mm_fp1_format.op & 0x7f) ==
-                                   mm_movf0_op)
-                                       op = 0;
-                               else
-                                       op = 1;
-                               mips32_insn.r_format.opcode = spec_op;
-                               mips32_insn.r_format.rs = insn.mm_fp4_format.fs;
-                               mips32_insn.r_format.rt =
-                                       (insn.mm_fp4_format.cc << 2) + op;
-                               mips32_insn.r_format.rd = insn.mm_fp4_format.rt;
-                               mips32_insn.r_format.re = 0;
-                               mips32_insn.r_format.func = movc_op;
-                               break;
-                       case mm_fcvtd0_op:
-                       case mm_fcvtd1_op:
-                       case mm_fcvts0_op:
-                       case mm_fcvts1_op:
-                               if ((insn.mm_fp1_format.op & 0x7f) ==
-                                   mm_fcvtd0_op) {
-                                       func = fcvtd_op;
-                                       fmt = swl_format[insn.mm_fp3_format.fmt];
-                               } else {
-                                       func = fcvts_op;
-                                       fmt = dwl_format[insn.mm_fp3_format.fmt];
-                               }
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt = fmt;
-                               mips32_insn.fp0_format.ft = 0;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp3_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp3_format.rt;
-                               mips32_insn.fp0_format.func = func;
-                               break;
-                       case mm_fmov0_op:
-                       case mm_fmov1_op:
-                       case mm_fabs0_op:
-                       case mm_fabs1_op:
-                       case mm_fneg0_op:
-                       case mm_fneg1_op:
-                               if ((insn.mm_fp1_format.op & 0x7f) ==
-                                   mm_fmov0_op)
-                                       func = fmov_op;
-                               else if ((insn.mm_fp1_format.op & 0x7f) ==
-                                        mm_fabs0_op)
-                                       func = fabs_op;
-                               else
-                                       func = fneg_op;
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt =
-                                       sdps_format[insn.mm_fp3_format.fmt];
-                               mips32_insn.fp0_format.ft = 0;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp3_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp3_format.rt;
-                               mips32_insn.fp0_format.func = func;
-                               break;
-                       case mm_ffloorl_op:
-                       case mm_ffloorw_op:
-                       case mm_fceill_op:
-                       case mm_fceilw_op:
-                       case mm_ftruncl_op:
-                       case mm_ftruncw_op:
-                       case mm_froundl_op:
-                       case mm_froundw_op:
-                       case mm_fcvtl_op:
-                       case mm_fcvtw_op:
-                               if (insn.mm_fp1_format.op == mm_ffloorl_op)
-                                       func = ffloorl_op;
-                               else if (insn.mm_fp1_format.op == mm_ffloorw_op)
-                                       func = ffloor_op;
-                               else if (insn.mm_fp1_format.op == mm_fceill_op)
-                                       func = fceill_op;
-                               else if (insn.mm_fp1_format.op == mm_fceilw_op)
-                                       func = fceil_op;
-                               else if (insn.mm_fp1_format.op == mm_ftruncl_op)
-                                       func = ftruncl_op;
-                               else if (insn.mm_fp1_format.op == mm_ftruncw_op)
-                                       func = ftrunc_op;
-                               else if (insn.mm_fp1_format.op == mm_froundl_op)
-                                       func = froundl_op;
-                               else if (insn.mm_fp1_format.op == mm_froundw_op)
-                                       func = fround_op;
-                               else if (insn.mm_fp1_format.op == mm_fcvtl_op)
-                                       func = fcvtl_op;
-                               else
-                                       func = fcvtw_op;
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt =
-                                       sd_format[insn.mm_fp1_format.fmt];
-                               mips32_insn.fp0_format.ft = 0;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp1_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp1_format.rt;
-                               mips32_insn.fp0_format.func = func;
-                               break;
-                       case mm_frsqrt_op:
-                       case mm_fsqrt_op:
-                       case mm_frecip_op:
-                               if (insn.mm_fp1_format.op == mm_frsqrt_op)
-                                       func = frsqrt_op;
-                               else if (insn.mm_fp1_format.op == mm_fsqrt_op)
-                                       func = fsqrt_op;
-                               else
-                                       func = frecip_op;
-                               mips32_insn.fp0_format.opcode = cop1_op;
-                               mips32_insn.fp0_format.fmt =
-                                       sdps_format[insn.mm_fp1_format.fmt];
-                               mips32_insn.fp0_format.ft = 0;
-                               mips32_insn.fp0_format.fs =
-                                       insn.mm_fp1_format.fs;
-                               mips32_insn.fp0_format.fd =
-                                       insn.mm_fp1_format.rt;
-                               mips32_insn.fp0_format.func = func;
-                               break;
-                       case mm_mfc1_op:
-                       case mm_mtc1_op:
-                       case mm_cfc1_op:
-                       case mm_ctc1_op:
-                       case mm_mfhc1_op:
-                       case mm_mthc1_op:
-                               if (insn.mm_fp1_format.op == mm_mfc1_op)
-                                       op = mfc_op;
-                               else if (insn.mm_fp1_format.op == mm_mtc1_op)
-                                       op = mtc_op;
-                               else if (insn.mm_fp1_format.op == mm_cfc1_op)
-                                       op = cfc_op;
-                               else if (insn.mm_fp1_format.op == mm_ctc1_op)
-                                       op = ctc_op;
-                               else if (insn.mm_fp1_format.op == mm_mfhc1_op)
-                                       op = mfhc_op;
-                               else
-                                       op = mthc_op;
-                               mips32_insn.fp1_format.opcode = cop1_op;
-                               mips32_insn.fp1_format.op = op;
-                               mips32_insn.fp1_format.rt =
-                                       insn.mm_fp1_format.rt;
-                               mips32_insn.fp1_format.fs =
-                                       insn.mm_fp1_format.fs;
-                               mips32_insn.fp1_format.fd = 0;
-                               mips32_insn.fp1_format.func = 0;
-                               break;
-                       default:
-                               return SIGILL;
-                       }
-                       break;
-               case mm_32f_74_op:      /* c.cond.fmt */
-                       mips32_insn.fp0_format.opcode = cop1_op;
-                       mips32_insn.fp0_format.fmt =
-                               sdps_format[insn.mm_fp4_format.fmt];
-                       mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt;
-                       mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs;
-                       mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2;
-                       mips32_insn.fp0_format.func =
-                               insn.mm_fp4_format.cond | MM_MIPS32_COND_FC;
-                       break;
-               default:
-                       return SIGILL;
-               }
-               break;
-       default:
-               return SIGILL;
-       }
-
-       *insn_ptr = mips32_insn;
-       return 0;
-}
-
-int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
-                    unsigned long *contpc)
-{
-       union mips_instruction insn = (union mips_instruction)dec_insn.insn;
-       int bc_false = 0;
-       unsigned int fcr31;
-       unsigned int bit;
-
-       if (!cpu_has_mmips)
-               return 0;
-
-       switch (insn.mm_i_format.opcode) {
-       case mm_pool32a_op:
-               if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) ==
-                   mm_pool32axf_op) {
-                       switch (insn.mm_i_format.simmediate >>
-                               MM_POOL32A_MINOR_SHIFT) {
-                       case mm_jalr_op:
-                       case mm_jalrhb_op:
-                       case mm_jalrs_op:
-                       case mm_jalrshb_op:
-                               if (insn.mm_i_format.rt != 0)   /* Not mm_jr */
-                                       regs->regs[insn.mm_i_format.rt] =
-                                               regs->cp0_epc +
-                                               dec_insn.pc_inc +
-                                               dec_insn.next_pc_inc;
-                               *contpc = regs->regs[insn.mm_i_format.rs];
-                               return 1;
-                       }
-               }
-               break;
-       case mm_pool32i_op:
-               switch (insn.mm_i_format.rt) {
-               case mm_bltzals_op:
-               case mm_bltzal_op:
-                       regs->regs[31] = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
-                       /* Fall through */
-               case mm_bltz_op:
-                       if ((long)regs->regs[insn.mm_i_format.rs] < 0)
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       (insn.mm_i_format.simmediate << 1);
-                       else
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
-                       return 1;
-               case mm_bgezals_op:
-               case mm_bgezal_op:
-                       regs->regs[31] = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
-                       /* Fall through */
-               case mm_bgez_op:
-                       if ((long)regs->regs[insn.mm_i_format.rs] >= 0)
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       (insn.mm_i_format.simmediate << 1);
-                       else
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
-                       return 1;
-               case mm_blez_op:
-                       if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       (insn.mm_i_format.simmediate << 1);
-                       else
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
-                       return 1;
-               case mm_bgtz_op:
-                       if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       (insn.mm_i_format.simmediate << 1);
-                       else
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
-                       return 1;
-               case mm_bc2f_op:
-               case mm_bc1f_op:
-                       bc_false = 1;
-                       /* Fall through */
-               case mm_bc2t_op:
-               case mm_bc1t_op:
-                       preempt_disable();
-                       if (is_fpu_owner())
-                               asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
-                       else
-                               fcr31 = current->thread.fpu.fcr31;
-                       preempt_enable();
-
-                       if (bc_false)
-                               fcr31 = ~fcr31;
-
-                       bit = (insn.mm_i_format.rs >> 2);
-                       bit += (bit != 0);
-                       bit += 23;
-                       if (fcr31 & (1 << bit))
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       (insn.mm_i_format.simmediate << 1);
-                       else
-                               *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc + dec_insn.next_pc_inc;
-                       return 1;
-               }
-               break;
-       case mm_pool16c_op:
-               switch (insn.mm_i_format.rt) {
-               case mm_jalr16_op:
-               case mm_jalrs16_op:
-                       regs->regs[31] = regs->cp0_epc +
-                               dec_insn.pc_inc + dec_insn.next_pc_inc;
-                       /* Fall through */
-               case mm_jr16_op:
-                       *contpc = regs->regs[insn.mm_i_format.rs];
-                       return 1;
-               }
-               break;
-       case mm_beqz16_op:
-               if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0)
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               (insn.mm_b1_format.simmediate << 1);
-               else
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc + dec_insn.next_pc_inc;
-               return 1;
-       case mm_bnez16_op:
-               if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0)
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               (insn.mm_b1_format.simmediate << 1);
-               else
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc + dec_insn.next_pc_inc;
-               return 1;
-       case mm_b16_op:
-               *contpc = regs->cp0_epc + dec_insn.pc_inc +
-                        (insn.mm_b0_format.simmediate << 1);
-               return 1;
-       case mm_beq32_op:
-               if (regs->regs[insn.mm_i_format.rs] ==
-                   regs->regs[insn.mm_i_format.rt])
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               (insn.mm_i_format.simmediate << 1);
-               else
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
-               return 1;
-       case mm_bne32_op:
-               if (regs->regs[insn.mm_i_format.rs] !=
-                   regs->regs[insn.mm_i_format.rt])
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               (insn.mm_i_format.simmediate << 1);
-               else
-                       *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc + dec_insn.next_pc_inc;
-               return 1;
-       case mm_jalx32_op:
-               regs->regs[31] = regs->cp0_epc +
-                       dec_insn.pc_inc + dec_insn.next_pc_inc;
-               *contpc = regs->cp0_epc + dec_insn.pc_inc;
-               *contpc >>= 28;
-               *contpc <<= 28;
-               *contpc |= (insn.j_format.target << 2);
-               return 1;
-       case mm_jals32_op:
-       case mm_jal32_op:
-               regs->regs[31] = regs->cp0_epc +
-                       dec_insn.pc_inc + dec_insn.next_pc_inc;
-               /* Fall through */
-       case mm_j32_op:
-               *contpc = regs->cp0_epc + dec_insn.pc_inc;
-               *contpc >>= 27;
-               *contpc <<= 27;
-               *contpc |= (insn.j_format.target << 1);
-               set_isa16_mode(*contpc);
-               return 1;
-       }
-       return 0;
-}
 
 /*
  * Redundant with logic already in kernel/branch.c,
@@ -665,10 +85,10 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
  * a single subroutine should be used across both
  * modules.
  */
-static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
-                        unsigned long *contpc)
+static int isBranchInstr(struct pt_regs *regs,
+       const struct mm_decoded_insn * const dec_insn, unsigned long *contpc)
 {
-       union mips_instruction insn = (union mips_instruction)dec_insn.insn;
+       union mips_instruction insn = (union mips_instruction)dec_insn->insn;
        unsigned int fcr31;
        unsigned int bit = 0;
 
@@ -677,8 +97,8 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                switch (insn.r_format.func) {
                case jalr_op:
                        regs->regs[insn.r_format.rd] =
-                               regs->cp0_epc + dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               regs->cp0_epc + dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                        /* Fall through */
                case jr_op:
                        *contpc = regs->regs[insn.r_format.rs];
@@ -690,36 +110,36 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                case bltzal_op:
                case bltzall_op:
                        regs->regs[31] = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                        /* Fall through */
                case bltz_op:
                case bltzl_op:
                        if ((long)regs->regs[insn.i_format.rs] < 0)
                                *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
+                                       dec_insn->pc_inc +
                                        (insn.i_format.simmediate << 2);
                        else
                                *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
                        return 1;
                case bgezal_op:
                case bgezall_op:
                        regs->regs[31] = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                        /* Fall through */
                case bgez_op:
                case bgezl_op:
                        if ((long)regs->regs[insn.i_format.rs] >= 0)
                                *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
+                                       dec_insn->pc_inc +
                                        (insn.i_format.simmediate << 2);
                        else
                                *contpc = regs->cp0_epc +
-                                       dec_insn.pc_inc +
-                                       dec_insn.next_pc_inc;
+                                       dec_insn->pc_inc +
+                                       dec_insn->next_pc_inc;
                        return 1;
                }
                break;
@@ -727,11 +147,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                set_isa16_mode(bit);
        case jal_op:
                regs->regs[31] = regs->cp0_epc +
-                       dec_insn.pc_inc +
-                       dec_insn.next_pc_inc;
+                       dec_insn->pc_inc +
+                       dec_insn->next_pc_inc;
                /* Fall through */
        case j_op:
-               *contpc = regs->cp0_epc + dec_insn.pc_inc;
+               *contpc = regs->cp0_epc + dec_insn->pc_inc;
                *contpc >>= 28;
                *contpc <<= 28;
                *contpc |= (insn.j_format.target << 2);
@@ -743,46 +163,46 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                if (regs->regs[insn.i_format.rs] ==
                    regs->regs[insn.i_format.rt])
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
+                               dec_insn->pc_inc +
                                (insn.i_format.simmediate << 2);
                else
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                return 1;
        case bne_op:
        case bnel_op:
                if (regs->regs[insn.i_format.rs] !=
                    regs->regs[insn.i_format.rt])
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
+                               dec_insn->pc_inc +
                                (insn.i_format.simmediate << 2);
                else
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                return 1;
        case blez_op:
        case blezl_op:
                if ((long)regs->regs[insn.i_format.rs] <= 0)
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
+                               dec_insn->pc_inc +
                                (insn.i_format.simmediate << 2);
                else
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                return 1;
        case bgtz_op:
        case bgtzl_op:
                if ((long)regs->regs[insn.i_format.rs] > 0)
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
+                               dec_insn->pc_inc +
                                (insn.i_format.simmediate << 2);
                else
                        *contpc = regs->cp0_epc +
-                               dec_insn.pc_inc +
-                               dec_insn.next_pc_inc;
+                               dec_insn->pc_inc +
+                               dec_insn->next_pc_inc;
                return 1;
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
        case lwc2_op: /* This is bbit0 on Octeon */
@@ -830,23 +250,23 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        case 2: /* bc1fl */
                                if (~fcr31 & (1 << bit))
                                        *contpc = regs->cp0_epc +
-                                               dec_insn.pc_inc +
+                                               dec_insn->pc_inc +
                                                (insn.i_format.simmediate << 2);
                                else
                                        *contpc = regs->cp0_epc +
-                                               dec_insn.pc_inc +
-                                               dec_insn.next_pc_inc;
+                                               dec_insn->pc_inc +
+                                               dec_insn->next_pc_inc;
                                return 1;
                        case 1: /* bc1t */
                        case 3: /* bc1tl */
                                if (fcr31 & (1 << bit))
                                        *contpc = regs->cp0_epc +
-                                               dec_insn.pc_inc +
+                                               dec_insn->pc_inc +
                                                (insn.i_format.simmediate << 2);
                                else
                                        *contpc = regs->cp0_epc +
-                                               dec_insn.pc_inc +
-                                               dec_insn.next_pc_inc;
+                                               dec_insn->pc_inc +
+                                               dec_insn->next_pc_inc;
                                return 1;
                        }
                }
@@ -867,23 +287,25 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
  */
 static inline int cop1_64bit(struct pt_regs *xcp)
 {
-#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32)
-       return 1;
-#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT)
-       return 0;
-#else
+       if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32))
+               return 1;
+       else if (config_enabled(CONFIG_32BIT) &&
+                !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
+               return 0;
+
        return !test_thread_flag(TIF_32BIT_FPREGS);
-#endif
 }
 
-#define SIFROMREG(si, x) do {                                          \
+#define SIFROMREG(si, x)                                               \
+do {                                                                   \
        if (cop1_64bit(xcp))                                            \
                (si) = get_fpr32(&ctx->fpr[x], 0);                      \
        else                                                            \
                (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1);         \
 } while (0)
 
-#define SITOREG(si, x) do {                                            \
+#define SITOREG(si, x)                                                 \
+do {                                                                   \
        if (cop1_64bit(xcp)) {                                          \
                unsigned i;                                             \
                set_fpr32(&ctx->fpr[x], 0, si);                         \
@@ -896,17 +318,19 @@ static inline int cop1_64bit(struct pt_regs *xcp)
 
 #define SIFROMHREG(si, x)      ((si) = get_fpr32(&ctx->fpr[x], 1))
 
-#define SITOHREG(si, x) do {                                           \
+#define SITOHREG(si, x)                                                        \
+do {                                                                   \
        unsigned i;                                                     \
        set_fpr32(&ctx->fpr[x], 1, si);                                 \
        for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++)             \
                set_fpr32(&ctx->fpr[x], i, 0);                          \
 } while (0)
 
-#define DIFROMREG(di, x) \
+#define DIFROMREG(di, x)                                               \
        ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
 
-#define DITOREG(di, x) do {                                            \
+#define DITOREG(di, x)                                                 \
+do {                                                                   \
        unsigned fpr, i;                                                \
        fpr = (x) & ~(cop1_64bit(xcp) == 0);                            \
        set_fpr64(&ctx->fpr[fpr], 0, di);                               \
@@ -927,23 +351,29 @@ static inline int cop1_64bit(struct pt_regs *xcp)
 static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                struct mm_decoded_insn dec_insn, void *__user *fault_addr)
 {
-       mips_instruction ir;
        unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc;
-       unsigned int cond;
-       int pc_inc;
+       unsigned int cond, cbit;
+       mips_instruction ir;
+       int likely, pc_inc;
+       u32 __user *wva;
+       u64 __user *dva;
+       u32 value;
+       u32 wval;
+       u64 dval;
+       int sig;
 
        /* XXX NEC Vr54xx bug workaround */
-       if (xcp->cp0_cause & CAUSEF_BD) {
+       if (delay_slot(xcp)) {
                if (dec_insn.micro_mips_mode) {
-                       if (!mm_isBranchInstr(xcp, dec_insn, &contpc))
-                               xcp->cp0_cause &= ~CAUSEF_BD;
+                       if (!mm_isBranchInstr(xcp, &dec_insn, &contpc))
+                               clear_delay_slot(xcp);
                } else {
-                       if (!isBranchInstr(xcp, dec_insn, &contpc))
-                               xcp->cp0_cause &= ~CAUSEF_BD;
+                       if (!isBranchInstr(xcp, &dec_insn, &contpc))
+                               clear_delay_slot(xcp);
                }
        }
 
-       if (xcp->cp0_cause & CAUSEF_BD) {
+       if (delay_slot(xcp)) {
                /*
                 * The instruction to be emulated is in a branch delay slot
                 * which means that we have to  emulate the branch instruction
@@ -985,96 +415,85 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        return SIGILL;
        }
 
-      emul:
+emul:
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0);
        MIPS_FPU_EMU_INC_STATS(emulated);
        switch (MIPSInst_OPCODE(ir)) {
-       case ldc1_op:{
-               u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
-                       MIPSInst_SIMM(ir));
-               u64 val;
-
+       case ldc1_op:
+               dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
+                                    MIPSInst_SIMM(ir));
                MIPS_FPU_EMU_INC_STATS(loads);
 
-               if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
+               if (!access_ok(VERIFY_READ, dva, sizeof(u64))) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = dva;
                        return SIGBUS;
                }
-               if (__get_user(val, va)) {
+               if (__get_user(dval, dva)) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = dva;
                        return SIGSEGV;
                }
-               DITOREG(val, MIPSInst_RT(ir));
+               DITOREG(dval, MIPSInst_RT(ir));
                break;
-       }
-
-       case sdc1_op:{
-               u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
-                       MIPSInst_SIMM(ir));
-               u64 val;
 
+       case sdc1_op:
+               dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
+                                     MIPSInst_SIMM(ir));
                MIPS_FPU_EMU_INC_STATS(stores);
-               DIFROMREG(val, MIPSInst_RT(ir));
-               if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
+               DIFROMREG(dval, MIPSInst_RT(ir));
+               if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = dva;
                        return SIGBUS;
                }
-               if (__put_user(val, va)) {
+               if (__put_user(dval, dva)) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = dva;
                        return SIGSEGV;
                }
                break;
-       }
-
-       case lwc1_op:{
-               u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
-                       MIPSInst_SIMM(ir));
-               u32 val;
 
+       case lwc1_op:
+               wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
+                                     MIPSInst_SIMM(ir));
                MIPS_FPU_EMU_INC_STATS(loads);
-               if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
+               if (!access_ok(VERIFY_READ, wva, sizeof(u32))) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = wva;
                        return SIGBUS;
                }
-               if (__get_user(val, va)) {
+               if (__get_user(wval, wva)) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = wva;
                        return SIGSEGV;
                }
-               SITOREG(val, MIPSInst_RT(ir));
+               SITOREG(wval, MIPSInst_RT(ir));
                break;
-       }
-
-       case swc1_op:{
-               u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
-                       MIPSInst_SIMM(ir));
-               u32 val;
 
+       case swc1_op:
+               wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
+                                     MIPSInst_SIMM(ir));
                MIPS_FPU_EMU_INC_STATS(stores);
-               SIFROMREG(val, MIPSInst_RT(ir));
-               if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
+               SIFROMREG(wval, MIPSInst_RT(ir));
+               if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = wva;
                        return SIGBUS;
                }
-               if (__put_user(val, va)) {
+               if (__put_user(wval, wva)) {
                        MIPS_FPU_EMU_INC_STATS(errors);
-                       *fault_addr = va;
+                       *fault_addr = wva;
                        return SIGSEGV;
                }
                break;
-       }
 
        case cop1_op:
                switch (MIPSInst_RS(ir)) {
-
-#if defined(__mips64)
                case dmfc_op:
+                       if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
+                               return SIGILL;
+
                        /* copregister fs -> gpr[rt] */
                        if (MIPSInst_RT(ir) != 0) {
                                DIFROMREG(xcp->regs[MIPSInst_RT(ir)],
@@ -1083,10 +502,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        break;
 
                case dmtc_op:
+                       if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
+                               return SIGILL;
+
                        /* copregister fs <- rt */
                        DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
                        break;
-#endif
 
                case mfhc_op:
                        if (!cpu_has_mips_r2)
@@ -1120,19 +541,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
                        break;
 
-               case cfc_op:{
+               case cfc_op:
                        /* cop control register rd -> gpr[rt] */
-                       u32 value;
-
                        if (MIPSInst_RD(ir) == FPCREG_CSR) {
                                value = ctx->fcr31;
-                               value = (value & ~FPU_CSR_RM) |
-                                       mips_rm[modeindex(value)];
-#ifdef CSRTRACE
-                               printk("%p gpr[%d]<-csr=%08x\n",
-                                       (void *) (xcp->cp0_epc),
-                                       MIPSInst_RT(ir), value);
-#endif
+                               value = (value & ~FPU_CSR_RM) | modeindex(value);
+                               pr_debug("%p gpr[%d]<-csr=%08x\n",
+                                        (void *) (xcp->cp0_epc),
+                                        MIPSInst_RT(ir), value);
                        }
                        else if (MIPSInst_RD(ir) == FPCREG_RID)
                                value = 0;
@@ -1141,12 +557,9 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (MIPSInst_RT(ir))
                                xcp->regs[MIPSInst_RT(ir)] = value;
                        break;
-               }
 
-               case ctc_op:{
+               case ctc_op:
                        /* copregister rd <- rt */
-                       u32 value;
-
                        if (MIPSInst_RT(ir) == 0)
                                value = 0;
                        else
@@ -1155,37 +568,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        /* we only have one writable control reg
                         */
                        if (MIPSInst_RD(ir) == FPCREG_CSR) {
-#ifdef CSRTRACE
-                               printk("%p gpr[%d]->csr=%08x\n",
-                                       (void *) (xcp->cp0_epc),
-                                       MIPSInst_RT(ir), value);
-#endif
+                               pr_debug("%p gpr[%d]->csr=%08x\n",
+                                        (void *) (xcp->cp0_epc),
+                                        MIPSInst_RT(ir), value);
 
                                /*
                                 * Don't write reserved bits,
                                 * and convert to ieee library modes
                                 */
-                               ctx->fcr31 = (value &
-                                               ~(FPU_CSR_RSVD | FPU_CSR_RM)) |
-                                               ieee_rm[modeindex(value)];
+                               ctx->fcr31 = (value & ~(FPU_CSR_RSVD | FPU_CSR_RM)) |
+                                            modeindex(value);
                        }
                        if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
                                return SIGFPE;
                        }
                        break;
-               }
-
-               case bc_op:{
-                       int likely = 0;
 
-                       if (xcp->cp0_cause & CAUSEF_BD)
+               case bc_op:
+                       if (delay_slot(xcp))
                                return SIGILL;
 
-#if __mips >= 4
-                       cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2];
-#else
-                       cond = ctx->fcr31 & FPU_CSR_COND;
-#endif
+                       if (cpu_has_mips_4_5_r)
+                               cbit = fpucondbit[MIPSInst_RT(ir) >> 2];
+                       else
+                               cbit = FPU_CSR_COND;
+                       cond = ctx->fcr31 & cbit;
+
+                       likely = 0;
                        switch (MIPSInst_RT(ir) & 3) {
                        case bcfl_op:
                                likely = 1;
@@ -1201,10 +610,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                                return SIGILL;
                        }
 
-                       xcp->cp0_cause |= CAUSEF_BD;
+                       set_delay_slot(xcp);
                        if (cond) {
-                               /* branch taken: emulate dslot
-                                * instruction
+                               /*
+                                * Branch taken: emulate dslot instruction
                                 */
                                xcp->cp0_epc += dec_insn.pc_inc;
 
@@ -1238,23 +647,37 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 
                                switch (MIPSInst_OPCODE(ir)) {
                                case lwc1_op:
+                                       goto emul;
+
                                case swc1_op:
-#if (__mips >= 2 || defined(__mips64))
+                                       goto emul;
+
                                case ldc1_op:
                                case sdc1_op:
-#endif
+                                       if (cpu_has_mips_2_3_4_5 ||
+                                           cpu_has_mips64)
+                                               goto emul;
+
+                                       return SIGILL;
+                                       goto emul;
+
                                case cop1_op:
-#if __mips >= 4 && __mips != 32
-                               case cop1x_op:
-#endif
-                                       /* its one of ours */
                                        goto emul;
-#if __mips >= 4
+
+                               case cop1x_op:
+                                       if (cpu_has_mips_4_5 || cpu_has_mips64)
+                                               /* its one of ours */
+                                               goto emul;
+
+                                       return SIGILL;
+
                                case spec_op:
+                                       if (!cpu_has_mips_4_5_r)
+                                               return SIGILL;
+
                                        if (MIPSInst_FUNC(ir) == movc_op)
                                                goto emul;
                                        break;
-#endif
                                }
 
                                /*
@@ -1262,10 +685,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                                 * instruction in the dslot
                                 */
                                return mips_dsemul(xcp, ir, contpc);
-                       }
-                       else {
-                               /* branch not taken */
-                               if (likely) {
+                       } else if (likely) {    /* branch not taken */
                                        /*
                                         * branch likely nullifies
                                         * dslot if not taken
@@ -1277,34 +697,31 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                                         * dslot as normal insn
                                         */
                                }
-                       }
                        break;
-               }
 
                default:
                        if (!(MIPSInst_RS(ir) & 0x10))
                                return SIGILL;
-                       {
-                               int sig;
 
-                               /* a real fpu computation instruction */
-                               if ((sig = fpu_emu(xcp, ctx, ir)))
-                                       return sig;
-                       }
+                       /* a real fpu computation instruction */
+                       if ((sig = fpu_emu(xcp, ctx, ir)))
+                               return sig;
                }
                break;
 
-#if __mips >= 4 && __mips != 32
-       case cop1x_op:{
-               int sig = fpux_emu(xcp, ctx, ir, fault_addr);
+       case cop1x_op:
+               if (!cpu_has_mips_4_5 && !cpu_has_mips64)
+                       return SIGILL;
+
+               sig = fpux_emu(xcp, ctx, ir, fault_addr);
                if (sig)
                        return sig;
                break;
-       }
-#endif
 
-#if __mips >= 4
        case spec_op:
+               if (!cpu_has_mips_4_5_r)
+                       return SIGILL;
+
                if (MIPSInst_FUNC(ir) != movc_op)
                        return SIGILL;
                cond = fpucondbit[MIPSInst_RT(ir) >> 2];
@@ -1312,8 +729,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        xcp->regs[MIPSInst_RD(ir)] =
                                xcp->regs[MIPSInst_RS(ir)];
                break;
-#endif
-
        default:
 sigill:
                return SIGILL;
@@ -1321,7 +736,7 @@ sigill:
 
        /* we did it !! */
        xcp->cp0_epc = contpc;
-       xcp->cp0_cause &= ~CAUSEF_BD;
+       clear_delay_slot(xcp);
 
        return 0;
 }
@@ -1342,44 +757,42 @@ static const unsigned char cmptab[8] = {
 };
 
 
-#if __mips >= 4 && __mips != 32
-
 /*
  * Additional MIPS4 instructions
  */
 
-#define DEF3OP(name, p, f1, f2, f3) \
-static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \
-    ieee754##p t) \
-{ \
-       struct _ieee754_csr ieee754_csr_save; \
-       s = f1(s, t); \
-       ieee754_csr_save = ieee754_csr; \
-       s = f2(s, r); \
-       ieee754_csr_save.cx |= ieee754_csr.cx; \
-       ieee754_csr_save.sx |= ieee754_csr.sx; \
-       s = f3(s); \
-       ieee754_csr.cx |= ieee754_csr_save.cx; \
-       ieee754_csr.sx |= ieee754_csr_save.sx; \
-       return s; \
+#define DEF3OP(name, p, f1, f2, f3)                                    \
+static union ieee754##p fpemu_##p##_##name(union ieee754##p r,         \
+       union ieee754##p s, union ieee754##p t)                         \
+{                                                                      \
+       struct _ieee754_csr ieee754_csr_save;                           \
+       s = f1(s, t);                                                   \
+       ieee754_csr_save = ieee754_csr;                                 \
+       s = f2(s, r);                                                   \
+       ieee754_csr_save.cx |= ieee754_csr.cx;                          \
+       ieee754_csr_save.sx |= ieee754_csr.sx;                          \
+       s = f3(s);                                                      \
+       ieee754_csr.cx |= ieee754_csr_save.cx;                          \
+       ieee754_csr.sx |= ieee754_csr_save.sx;                          \
+       return s;                                                       \
 }
 
-static ieee754dp fpemu_dp_recip(ieee754dp d)
+static union ieee754dp fpemu_dp_recip(union ieee754dp d)
 {
        return ieee754dp_div(ieee754dp_one(0), d);
 }
 
-static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
+static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d)
 {
        return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
 }
 
-static ieee754sp fpemu_sp_recip(ieee754sp s)
+static union ieee754sp fpemu_sp_recip(union ieee754sp s)
 {
        return ieee754sp_div(ieee754sp_one(0), s);
 }
 
-static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
+static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s)
 {
        return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
 }
@@ -1403,8 +816,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
        switch (MIPSInst_FMA_FFMT(ir)) {
        case s_fmt:{            /* 0 */
 
-               ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
-               ieee754sp fd, fr, fs, ft;
+               union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp);
+               union ieee754sp fd, fr, fs, ft;
                u32 __user *va;
                u32 val;
 
@@ -1478,7 +891,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 
                        ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
                        if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
-                               /*printk ("SIGFPE: fpu csr = %08x\n",
+                               /*printk ("SIGFPE: FPU csr = %08x\n",
                                   ctx->fcr31); */
                                return SIGFPE;
                        }
@@ -1492,8 +905,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
        }
 
        case d_fmt:{            /* 1 */
-               ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
-               ieee754dp fd, fr, fs, ft;
+               union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp);
+               union ieee754dp fd, fr, fs, ft;
                u64 __user *va;
                u64 val;
 
@@ -1574,7 +987,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 
        return 0;
 }
-#endif
 
 
 
@@ -1586,23 +998,25 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 {
        int rfmt;               /* resulting format */
        unsigned rcsr = 0;      /* resulting csr */
+       unsigned int oldrm;
+       unsigned int cbit;
        unsigned cond;
        union {
-               ieee754dp d;
-               ieee754sp s;
+               union ieee754dp d;
+               union ieee754sp s;
                int w;
-#ifdef __mips64
                s64 l;
-#endif
        } rv;                   /* resulting value */
+       u64 bits;
 
        MIPS_FPU_EMU_INC_STATS(cp1ops);
        switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
-       case s_fmt:           /* 0 */
+       case s_fmt: {           /* 0 */
                union {
-                       ieee754sp(*b) (ieee754sp, ieee754sp);
-                       ieee754sp(*u) (ieee754sp);
+                       union ieee754sp(*b) (union ieee754sp, union ieee754sp);
+                       union ieee754sp(*u) (union ieee754sp);
                } handler;
+               union ieee754sp fs, ft;
 
                switch (MIPSInst_FUNC(ir)) {
                        /* binary ops */
@@ -1620,69 +1034,86 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        goto scopbop;
 
                        /* unary  ops */
-#if __mips >= 2 || defined(__mips64)
                case fsqrt_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        handler.u = ieee754sp_sqrt;
                        goto scopuop;
-#endif
-#if __mips >= 4 && __mips != 32
+
+               /*
+                * Note that on some MIPS IV implementations such as the
+                * R5000 and R8000 the FSQRT and FRECIP instructions do not
+                * achieve full IEEE-754 accuracy - however this emulator does.
+                */
                case frsqrt_op:
+                       if (!cpu_has_mips_4_5_r2)
+                               return SIGILL;
+
                        handler.u = fpemu_sp_rsqrt;
                        goto scopuop;
+
                case frecip_op:
+                       if (!cpu_has_mips_4_5_r2)
+                               return SIGILL;
+
                        handler.u = fpemu_sp_recip;
                        goto scopuop;
-#endif
-#if __mips >= 4
+
                case fmovc_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        cond = fpucondbit[MIPSInst_FT(ir) >> 2];
                        if (((ctx->fcr31 & cond) != 0) !=
                                ((MIPSInst_FT(ir) & 1) != 0))
                                return 0;
                        SPFROMREG(rv.s, MIPSInst_FS(ir));
                        break;
+
                case fmovz_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        if (xcp->regs[MIPSInst_FT(ir)] != 0)
                                return 0;
                        SPFROMREG(rv.s, MIPSInst_FS(ir));
                        break;
+
                case fmovn_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        if (xcp->regs[MIPSInst_FT(ir)] == 0)
                                return 0;
                        SPFROMREG(rv.s, MIPSInst_FS(ir));
                        break;
-#endif
+
                case fabs_op:
                        handler.u = ieee754sp_abs;
                        goto scopuop;
+
                case fneg_op:
                        handler.u = ieee754sp_neg;
                        goto scopuop;
+
                case fmov_op:
                        /* an easy one */
                        SPFROMREG(rv.s, MIPSInst_FS(ir));
                        goto copcsr;
 
                        /* binary op on handler */
-                     scopbop:
-                       {
-                               ieee754sp fs, ft;
-
-                               SPFROMREG(fs, MIPSInst_FS(ir));
-                               SPFROMREG(ft, MIPSInst_FT(ir));
-
-                               rv.s = (*handler.b) (fs, ft);
-                               goto copcsr;
-                       }
-                     scopuop:
-                       {
-                               ieee754sp fs;
+scopbop:
+                       SPFROMREG(fs, MIPSInst_FS(ir));
+                       SPFROMREG(ft, MIPSInst_FT(ir));
 
-                               SPFROMREG(fs, MIPSInst_FS(ir));
-                               rv.s = (*handler.u) (fs);
-                               goto copcsr;
-                       }
-                     copcsr:
+                       rv.s = (*handler.b) (fs, ft);
+                       goto copcsr;
+scopuop:
+                       SPFROMREG(fs, MIPSInst_FS(ir));
+                       rv.s = (*handler.u) (fs);
+                       goto copcsr;
+copcsr:
                        if (ieee754_cxtest(IEEE754_INEXACT))
                                rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
                        if (ieee754_cxtest(IEEE754_UNDERFLOW))
@@ -1698,70 +1129,62 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        /* unary conv ops */
                case fcvts_op:
                        return SIGILL;  /* not defined */
-               case fcvtd_op:{
-                       ieee754sp fs;
 
+               case fcvtd_op:
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fsp(fs);
                        rfmt = d_fmt;
                        goto copcsr;
-               }
-               case fcvtw_op:{
-                       ieee754sp fs;
 
+               case fcvtw_op:
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.w = ieee754sp_tint(fs);
                        rfmt = w_fmt;
                        goto copcsr;
-               }
 
-#if __mips >= 2 || defined(__mips64)
                case fround_op:
                case ftrunc_op:
                case fceil_op:
-               case ffloor_op:{
-                       unsigned int oldrm = ieee754_csr.rm;
-                       ieee754sp fs;
+               case ffloor_op:
+                       if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64)
+                               return SIGILL;
 
+                       oldrm = ieee754_csr.rm;
                        SPFROMREG(fs, MIPSInst_FS(ir));
-                       ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
+                       ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir));
                        rv.w = ieee754sp_tint(fs);
                        ieee754_csr.rm = oldrm;
                        rfmt = w_fmt;
                        goto copcsr;
-               }
-#endif /* __mips >= 2 */
 
-#if defined(__mips64)
-               case fcvtl_op:{
-                       ieee754sp fs;
+               case fcvtl_op:
+                       if (!cpu_has_mips_3_4_5 && cpu_has_mips64)
+                               return SIGILL;
 
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.l = ieee754sp_tlong(fs);
                        rfmt = l_fmt;
                        goto copcsr;
-               }
 
                case froundl_op:
                case ftruncl_op:
                case fceill_op:
-               case ffloorl_op:{
-                       unsigned int oldrm = ieee754_csr.rm;
-                       ieee754sp fs;
+               case ffloorl_op:
+                       if (!cpu_has_mips_3_4_5 && cpu_has_mips64)
+                               return SIGILL;
 
+                       oldrm = ieee754_csr.rm;
                        SPFROMREG(fs, MIPSInst_FS(ir));
-                       ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
+                       ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir));
                        rv.l = ieee754sp_tlong(fs);
                        ieee754_csr.rm = oldrm;
                        rfmt = l_fmt;
                        goto copcsr;
-               }
-#endif /* defined(__mips64) */
 
                default:
                        if (MIPSInst_FUNC(ir) >= fcmp_op) {
                                unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
-                               ieee754sp fs, ft;
+                               union ieee754sp fs, ft;
 
                                SPFROMREG(fs, MIPSInst_FS(ir));
                                SPFROMREG(ft, MIPSInst_FT(ir));
@@ -1774,19 +1197,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                                else
                                        goto copcsr;
 
-                       }
-                       else {
+                       } else
                                return SIGILL;
-                       }
                        break;
                }
                break;
        }
 
-       case d_fmt:{
+       case d_fmt: {
+               union ieee754dp fs, ft;
                union {
-                       ieee754dp(*b) (ieee754dp, ieee754dp);
-                       ieee754dp(*u) (ieee754dp);
+                       union ieee754dp(*b) (union ieee754dp, union ieee754dp);
+                       union ieee754dp(*u) (union ieee754dp);
                } handler;
 
                switch (MIPSInst_FUNC(ir)) {
@@ -1805,21 +1227,33 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        goto dcopbop;
 
                        /* unary  ops */
-#if __mips >= 2 || defined(__mips64)
                case fsqrt_op:
+                       if (!cpu_has_mips_2_3_4_5_r)
+                               return SIGILL;
+
                        handler.u = ieee754dp_sqrt;
                        goto dcopuop;
-#endif
-#if __mips >= 4 && __mips != 32
+               /*
+                * Note that on some MIPS IV implementations such as the
+                * R5000 and R8000 the FSQRT and FRECIP instructions do not
+                * achieve full IEEE-754 accuracy - however this emulator does.
+                */
                case frsqrt_op:
+                       if (!cpu_has_mips_4_5_r2)
+                               return SIGILL;
+
                        handler.u = fpemu_dp_rsqrt;
                        goto dcopuop;
                case frecip_op:
+                       if (!cpu_has_mips_4_5_r2)
+                               return SIGILL;
+
                        handler.u = fpemu_dp_recip;
                        goto dcopuop;
-#endif
-#if __mips >= 4
                case fmovc_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        cond = fpucondbit[MIPSInst_FT(ir) >> 2];
                        if (((ctx->fcr31 & cond) != 0) !=
                                ((MIPSInst_FT(ir) & 1) != 0))
@@ -1827,16 +1261,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        DPFROMREG(rv.d, MIPSInst_FS(ir));
                        break;
                case fmovz_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        if (xcp->regs[MIPSInst_FT(ir)] != 0)
                                return 0;
                        DPFROMREG(rv.d, MIPSInst_FS(ir));
                        break;
                case fmovn_op:
+                       if (!cpu_has_mips_4_5_r)
+                               return SIGILL;
+
                        if (xcp->regs[MIPSInst_FT(ir)] == 0)
                                return 0;
                        DPFROMREG(rv.d, MIPSInst_FS(ir));
                        break;
-#endif
                case fabs_op:
                        handler.u = ieee754dp_abs;
                        goto dcopuop;
@@ -1851,91 +1290,78 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        goto copcsr;
 
                        /* binary op on handler */
-                     dcopbop:{
-                               ieee754dp fs, ft;
-
-                               DPFROMREG(fs, MIPSInst_FS(ir));
-                               DPFROMREG(ft, MIPSInst_FT(ir));
-
-                               rv.d = (*handler.b) (fs, ft);
-                               goto copcsr;
-                       }
-                     dcopuop:{
-                               ieee754dp fs;
-
-                               DPFROMREG(fs, MIPSInst_FS(ir));
-                               rv.d = (*handler.u) (fs);
-                               goto copcsr;
-                       }
+dcopbop:
+                       DPFROMREG(fs, MIPSInst_FS(ir));
+                       DPFROMREG(ft, MIPSInst_FT(ir));
 
-                       /* unary conv ops */
-               case fcvts_op:{
-                       ieee754dp fs;
+                       rv.d = (*handler.b) (fs, ft);
+                       goto copcsr;
+dcopuop:
+                       DPFROMREG(fs, MIPSInst_FS(ir));
+                       rv.d = (*handler.u) (fs);
+                       goto copcsr;
 
+               /*
+                * unary conv ops
+                */
+               case fcvts_op:
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fdp(fs);
                        rfmt = s_fmt;
                        goto copcsr;
-               }
+
                case fcvtd_op:
                        return SIGILL;  /* not defined */
 
-               case fcvtw_op:{
-                       ieee754dp fs;
-
+               case fcvtw_op:
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.w = ieee754dp_tint(fs);      /* wrong */
                        rfmt = w_fmt;
                        goto copcsr;
-               }
 
-#if __mips >= 2 || defined(__mips64)
                case fround_op:
                case ftrunc_op:
                case fceil_op:
-               case ffloor_op:{
-                       unsigned int oldrm = ieee754_csr.rm;
-                       ieee754dp fs;
+               case ffloor_op:
+                       if (!cpu_has_mips_2_3_4_5_r)
+                               return SIGILL;
 
+                       oldrm = ieee754_csr.rm;
                        DPFROMREG(fs, MIPSInst_FS(ir));
-                       ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
+                       ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir));
                        rv.w = ieee754dp_tint(fs);
                        ieee754_csr.rm = oldrm;
                        rfmt = w_fmt;
                        goto copcsr;
-               }
-#endif
 
-#if defined(__mips64)
-               case fcvtl_op:{
-                       ieee754dp fs;
+               case fcvtl_op:
+                       if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
+                               return SIGILL;
 
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.l = ieee754dp_tlong(fs);
                        rfmt = l_fmt;
                        goto copcsr;
-               }
 
                case froundl_op:
                case ftruncl_op:
                case fceill_op:
-               case ffloorl_op:{
-                       unsigned int oldrm = ieee754_csr.rm;
-                       ieee754dp fs;
+               case ffloorl_op:
+                       if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
+                               return SIGILL;
 
+                       oldrm = ieee754_csr.rm;
                        DPFROMREG(fs, MIPSInst_FS(ir));
-                       ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
+                       ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir));
                        rv.l = ieee754dp_tlong(fs);
                        ieee754_csr.rm = oldrm;
                        rfmt = l_fmt;
                        goto copcsr;
-               }
-#endif /* __mips >= 3 */
 
                default:
                        if (MIPSInst_FUNC(ir) >= fcmp_op) {
                                unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
-                               ieee754dp fs, ft;
+                               union ieee754dp fs, ft;
 
                                DPFROMREG(fs, MIPSInst_FS(ir));
                                DPFROMREG(ft, MIPSInst_FT(ir));
@@ -1957,11 +1383,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        break;
                }
                break;
-       }
-
-       case w_fmt:{
-               ieee754sp fs;
 
+       case w_fmt:
                switch (MIPSInst_FUNC(ir)) {
                case fcvts_op:
                        /* convert word to single precision real */
@@ -1981,9 +1404,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                break;
        }
 
-#if defined(__mips64)
-       case l_fmt:{
-               u64 bits;
+       case l_fmt:
+
+               if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
+                       return SIGILL;
+
                DIFROMREG(bits, MIPSInst_FS(ir));
 
                switch (MIPSInst_FUNC(ir)) {
@@ -2001,8 +1426,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        return SIGILL;
                }
                break;
-       }
-#endif
 
        default:
                return SIGILL;
@@ -2017,7 +1440,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
         */
        ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
        if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
-               /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
+               /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */
                return SIGFPE;
        }
 
@@ -2025,18 +1448,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
         * Now we can safely write the result back to the register file.
         */
        switch (rfmt) {
-       case -1:{
-#if __mips >= 4
-               cond = fpucondbit[MIPSInst_FD(ir) >> 2];
-#else
-               cond = FPU_CSR_COND;
-#endif
+       case -1:
+
+               if (cpu_has_mips_4_5_r)
+                       cbit = fpucondbit[MIPSInst_RT(ir) >> 2];
+               else
+                       cbit = FPU_CSR_COND;
+               cond = ctx->fcr31 & cbit;
                if (rv.w)
                        ctx->fcr31 |= cond;
                else
                        ctx->fcr31 &= ~cond;
                break;
-       }
+
        case d_fmt:
                DPTOREG(rv.d, MIPSInst_FD(ir));
                break;
@@ -2046,11 +1470,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
        case w_fmt:
                SITOREG(rv.w, MIPSInst_FD(ir));
                break;
-#if defined(__mips64)
        case l_fmt:
+               if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
+                       return SIGILL;
+
                DITOREG(rv.l, MIPSInst_FD(ir));
                break;
-#endif
        default:
                return SIGILL;
        }
@@ -2138,11 +1563,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                         * ieee754_csr.  But ieee754_csr.rm is ieee
                         * library modes. (not mips rounding mode)
                         */
-                       /* convert to ieee library modes */
-                       ieee754_csr.rm = ieee_rm[ieee754_csr.rm];
                        sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr);
-                       /* revert to mips rounding mode */
-                       ieee754_csr.rm = mips_rm[ieee754_csr.rm];
                }
 
                if (has_fpu)
@@ -2155,58 +1576,8 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 
        /* SIGILL indicates a non-fpu instruction */
        if (sig == SIGILL && xcp->cp0_epc != oldepc)
-               /* but if epc has advanced, then ignore it */
+               /* but if EPC has advanced, then ignore it */
                sig = 0;
 
        return sig;
 }
-
-#ifdef CONFIG_DEBUG_FS
-
-static int fpuemu_stat_get(void *data, u64 *val)
-{
-       int cpu;
-       unsigned long sum = 0;
-       for_each_online_cpu(cpu) {
-               struct mips_fpu_emulator_stats *ps;
-               local_t *pv;
-               ps = &per_cpu(fpuemustats, cpu);
-               pv = (void *)ps + (unsigned long)data;
-               sum += local_read(pv);
-       }
-       *val = sum;
-       return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
-
-extern struct dentry *mips_debugfs_dir;
-static int __init debugfs_fpuemu(void)
-{
-       struct dentry *d, *dir;
-
-       if (!mips_debugfs_dir)
-               return -ENODEV;
-       dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir);
-       if (!dir)
-               return -ENOMEM;
-
-#define FPU_STAT_CREATE(M)                                             \
-       do {                                                            \
-               d = debugfs_create_file(#M , S_IRUGO, dir,              \
-                       (void *)offsetof(struct mips_fpu_emulator_stats, M), \
-                       &fops_fpuemu_stat);                             \
-               if (!d)                                                 \
-                       return -ENOMEM;                                 \
-       } while (0)
-
-       FPU_STAT_CREATE(emulated);
-       FPU_STAT_CREATE(loads);
-       FPU_STAT_CREATE(stores);
-       FPU_STAT_CREATE(cp1ops);
-       FPU_STAT_CREATE(cp1xops);
-       FPU_STAT_CREATE(errors);
-
-       return 0;
-}
-__initcall(debugfs_fpuemu);
-#endif
index c57c8adc42c46aed52bfa6599b48f66b919080d0..7f64577df98492a9c721e237f15122933b8f26b2 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
- *
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
+union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y)
 {
+       int s;
+
        COMPXDP;
        COMPYDP;
 
        EXPLODEXDP;
        EXPLODEYDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXDP;
        FLUSHYDP;
@@ -52,8 +48,8 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "add", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -69,14 +65,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
                return x;
 
 
-               /* Infinity handling
-                */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
                if (xs == ys)
                        return x;
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
@@ -88,15 +84,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
                return x;
 
-               /* Zero handling
-                */
-
+       /*
+        * Zero handling
+        */
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
                if (xs == ys)
                        return x;
                else
-                       return ieee754dp_zero(ieee754_csr.rm ==
-                                             IEEE754_RD);
+                       return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
@@ -125,20 +120,24 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
        assert(xm & DP_HIDDEN_BIT);
        assert(ym & DP_HIDDEN_BIT);
 
-       /* provide guard,round and stick bit space */
+       /*
+        * Provide guard,round and stick bit space.
+        */
        xm <<= 3;
        ym <<= 3;
 
        if (xe > ye) {
-               /* have to shift y fraction right to align
+               /*
+                * Have to shift y fraction right to align.
                 */
-               int s = xe - ye;
+               s = xe - ye;
                ym = XDPSRS(ym, s);
                ye += s;
        } else if (ye > xe) {
-               /* have to shift x fraction right to align
+               /*
+                * Have to shift x fraction right to align.
                 */
-               int s = ye - xe;
+               s = ye - xe;
                xm = XDPSRS(xm, s);
                xe += s;
        }
@@ -146,14 +145,15 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
        assert(xe <= DP_EMAX);
 
        if (xs == ys) {
-               /* generate 28 bit result of adding two 27 bit numbers
-                * leaving result in xm,xs,xe
+               /*
+                * Generate 28 bit result of adding two 27 bit numbers
+                * leaving result in xm, xs and xe.
                 */
                xm = xm + ym;
                xe = xe;
                xs = xs;
 
-               if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */
+               if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */
                        xm = XDPSRS1(xm);
                        xe++;
                }
@@ -168,15 +168,16 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
                        xs = ys;
                }
                if (xm == 0)
-                       return ieee754dp_zero(ieee754_csr.rm ==
-                                             IEEE754_RD);
+                       return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
-               /* normalize to rounding precision */
-               while ((xm >> (DP_MBITS + 3)) == 0) {
+               /*
+                * Normalize to rounding precision.
+                */
+               while ((xm >> (DP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
-
        }
-       DPNORMRET2(xs, xe, xm, "add", x, y);
+
+       return ieee754dp_format(xs, xe, xm);
 }
index 0f32486b0ed9f09f32749bd321ebdba145948c2c..30f95f6e9ac443aa6ded22c80c453ef85167bc2c 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig)
+int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cmp, int sig)
 {
+       s64 vx;
+       s64 vy;
+
        COMPXDP;
        COMPYDP;
 
@@ -35,21 +33,21 @@ int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig)
        EXPLODEYDP;
        FLUSHXDP;
        FLUSHYDP;
-       CLEARCX;        /* Even clear inexact flag here */
+       ieee754_clearcx();      /* Even clear inexact flag here */
 
        if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) {
                if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
-                       SETCX(IEEE754_INVALID_OPERATION);
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
                if (cmp & IEEE754_CUN)
                        return 1;
                if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
-                       if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION))
-                               return ieee754si_xcpt(0, "fcmpf", x);
+                       if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION))
+                               return 0;
                }
                return 0;
        } else {
-               s64 vx = x.bits;
-               s64 vy = y.bits;
+               vx = x.bits;
+               vy = y.bits;
 
                if (vx < 0)
                        vx = -vx ^ DP_SIGN_BIT;
index a1bce1b7c09c8a116d079d4d86adc4ad2fb86039..bef0e55e59381e2b5c5d03b4970a0f8132a3b6b1 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
+union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y)
 {
+       u64 rm;
+       int re;
+       u64 bm;
+
        COMPXDP;
        COMPYDP;
 
        EXPLODEXDP;
        EXPLODEYDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXDP;
        FLUSHYDP;
@@ -51,8 +50,8 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "div", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,12 +67,12 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
                return x;
 
 
-               /* Infinity handling
-                */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
@@ -85,17 +84,17 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
                return ieee754dp_inf(xs ^ ys);
 
-               /* Zero handling
-                */
-
+       /*
+        * Zero handling
+        */
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-               SETCX(IEEE754_ZERO_DIVIDE);
-               return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y);
+               ieee754_setcx(IEEE754_ZERO_DIVIDE);
+               return ieee754dp_inf(xs ^ ys);
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
@@ -122,35 +121,34 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
        xm <<= 3;
        ym <<= 3;
 
-       {
-               /* now the dirty work */
-
-               u64 rm = 0;
-               int re = xe - ye;
-               u64 bm;
-
-               for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) {
-                       if (xm >= ym) {
-                               xm -= ym;
-                               rm |= bm;
-                               if (xm == 0)
-                                       break;
-                       }
-                       xm <<= 1;
-               }
-               rm <<= 1;
-               if (xm)
-                       rm |= 1;        /* have remainder, set sticky */
+       /* now the dirty work */
 
-               assert(rm);
+       rm = 0;
+       re = xe - ye;
 
-               /* normalise rm to rounding precision ?
-                */
-               while ((rm >> (DP_MBITS + 3)) == 0) {
-                       rm <<= 1;
-                       re--;
+       for (bm = DP_MBIT(DP_FBITS + 2); bm; bm >>= 1) {
+               if (xm >= ym) {
+                       xm -= ym;
+                       rm |= bm;
+                       if (xm == 0)
+                               break;
                }
+               xm <<= 1;
+       }
+
+       rm <<= 1;
+       if (xm)
+               rm |= 1;        /* have remainder, set sticky */
 
-               DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
+       assert(rm);
+
+       /*
+        * Normalise rm to rounding precision ?
+        */
+       while ((rm >> (DP_FBITS + 3)) == 0) {
+               rm <<= 1;
+               re--;
        }
+
+       return ieee754dp_format(xs == ys ? 0 : 1, re, rm);
 }
index 88571288c9e0044584f7fcf45def526ac9bd87bb..10258f0afd698f7fa6c5c2ed4214e45f54b2031b 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_fint(int x)
+union ieee754dp ieee754dp_fint(int x)
 {
        u64 xm;
        int xe;
        int xs;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        if (x == 0)
                return ieee754dp_zero(0);
@@ -51,29 +46,11 @@ ieee754dp ieee754dp_fint(int x)
                xm = x;
        }
 
-#if 1
        /* normalize - result can never be inexact or overflow */
-       xe = DP_MBITS;
-       while ((xm >> DP_MBITS) == 0) {
+       xe = DP_FBITS;
+       while ((xm >> DP_FBITS) == 0) {
                xm <<= 1;
                xe--;
        }
        return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-#else
-       /* normalize */
-       xe = DP_MBITS + 3;
-       while ((xm >> (DP_MBITS + 3)) == 0) {
-               xm <<= 1;
-               xe--;
-       }
-       DPNORMRET1(xs, xe, xm, "fint", x);
-#endif
-}
-
-ieee754dp ieee754dp_funs(unsigned int u)
-{
-       if ((int) u < 0)
-               return ieee754dp_add(ieee754dp_1e31(),
-                                    ieee754dp_fint(u & ~(1 << 31)));
-       return ieee754dp_fint(u);
 }
index 14fc01ec742d2c0d45833bdd610d7590a0ef2c49..a267c2e39d7832367dcc1af9ae38596be4a6348b 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_flong(s64 x)
+union ieee754dp ieee754dp_flong(s64 x)
 {
        u64 xm;
        int xe;
        int xs;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        if (x == 0)
                return ieee754dp_zero(0);
@@ -52,26 +47,19 @@ ieee754dp ieee754dp_flong(s64 x)
        }
 
        /* normalize */
-       xe = DP_MBITS + 3;
-       if (xm >> (DP_MBITS + 1 + 3)) {
+       xe = DP_FBITS + 3;
+       if (xm >> (DP_FBITS + 1 + 3)) {
                /* shunt out overflow bits */
-               while (xm >> (DP_MBITS + 1 + 3)) {
+               while (xm >> (DP_FBITS + 1 + 3)) {
                        XDPSRSX1();
                }
        } else {
                /* normalize in grs extended double precision */
-               while ((xm >> (DP_MBITS + 3)) == 0) {
+               while ((xm >> (DP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
        }
-       DPNORMRET1(xs, xe, xm, "dp_flong", x);
-}
 
-ieee754dp ieee754dp_fulong(u64 u)
-{
-       if ((s64) u < 0)
-               return ieee754dp_add(ieee754dp_1e63(),
-                                    ieee754dp_flong(u & ~(1ULL << 63)));
-       return ieee754dp_flong(u);
+       return ieee754dp_format(xs, xe, xm);
 }
diff --git a/arch/mips/math-emu/dp_frexp.c b/arch/mips/math-emu/dp_frexp.c
deleted file mode 100644 (file)
index cb15a5e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754dp.h"
-
-/* close to ieeep754dp_logb
-*/
-ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr)
-{
-       COMPXDP;
-       CLEARCX;
-       EXPLODEXDP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-       case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
-       case IEEE754_CLASS_ZERO:
-               *eptr = 0;
-               return x;
-       case IEEE754_CLASS_DNORM:
-               DPDNORMX;
-               break;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       *eptr = xe + 1;
-       return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-}
index daed6834dc153bbd543d2783a161003a699070b0..ffb69c5830b044c1bedd5e60773b430eae7bb322 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
+#include "ieee754sp.h"
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_fsp(ieee754sp x)
+union ieee754dp ieee754dp_fsp(union ieee754sp x)
 {
        COMPXSP;
 
        EXPLODEXSP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXSP;
 
        switch (xc) {
        case IEEE754_CLASS_SNAN:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "fsp");
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
+
        case IEEE754_CLASS_QNAN:
                return ieee754dp_nanxcpt(builddp(xs,
                                                 DP_EMAX + 1 + DP_EBIAS,
                                                 ((u64) xm
-                                                 << (DP_MBITS -
-                                                     SP_MBITS))), "fsp",
-                                        x);
+                                                 << (DP_FBITS -
+                                                     SP_FBITS))));
        case IEEE754_CLASS_INF:
                return ieee754dp_inf(xs);
+
        case IEEE754_CLASS_ZERO:
                return ieee754dp_zero(xs);
+
        case IEEE754_CLASS_DNORM:
                /* normalize */
-               while ((xm >> SP_MBITS) == 0) {
+               while ((xm >> SP_FBITS) == 0) {
                        xm <<= 1;
                        xe--;
                }
                break;
+
        case IEEE754_CLASS_NORM:
                break;
        }
 
-       /* CAN'T possibly overflow,underflow, or need rounding
+       /*
+        * Can't possibly overflow,underflow, or need rounding
         */
 
        /* drop the hidden bit */
        xm &= ~SP_HIDDEN_BIT;
 
        return builddp(xs, xe + DP_EBIAS,
-                      (u64) xm << (DP_MBITS - SP_MBITS));
+                      (u64) xm << (DP_FBITS - SP_FBITS));
 }
diff --git a/arch/mips/math-emu/dp_logb.c b/arch/mips/math-emu/dp_logb.c
deleted file mode 100644 (file)
index 151127e..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754dp.h"
-
-ieee754dp ieee754dp_logb(ieee754dp x)
-{
-       COMPXDP;
-
-       CLEARCX;
-
-       EXPLODEXDP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-               return ieee754dp_nanxcpt(x, "logb", x);
-       case IEEE754_CLASS_QNAN:
-               return x;
-       case IEEE754_CLASS_INF:
-               return ieee754dp_inf(0);
-       case IEEE754_CLASS_ZERO:
-               return ieee754dp_inf(1);
-       case IEEE754_CLASS_DNORM:
-               DPDNORMX;
-               break;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       return ieee754dp_fint(xe);
-}
diff --git a/arch/mips/math-emu/dp_modf.c b/arch/mips/math-emu/dp_modf.c
deleted file mode 100644 (file)
index b01f9cf..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754dp.h"
-
-/* modf function is always exact for a finite number
-*/
-ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp *ip)
-{
-       COMPXDP;
-
-       CLEARCX;
-
-       EXPLODEXDP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-       case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
-       case IEEE754_CLASS_ZERO:
-               *ip = x;
-               return x;
-       case IEEE754_CLASS_DNORM:
-               /* far to small */
-               *ip = ieee754dp_zero(xs);
-               return x;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       if (xe < 0) {
-               *ip = ieee754dp_zero(xs);
-               return x;
-       }
-       if (xe >= DP_MBITS) {
-               *ip = x;
-               return ieee754dp_zero(xs);
-       }
-       /* generate ipart mantissa by clearing bottom bits
-        */
-       *ip = builddp(xs, xe + DP_EBIAS,
-                     ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) &
-                     ~DP_HIDDEN_BIT);
-
-       /* generate fpart mantissa by clearing top bits
-        * and normalizing (must be able to normalize)
-        */
-       xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe));
-       if (xm == 0)
-               return ieee754dp_zero(xs);
-
-       while ((xm >> DP_MBITS) == 0) {
-               xm <<= 1;
-               xe--;
-       }
-       return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-}
index 09175f461920c0a41bbd0d29a57745feab9afd6a..d3acdedb5b9dd33053d7688af197a4d0e1f2d5de 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
+union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
 {
+       int re;
+       int rs;
+       u64 rm;
+       unsigned lxm;
+       unsigned hxm;
+       unsigned lym;
+       unsigned hym;
+       u64 lrm;
+       u64 hrm;
+       u64 t;
+       u64 at;
+
        COMPXDP;
        COMPYDP;
 
        EXPLODEXDP;
        EXPLODEYDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXDP;
        FLUSHYDP;
@@ -51,8 +58,8 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "mul", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,12 +75,13 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
                return x;
 
 
-               /* Infinity handling */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
@@ -107,70 +115,59 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
        /* rm = xm * ym, re = xe+ye basically */
        assert(xm & DP_HIDDEN_BIT);
        assert(ym & DP_HIDDEN_BIT);
-       {
-               int re = xe + ye;
-               int rs = xs ^ ys;
-               u64 rm;
 
-               /* shunt to top of word */
-               xm <<= 64 - (DP_MBITS + 1);
-               ym <<= 64 - (DP_MBITS + 1);
+       re = xe + ye;
+       rs = xs ^ ys;
+
+       /* shunt to top of word */
+       xm <<= 64 - (DP_FBITS + 1);
+       ym <<= 64 - (DP_FBITS + 1);
 
-               /* multiply 32bits xm,ym to give high 32bits rm with stickness
-                */
+       /*
+        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
+        */
 
-               /* 32 * 32 => 64 */
+       /* 32 * 32 => 64 */
 #define DPXMULT(x, y)  ((u64)(x) * (u64)y)
 
-               {
-                       unsigned lxm = xm;
-                       unsigned hxm = xm >> 32;
-                       unsigned lym = ym;
-                       unsigned hym = ym >> 32;
-                       u64 lrm;
-                       u64 hrm;
-
-                       lrm = DPXMULT(lxm, lym);
-                       hrm = DPXMULT(hxm, hym);
-
-                       {
-                               u64 t = DPXMULT(lxm, hym);
-                               {
-                                       u64 at =
-                                           lrm + (t << 32);
-                                       hrm += at < lrm;
-                                       lrm = at;
-                               }
-                               hrm = hrm + (t >> 32);
-                       }
-
-                       {
-                               u64 t = DPXMULT(hxm, lym);
-                               {
-                                       u64 at =
-                                           lrm + (t << 32);
-                                       hrm += at < lrm;
-                                       lrm = at;
-                               }
-                               hrm = hrm + (t >> 32);
-                       }
-                       rm = hrm | (lrm != 0);
-               }
-
-               /*
-                * sticky shift down to normal rounding precision
-                */
-               if ((s64) rm < 0) {
-                       rm =
-                           (rm >> (64 - (DP_MBITS + 1 + 3))) |
-                           ((rm << (DP_MBITS + 1 + 3)) != 0);
+       lxm = xm;
+       hxm = xm >> 32;
+       lym = ym;
+       hym = ym >> 32;
+
+       lrm = DPXMULT(lxm, lym);
+       hrm = DPXMULT(hxm, hym);
+
+       t = DPXMULT(lxm, hym);
+
+       at = lrm + (t << 32);
+       hrm += at < lrm;
+       lrm = at;
+
+       hrm = hrm + (t >> 32);
+
+       t = DPXMULT(hxm, lym);
+
+       at = lrm + (t << 32);
+       hrm += at < lrm;
+       lrm = at;
+
+       hrm = hrm + (t >> 32);
+
+       rm = hrm | (lrm != 0);
+
+       /*
+        * Sticky shift down to normal rounding precision.
+        */
+       if ((s64) rm < 0) {
+               rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
+                    ((rm << (DP_FBITS + 1 + 3)) != 0);
                        re++;
-               } else {
-                       rm =
-                           (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) |
-                           ((rm << (DP_MBITS + 1 + 3 + 1)) != 0);
-               }
-               assert(rm & (DP_HIDDEN_BIT << 3));
-               DPNORMRET2(rs, re, rm, "mul", x, y);
+       } else {
+               rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
+                    ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
        }
+       assert(rm & (DP_HIDDEN_BIT << 3));
+
+       return ieee754dp_format(rs, re, rm);
 }
diff --git a/arch/mips/math-emu/dp_scalb.c b/arch/mips/math-emu/dp_scalb.c
deleted file mode 100644 (file)
index 6f5df43..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754dp.h"
-
-ieee754dp ieee754dp_scalb(ieee754dp x, int n)
-{
-       COMPXDP;
-
-       CLEARCX;
-
-       EXPLODEXDP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-               return ieee754dp_nanxcpt(x, "scalb", x, n);
-       case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
-       case IEEE754_CLASS_ZERO:
-               return x;
-       case IEEE754_CLASS_DNORM:
-               DPDNORMX;
-               break;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
-}
-
-
-ieee754dp ieee754dp_ldexp(ieee754dp x, int n)
-{
-       return ieee754dp_scalb(x, n);
-}
index 79ce2673a71418e810d40a878160313834b415c8..bccbe90efceb9a00ef59ebe6689ddfd2117ca157 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-int ieee754dp_finite(ieee754dp x)
-{
-       return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS;
-}
-
-ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y)
-{
-       CLEARCX;
-       DPSIGN(x) = DPSIGN(y);
-       return x;
-}
-
-
-ieee754dp ieee754dp_neg(ieee754dp x)
+union ieee754dp ieee754dp_neg(union ieee754dp x)
 {
        COMPXDP;
 
        EXPLODEXDP;
-       CLEARCX;
+       ieee754_clearcx();
        FLUSHXDP;
 
        /*
@@ -55,30 +37,29 @@ ieee754dp ieee754dp_neg(ieee754dp x)
        DPSIGN(x) ^= 1;
 
        if (xc == IEEE754_CLASS_SNAN) {
-               ieee754dp y = ieee754dp_indef();
-               SETCX(IEEE754_INVALID_OPERATION);
+               union ieee754dp y = ieee754dp_indef();
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
                DPSIGN(y) = DPSIGN(x);
-               return ieee754dp_nanxcpt(y, "neg");
+               return ieee754dp_nanxcpt(y);
        }
 
        return x;
 }
 
-
-ieee754dp ieee754dp_abs(ieee754dp x)
+union ieee754dp ieee754dp_abs(union ieee754dp x)
 {
        COMPXDP;
 
        EXPLODEXDP;
-       CLEARCX;
+       ieee754_clearcx();
        FLUSHXDP;
 
        /* Clear sign ALWAYS, irrespective of NaN */
        DPSIGN(x) = 0;
 
        if (xc == IEEE754_CLASS_SNAN) {
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "abs");
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
        }
 
        return x;
index b874d60a942bd0fde028acd1c82f64546ee701a5..041bbb6124bbde5ec679e7a855f147bf02c24b23 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
 static const unsigned table[] = {
@@ -34,44 +29,49 @@ static const unsigned table[] = {
        1742, 661, 130
 };
 
-ieee754dp ieee754dp_sqrt(ieee754dp x)
+union ieee754dp ieee754dp_sqrt(union ieee754dp x)
 {
        struct _ieee754_csr oldcsr;
-       ieee754dp y, z, t;
+       union ieee754dp y, z, t;
        unsigned scalx, yh;
        COMPXDP;
 
        EXPLODEXDP;
-       CLEARCX;
+       ieee754_clearcx();
        FLUSHXDP;
 
        /* x == INF or NAN? */
        switch (xc) {
        case IEEE754_CLASS_QNAN:
                /* sqrt(Nan) = Nan */
-               return ieee754dp_nanxcpt(x, "sqrt");
+               return ieee754dp_nanxcpt(x);
+
        case IEEE754_CLASS_SNAN:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt");
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
+
        case IEEE754_CLASS_ZERO:
                /* sqrt(0) = 0 */
                return x;
+
        case IEEE754_CLASS_INF:
                if (xs) {
                        /* sqrt(-Inf) = Nan */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt");
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754dp_nanxcpt(ieee754dp_indef());
                }
                /* sqrt(+Inf) = Inf */
                return x;
+
        case IEEE754_CLASS_DNORM:
                DPDNORMX;
                /* fall through */
+
        case IEEE754_CLASS_NORM:
                if (xs) {
                        /* sqrt(-x) = Nan */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt");
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754dp_nanxcpt(ieee754dp_indef());
                }
                break;
        }
@@ -80,7 +80,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x)
        oldcsr = ieee754_csr;
        ieee754_csr.mx &= ~IEEE754_INEXACT;
        ieee754_csr.sx &= ~IEEE754_INEXACT;
-       ieee754_csr.rm = IEEE754_RN;
+       ieee754_csr.rm = FPU_CSR_RN;
 
        /* adjust exponent to prevent overflow */
        scalx = 0;
@@ -110,19 +110,19 @@ ieee754dp ieee754dp_sqrt(ieee754dp x)
        /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
        /* t=y*y; z=t;  pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
        z = t = ieee754dp_mul(y, y);
-       t.parts.bexp += 0x001;
+       t.bexp += 0x001;
        t = ieee754dp_add(t, z);
        z = ieee754dp_mul(ieee754dp_sub(x, z), y);
 
        /* t=z/(t+x) ;  pt[n0]+=0x00100000; y+=t; */
        t = ieee754dp_div(z, ieee754dp_add(t, x));
-       t.parts.bexp += 0x001;
+       t.bexp += 0x001;
        y = ieee754dp_add(y, t);
 
        /* twiddle last bit to force y correctly rounded */
 
        /* set RZ, clear INEX flag */
-       ieee754_csr.rm = IEEE754_RZ;
+       ieee754_csr.rm = FPU_CSR_RZ;
        ieee754_csr.sx &= ~IEEE754_INEXACT;
 
        /* t=x/y; ...chopped quotient, possibly inexact */
@@ -139,10 +139,10 @@ ieee754dp ieee754dp_sqrt(ieee754dp x)
                oldcsr.sx |= IEEE754_INEXACT;
 
                switch (oldcsr.rm) {
-               case IEEE754_RP:
+               case FPU_CSR_RU:
                        y.bits += 1;
                        /* drop through */
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        t.bits += 1;
                        break;
                }
@@ -155,7 +155,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x)
        }
 
        /* py[n0]=py[n0]+scalx; ...scale back y */
-       y.parts.bexp += scalx;
+       y.bexp += scalx;
 
        /* restore rounding mode, possibly set inexact */
        ieee754_csr = oldcsr;
index 91e0a4b5cbc76ebad10302781fcf753d09bec6dd..7a174029043a674348619f65de6d5433dd25b283 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
+union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y)
 {
+       int s;
+
        COMPXDP;
        COMPYDP;
 
        EXPLODEXDP;
        EXPLODEYDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXDP;
        FLUSHYDP;
@@ -51,8 +48,8 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "sub", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_nanxcpt(ieee754dp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,14 +65,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
                return x;
 
 
-               /* Infinity handling
-                */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
                if (xs != ys)
                        return x;
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754dp_indef();
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
@@ -87,15 +84,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
                return x;
 
-               /* Zero handling
-                */
-
+       /*
+        * Zero handling
+        */
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
                if (xs != ys)
                        return x;
                else
-                       return ieee754dp_zero(ieee754_csr.rm ==
-                                             IEEE754_RD);
+                       return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
@@ -136,15 +132,17 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
        ym <<= 3;
 
        if (xe > ye) {
-               /* have to shift y fraction right to align
+               /*
+                * Have to shift y fraction right to align
                 */
-               int s = xe - ye;
+               s = xe - ye;
                ym = XDPSRS(ym, s);
                ye += s;
        } else if (ye > xe) {
-               /* have to shift x fraction right to align
+               /*
+                * Have to shift x fraction right to align
                 */
-               int s = ye - xe;
+               s = ye - xe;
                xm = XDPSRS(xm, s);
                xe += s;
        }
@@ -158,7 +156,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
                xe = xe;
                xs = xs;
 
-               if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */
+               if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */
                        xm = XDPSRS1(xm);       /* shift preserving sticky */
                        xe++;
                }
@@ -173,7 +171,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
                        xs = ys;
                }
                if (xm == 0) {
-                       if (ieee754_csr.rm == IEEE754_RD)
+                       if (ieee754_csr.rm == FPU_CSR_RD)
                                return ieee754dp_zero(1);       /* round negative inf. => sign = -1 */
                        else
                                return ieee754dp_zero(0);       /* other round modes   => sign = 1 */
@@ -181,10 +179,11 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
 
                /* normalize to rounding precision
                 */
-               while ((xm >> (DP_MBITS + 3)) == 0) {
+               while ((xm >> (DP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
        }
-       DPNORMRET2(xs, xe, xm, "sub", x, y);
+
+       return ieee754dp_format(xs, xe, xm);
 }
index 0ebe8598b94ae6ad0f7542d3cd263d874d3c1c73..6ffc336c530e3e11c48c1dcb8ab9eb50224b7ff4 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
-#include <linux/kernel.h>
 #include "ieee754dp.h"
 
-int ieee754dp_tint(ieee754dp x)
+int ieee754dp_tint(union ieee754dp x)
 {
+       u64 residue;
+       int round;
+       int sticky;
+       int odd;
+
        COMPXDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        EXPLODEXDP;
        FLUSHXDP;
@@ -40,10 +39,12 @@ int ieee754dp_tint(ieee754dp x)
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
        case IEEE754_CLASS_INF:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754si_indef();
+
        case IEEE754_CLASS_ZERO:
                return 0;
+
        case IEEE754_CLASS_DNORM:
        case IEEE754_CLASS_NORM:
                break;
@@ -51,44 +52,39 @@ int ieee754dp_tint(ieee754dp x)
        if (xe > 31) {
                /* Set invalid. We will only use overflow for floating
                   point overflow */
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754si_indef();
        }
        /* oh gawd */
-       if (xe > DP_MBITS) {
-               xm <<= xe - DP_MBITS;
-       } else if (xe < DP_MBITS) {
-               u64 residue;
-               int round;
-               int sticky;
-               int odd;
-
+       if (xe > DP_FBITS) {
+               xm <<= xe - DP_FBITS;
+       } else if (xe < DP_FBITS) {
                if (xe < -1) {
                        residue = xm;
                        round = 0;
                        sticky = residue != 0;
                        xm = 0;
                } else {
-                       residue = xm << (64 - DP_MBITS + xe);
+                       residue = xm << (64 - DP_FBITS + xe);
                        round = (residue >> 63) != 0;
                        sticky = (residue << 1) != 0;
-                       xm >>= DP_MBITS - xe;
+                       xm >>= DP_FBITS - xe;
                }
                /* Note: At this point upper 32 bits of xm are guaranteed
                   to be zero */
                odd = (xm & 0x1) != 0x0;
                switch (ieee754_csr.rm) {
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        if (round && (sticky || odd))
                                xm++;
                        break;
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        break;
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if ((round || sticky) && !xs)
                                xm++;
                        break;
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if ((round || sticky) && xs)
                                xm++;
                        break;
@@ -96,27 +92,14 @@ int ieee754dp_tint(ieee754dp x)
                /* look for valid corner case 0x80000000 */
                if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) {
                        /* This can happen after rounding */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x);
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754si_indef();
                }
                if (round || sticky)
-                       SETCX(IEEE754_INEXACT);
+                       ieee754_setcx(IEEE754_INEXACT);
        }
        if (xs)
                return -xm;
        else
                return xm;
 }
-
-
-unsigned int ieee754dp_tuns(ieee754dp x)
-{
-       ieee754dp hb = ieee754dp_1e31();
-
-       /* what if x < 0 ?? */
-       if (ieee754dp_lt(x, hb))
-               return (unsigned) ieee754dp_tint(x);
-
-       return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) |
-           ((unsigned) 1 << 31);
-}
index 133ce2ba0012eb61e09a4a5729cf25bb32ea82e3..9cdc145b75e012d75a22f146c1e3c3b5c65a4e7f 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754dp.h"
 
-s64 ieee754dp_tlong(ieee754dp x)
+s64 ieee754dp_tlong(union ieee754dp x)
 {
+       u64 residue;
+       int round;
+       int sticky;
+       int odd;
+
        COMPXDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        EXPLODEXDP;
        FLUSHXDP;
@@ -39,10 +39,12 @@ s64 ieee754dp_tlong(ieee754dp x)
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
        case IEEE754_CLASS_INF:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754di_indef();
+
        case IEEE754_CLASS_ZERO:
                return 0;
+
        case IEEE754_CLASS_DNORM:
        case IEEE754_CLASS_NORM:
                break;
@@ -53,18 +55,13 @@ s64 ieee754dp_tlong(ieee754dp x)
                        return -0x8000000000000000LL;
                /* Set invalid. We will only use overflow for floating
                   point overflow */
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754di_indef();
        }
        /* oh gawd */
-       if (xe > DP_MBITS) {
-               xm <<= xe - DP_MBITS;
-       } else if (xe < DP_MBITS) {
-               u64 residue;
-               int round;
-               int sticky;
-               int odd;
-
+       if (xe > DP_FBITS) {
+               xm <<= xe - DP_FBITS;
+       } else if (xe < DP_FBITS) {
                if (xe < -1) {
                        residue = xm;
                        round = 0;
@@ -75,51 +72,38 @@ s64 ieee754dp_tlong(ieee754dp x)
                        * so we do it in two steps. Be aware that xe
                        * may be -1 */
                        residue = xm << (xe + 1);
-                       residue <<= 63 - DP_MBITS;
+                       residue <<= 63 - DP_FBITS;
                        round = (residue >> 63) != 0;
                        sticky = (residue << 1) != 0;
-                       xm >>= DP_MBITS - xe;
+                       xm >>= DP_FBITS - xe;
                }
                odd = (xm & 0x1) != 0x0;
                switch (ieee754_csr.rm) {
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        if (round && (sticky || odd))
                                xm++;
                        break;
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        break;
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if ((round || sticky) && !xs)
                                xm++;
                        break;
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if ((round || sticky) && xs)
                                xm++;
                        break;
                }
                if ((xm >> 63) != 0) {
                        /* This can happen after rounding */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754di_indef();
                }
                if (round || sticky)
-                       SETCX(IEEE754_INEXACT);
+                       ieee754_setcx(IEEE754_INEXACT);
        }
        if (xs)
                return -xm;
        else
                return xm;
 }
-
-
-u64 ieee754dp_tulong(ieee754dp x)
-{
-       ieee754dp hb = ieee754dp_1e63();
-
-       /* what if x < 0 ?? */
-       if (ieee754dp_lt(x, hb))
-               return (u64) ieee754dp_tlong(x);
-
-       return (u64) ieee754dp_tlong(ieee754dp_sub(x, hb)) |
-           (1ULL << 63);
-}
index 7ea622ab8dad32df6bf1fbd8d07bffdbf48c3f72..4f514f3724cb9e819276d2cf34ad8b83f722d74a 100644 (file)
@@ -1,30 +1,12 @@
-#include <linux/compiler.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/smp.h>
-
-#include <asm/asm.h>
-#include <asm/bootinfo.h>
-#include <asm/byteorder.h>
-#include <asm/cpu.h>
-#include <asm/inst.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
 #include <asm/branch.h>
-#include <asm/mipsregs.h>
 #include <asm/cacheflush.h>
-
 #include <asm/fpu_emulator.h>
+#include <asm/inst.h>
+#include <asm/mipsregs.h>
+#include <asm/uaccess.h>
 
 #include "ieee754.h"
 
-/* Strap kernel emulator for full MIPS IV emulation */
-
-#ifdef __mips
-#undef __mips
-#endif
-#define __mips 4
-
 /*
  * Emulate the arbritrary instruction ir at xcp->cp0_epc.  Required when
  * we have to emulate the instruction in a COP1 branch delay slot.  Do
@@ -59,13 +41,11 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
                (ir == 0)) {
                /* NOP is easy */
                regs->cp0_epc = cpc;
-               regs->cp0_cause &= ~CAUSEF_BD;
+               clear_delay_slot(regs);
                return 0;
        }
-#ifdef DSEMUL_TRACE
-       printk("dsemul %lx %lx\n", regs->cp0_epc, cpc);
 
-#endif
+       pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc);
 
        /*
         * The strategy is to push the instruction onto the user stack
@@ -167,9 +147,8 @@ int do_dsemulret(struct pt_regs *xcp)
         * emulating the branch delay instruction.
         */
 
-#ifdef DSEMUL_TRACE
-       printk("dsemulret\n");
-#endif
+       pr_debug("dsemulret\n");
+
        if (__get_user(epc, &fr->epc)) {                /* Saved EPC */
                /* This is not a good situation to be in */
                force_sig(SIGBUS, current);
index 0015cf1989dad3f87e823a0f6b2d1261c123c7ff..53f1d2287084099e3a683f897963c554d247d71c 100644 (file)
@@ -10,8 +10,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
+#include <linux/compiler.h>
 
-#include "ieee754int.h"
+#include "ieee754.h"
 #include "ieee754sp.h"
 #include "ieee754dp.h"
 
-#define DP_EBIAS       1023
-#define DP_EMIN                (-1022)
-#define DP_EMAX                1023
-
-#define SP_EBIAS       127
-#define SP_EMIN                (-126)
-#define SP_EMAX                127
-
-/* special constants
-*/
-
-
-#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
-#define SPSTR(s, b, m) {m, b, s}
-#define DPSTR(s, b, mh, ml) {ml, mh, b, s}
-#endif
-
-#ifdef __MIPSEB__
-#define SPSTR(s, b, m) {s, b, m}
-#define DPSTR(s, b, mh, ml) {s, b, mh, ml}
-#endif
+/*
+ * Special constants
+ */
 
-const struct ieee754dp_konst __ieee754dp_spcvals[] = {
-       DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero   */
-       DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero   */
-       DPSTR(0, DP_EBIAS, 0, 0),       /* + 1.0   */
-       DPSTR(1, DP_EBIAS, 0, 0),       /* - 1.0   */
-       DPSTR(0, 3 + DP_EBIAS, 0x40000, 0),     /* + 10.0   */
-       DPSTR(1, 3 + DP_EBIAS, 0x40000, 0),     /* - 10.0   */
-       DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */
-       DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */
-       DPSTR(0, DP_EMAX+1+DP_EBIAS, 0x7FFFF, 0xFFFFFFFF), /* + indef quiet Nan */
-       DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF),      /* + max */
-       DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF),      /* - max */
-       DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0),     /* + min normal */
-       DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0),     /* - min normal */
-       DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */
-       DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */
-       DPSTR(0, 31 + DP_EBIAS, 0, 0),  /* + 1.0e31 */
-       DPSTR(0, 63 + DP_EBIAS, 0, 0),  /* + 1.0e63 */
-};
+#define DPCNST(s, b, m)                                                        \
+{                                                                      \
+       .sign   = (s),                                                  \
+       .bexp   = (b) + DP_EBIAS,                                       \
+       .mant   = (m)                                                   \
+}
 
-const struct ieee754sp_konst __ieee754sp_spcvals[] = {
-       SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0),    /* + zero   */
-       SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0),    /* - zero   */
-       SPSTR(0, SP_EBIAS, 0),  /* + 1.0   */
-       SPSTR(1, SP_EBIAS, 0),  /* - 1.0   */
-       SPSTR(0, 3 + SP_EBIAS, 0x200000),       /* + 10.0   */
-       SPSTR(1, 3 + SP_EBIAS, 0x200000),       /* - 10.0   */
-       SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0),    /* + infinity */
-       SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0),    /* - infinity */
-       SPSTR(0, SP_EMAX+1+SP_EBIAS, 0x3FFFFF),     /* + indef quiet Nan  */
-       SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */
-       SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */
-       SPSTR(0, SP_EMIN + SP_EBIAS, 0),        /* + min normal */
-       SPSTR(1, SP_EMIN + SP_EBIAS, 0),        /* - min normal */
-       SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1),    /* + min denormal */
-       SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1),    /* - min denormal */
-       SPSTR(0, 31 + SP_EBIAS, 0),     /* + 1.0e31 */
-       SPSTR(0, 63 + SP_EBIAS, 0),     /* + 1.0e63 */
+const union ieee754dp __ieee754dp_spcvals[] = {
+       DPCNST(0, DP_EMIN - 1, 0x0000000000000ULL),     /* + zero   */
+       DPCNST(1, DP_EMIN - 1, 0x0000000000000ULL),     /* - zero   */
+       DPCNST(0, 0,           0x0000000000000ULL),     /* + 1.0   */
+       DPCNST(1, 0,           0x0000000000000ULL),     /* - 1.0   */
+       DPCNST(0, 3,           0x4000000000000ULL),     /* + 10.0   */
+       DPCNST(1, 3,           0x4000000000000ULL),     /* - 10.0   */
+       DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL),     /* + infinity */
+       DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL),     /* - infinity */
+       DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),     /* + indef quiet Nan */
+       DPCNST(0, DP_EMAX,     0xFFFFFFFFFFFFFULL),     /* + max */
+       DPCNST(1, DP_EMAX,     0xFFFFFFFFFFFFFULL),     /* - max */
+       DPCNST(0, DP_EMIN,     0x0000000000000ULL),     /* + min normal */
+       DPCNST(1, DP_EMIN,     0x0000000000000ULL),     /* - min normal */
+       DPCNST(0, DP_EMIN - 1, 0x0000000000001ULL),     /* + min denormal */
+       DPCNST(1, DP_EMIN - 1, 0x0000000000001ULL),     /* - min denormal */
+       DPCNST(0, 31,          0x0000000000000ULL),     /* + 1.0e31 */
+       DPCNST(0, 63,          0x0000000000000ULL),     /* + 1.0e63 */
 };
 
-
-int ieee754si_xcpt(int r, const char *op, ...)
-{
-       struct ieee754xctx ax;
-
-       if (!TSTX())
-               return r;
-       ax.op = op;
-       ax.rt = IEEE754_RT_SI;
-       ax.rv.si = r;
-       va_start(ax.ap, op);
-       ieee754_xcpt(&ax);
-       va_end(ax.ap);
-       return ax.rv.si;
+#define SPCNST(s, b, m)                                                        \
+{                                                                      \
+       .sign   = (s),                                                  \
+       .bexp   = (b) + SP_EBIAS,                                       \
+       .mant   = (m)                                                   \
 }
 
-s64 ieee754di_xcpt(s64 r, const char *op, ...)
-{
-       struct ieee754xctx ax;
-
-       if (!TSTX())
-               return r;
-       ax.op = op;
-       ax.rt = IEEE754_RT_DI;
-       ax.rv.di = r;
-       va_start(ax.ap, op);
-       ieee754_xcpt(&ax);
-       va_end(ax.ap);
-       return ax.rv.di;
-}
+const union ieee754sp __ieee754sp_spcvals[] = {
+       SPCNST(0, SP_EMIN - 1, 0x000000),       /* + zero   */
+       SPCNST(1, SP_EMIN - 1, 0x000000),       /* - zero   */
+       SPCNST(0, 0,           0x000000),       /* + 1.0   */
+       SPCNST(1, 0,           0x000000),       /* - 1.0   */
+       SPCNST(0, 3,           0x200000),       /* + 10.0   */
+       SPCNST(1, 3,           0x200000),       /* - 10.0   */
+       SPCNST(0, SP_EMAX + 1, 0x000000),       /* + infinity */
+       SPCNST(1, SP_EMAX + 1, 0x000000),       /* - infinity */
+       SPCNST(0, SP_EMAX + 1, 0x3FFFFF),       /* + indef quiet Nan  */
+       SPCNST(0, SP_EMAX,     0x7FFFFF),       /* + max normal */
+       SPCNST(1, SP_EMAX,     0x7FFFFF),       /* - max normal */
+       SPCNST(0, SP_EMIN,     0x000000),       /* + min normal */
+       SPCNST(1, SP_EMIN,     0x000000),       /* - min normal */
+       SPCNST(0, SP_EMIN - 1, 0x000001),       /* + min denormal */
+       SPCNST(1, SP_EMIN - 1, 0x000001),       /* - min denormal */
+       SPCNST(0, 31,          0x000000),       /* + 1.0e31 */
+       SPCNST(0, 63,          0x000000),       /* + 1.0e63 */
+};
index 22796e0120607157abb40b91d5467f6761735c9d..43c4fb522ac2d4d609211b93a75830f231207ad8 100644 (file)
@@ -13,7 +13,7 @@
  *
  *  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.
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  *
  *  Nov 7, 2000
  *  Modification to allow integration with Linux kernel
 #ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H
 #define __ARCH_MIPS_MATH_EMU_IEEE754_H
 
+#include <linux/compiler.h>
 #include <asm/byteorder.h>
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <asm/bitfield.h>
 
-/*
- * Not very pretty, but the Linux kernel's normal va_list definition
- * does not allow it to be used as a structure element, as it is here.
- */
-#ifndef _STDARG_H
-#include <stdarg.h>
-#endif
-
-#ifdef __LITTLE_ENDIAN
-struct ieee754dp_konst {
-       unsigned mantlo:32;
-       unsigned manthi:20;
-       unsigned bexp:11;
-       unsigned sign:1;
-};
-struct ieee754sp_konst {
-       unsigned mant:23;
-       unsigned bexp:8;
-       unsigned sign:1;
-};
-
-typedef union _ieee754dp {
-       struct ieee754dp_konst oparts;
+union ieee754dp {
        struct {
-               u64 mant:52;
-               unsigned int bexp:11;
-               unsigned int sign:1;
-       } parts;
+               __BITFIELD_FIELD(unsigned int sign:1,
+               __BITFIELD_FIELD(unsigned int bexp:11,
+               __BITFIELD_FIELD(u64 mant:52,
+               ;)))
+       };
        u64 bits;
-       double d;
-} ieee754dp;
-
-typedef union _ieee754sp {
-       struct ieee754sp_konst parts;
-       float f;
-       u32 bits;
-} ieee754sp;
-#endif
-
-#ifdef __BIG_ENDIAN
-struct ieee754dp_konst {
-       unsigned sign:1;
-       unsigned bexp:11;
-       unsigned manthi:20;
-       unsigned mantlo:32;
 };
 
-typedef union _ieee754dp {
-       struct ieee754dp_konst oparts;
+union ieee754sp {
        struct {
-               unsigned int sign:1;
-               unsigned int bexp:11;
-               u64 mant:52;
-       } parts;
-       double d;
-       u64 bits;
-} ieee754dp;
-
-struct ieee754sp_konst {
-       unsigned sign:1;
-       unsigned bexp:8;
-       unsigned mant:23;
-};
-
-typedef union _ieee754sp {
-       struct ieee754sp_konst parts;
-       float f;
+               __BITFIELD_FIELD(unsigned sign:1,
+               __BITFIELD_FIELD(unsigned bexp:8,
+               __BITFIELD_FIELD(unsigned mant:23,
+               ;)))
+       };
        u32 bits;
-} ieee754sp;
-#endif
+};
 
 /*
  * single precision (often aka float)
 */
-int ieee754sp_finite(ieee754sp x);
-int ieee754sp_class(ieee754sp x);
-
-ieee754sp ieee754sp_abs(ieee754sp x);
-ieee754sp ieee754sp_neg(ieee754sp x);
-ieee754sp ieee754sp_scalb(ieee754sp x, int);
-ieee754sp ieee754sp_logb(ieee754sp x);
-
-/* x with sign of y */
-ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y);
-
-ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y);
-ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y);
-ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y);
-ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y);
-
-ieee754sp ieee754sp_fint(int x);
-ieee754sp ieee754sp_funs(unsigned x);
-ieee754sp ieee754sp_flong(s64 x);
-ieee754sp ieee754sp_fulong(u64 x);
-ieee754sp ieee754sp_fdp(ieee754dp x);
-
-int ieee754sp_tint(ieee754sp x);
-unsigned int ieee754sp_tuns(ieee754sp x);
-s64 ieee754sp_tlong(ieee754sp x);
-u64 ieee754sp_tulong(ieee754sp x);
-
-int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop, int sig);
-/*
- * basic sp math
- */
-ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip);
-ieee754sp ieee754sp_frexp(ieee754sp x, int *exp);
-ieee754sp ieee754sp_ldexp(ieee754sp x, int exp);
+int ieee754sp_class(union ieee754sp x);
 
-ieee754sp ieee754sp_ceil(ieee754sp x);
-ieee754sp ieee754sp_floor(ieee754sp x);
-ieee754sp ieee754sp_trunc(ieee754sp x);
+union ieee754sp ieee754sp_abs(union ieee754sp x);
+union ieee754sp ieee754sp_neg(union ieee754sp x);
 
-ieee754sp ieee754sp_sqrt(ieee754sp x);
+union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y);
+union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y);
+union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y);
+union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y);
 
-/*
- * double precision (often aka double)
-*/
-int ieee754dp_finite(ieee754dp x);
-int ieee754dp_class(ieee754dp x);
+union ieee754sp ieee754sp_fint(int x);
+union ieee754sp ieee754sp_flong(s64 x);
+union ieee754sp ieee754sp_fdp(union ieee754dp x);
 
-/* x with sign of y */
-ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y);
+int ieee754sp_tint(union ieee754sp x);
+s64 ieee754sp_tlong(union ieee754sp x);
 
-ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y);
-ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y);
-ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y);
-ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y);
+int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig);
 
-ieee754dp ieee754dp_abs(ieee754dp x);
-ieee754dp ieee754dp_neg(ieee754dp x);
-ieee754dp ieee754dp_scalb(ieee754dp x, int);
+union ieee754sp ieee754sp_sqrt(union ieee754sp x);
 
-/* return exponent as integer in floating point format
- */
-ieee754dp ieee754dp_logb(ieee754dp x);
+/*
+ * double precision (often aka double)
+*/
+int ieee754dp_class(union ieee754dp x);
 
-ieee754dp ieee754dp_fint(int x);
-ieee754dp ieee754dp_funs(unsigned x);
-ieee754dp ieee754dp_flong(s64 x);
-ieee754dp ieee754dp_fulong(u64 x);
-ieee754dp ieee754dp_fsp(ieee754sp x);
+union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y);
+union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y);
+union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y);
+union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y);
 
-ieee754dp ieee754dp_ceil(ieee754dp x);
-ieee754dp ieee754dp_floor(ieee754dp x);
-ieee754dp ieee754dp_trunc(ieee754dp x);
+union ieee754dp ieee754dp_abs(union ieee754dp x);
+union ieee754dp ieee754dp_neg(union ieee754dp x);
 
-int ieee754dp_tint(ieee754dp x);
-unsigned int ieee754dp_tuns(ieee754dp x);
-s64 ieee754dp_tlong(ieee754dp x);
-u64 ieee754dp_tulong(ieee754dp x);
+union ieee754dp ieee754dp_fint(int x);
+union ieee754dp ieee754dp_flong(s64 x);
+union ieee754dp ieee754dp_fsp(union ieee754sp x);
 
-int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig);
-/*
- * basic sp math
- */
-ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip);
-ieee754dp ieee754dp_frexp(ieee754dp x, int *exp);
-ieee754dp ieee754dp_ldexp(ieee754dp x, int exp);
+int ieee754dp_tint(union ieee754dp x);
+s64 ieee754dp_tlong(union ieee754dp x);
 
-ieee754dp ieee754dp_ceil(ieee754dp x);
-ieee754dp ieee754dp_floor(ieee754dp x);
-ieee754dp ieee754dp_trunc(ieee754dp x);
+int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig);
 
-ieee754dp ieee754dp_sqrt(ieee754dp x);
+union ieee754dp ieee754dp_sqrt(union ieee754dp x);
 
 
 
 /* 5 types of floating point number
 */
-#define IEEE754_CLASS_NORM     0x00
-#define IEEE754_CLASS_ZERO     0x01
-#define IEEE754_CLASS_DNORM    0x02
-#define IEEE754_CLASS_INF      0x03
-#define IEEE754_CLASS_SNAN     0x04
-#define IEEE754_CLASS_QNAN     0x05
+enum {
+       IEEE754_CLASS_NORM      = 0x00,
+       IEEE754_CLASS_ZERO      = 0x01,
+       IEEE754_CLASS_DNORM     = 0x02,
+       IEEE754_CLASS_INF       = 0x03,
+       IEEE754_CLASS_SNAN      = 0x04,
+       IEEE754_CLASS_QNAN      = 0x05,
+};
 
 /* exception numbers */
 #define IEEE754_INEXACT                        0x01
@@ -219,114 +126,84 @@ ieee754dp ieee754dp_sqrt(ieee754dp x);
 #define IEEE754_CGT    0x04
 #define IEEE754_CUN    0x08
 
-/* rounding mode
-*/
-#define IEEE754_RN     0       /* round to nearest */
-#define IEEE754_RZ     1       /* round toward zero  */
-#define IEEE754_RD     2       /* round toward -Infinity */
-#define IEEE754_RU     3       /* round toward +Infinity */
-
-/* other naming */
-#define IEEE754_RM     IEEE754_RD
-#define IEEE754_RP     IEEE754_RU
-
 /* "normal" comparisons
 */
-static inline int ieee754sp_eq(ieee754sp x, ieee754sp y)
+static inline int ieee754sp_eq(union ieee754sp x, union ieee754sp y)
 {
        return ieee754sp_cmp(x, y, IEEE754_CEQ, 0);
 }
 
-static inline int ieee754sp_ne(ieee754sp x, ieee754sp y)
+static inline int ieee754sp_ne(union ieee754sp x, union ieee754sp y)
 {
        return ieee754sp_cmp(x, y,
                             IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0);
 }
 
-static inline int ieee754sp_lt(ieee754sp x, ieee754sp y)
+static inline int ieee754sp_lt(union ieee754sp x, union ieee754sp y)
 {
        return ieee754sp_cmp(x, y, IEEE754_CLT, 0);
 }
 
-static inline int ieee754sp_le(ieee754sp x, ieee754sp y)
+static inline int ieee754sp_le(union ieee754sp x, union ieee754sp y)
 {
        return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0);
 }
 
-static inline int ieee754sp_gt(ieee754sp x, ieee754sp y)
+static inline int ieee754sp_gt(union ieee754sp x, union ieee754sp y)
 {
        return ieee754sp_cmp(x, y, IEEE754_CGT, 0);
 }
 
 
-static inline int ieee754sp_ge(ieee754sp x, ieee754sp y)
+static inline int ieee754sp_ge(union ieee754sp x, union ieee754sp y)
 {
        return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0);
 }
 
-static inline int ieee754dp_eq(ieee754dp x, ieee754dp y)
+static inline int ieee754dp_eq(union ieee754dp x, union ieee754dp y)
 {
        return ieee754dp_cmp(x, y, IEEE754_CEQ, 0);
 }
 
-static inline int ieee754dp_ne(ieee754dp x, ieee754dp y)
+static inline int ieee754dp_ne(union ieee754dp x, union ieee754dp y)
 {
        return ieee754dp_cmp(x, y,
                             IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0);
 }
 
-static inline int ieee754dp_lt(ieee754dp x, ieee754dp y)
+static inline int ieee754dp_lt(union ieee754dp x, union ieee754dp y)
 {
        return ieee754dp_cmp(x, y, IEEE754_CLT, 0);
 }
 
-static inline int ieee754dp_le(ieee754dp x, ieee754dp y)
+static inline int ieee754dp_le(union ieee754dp x, union ieee754dp y)
 {
        return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0);
 }
 
-static inline int ieee754dp_gt(ieee754dp x, ieee754dp y)
+static inline int ieee754dp_gt(union ieee754dp x, union ieee754dp y)
 {
        return ieee754dp_cmp(x, y, IEEE754_CGT, 0);
 }
 
-static inline int ieee754dp_ge(ieee754dp x, ieee754dp y)
+static inline int ieee754dp_ge(union ieee754dp x, union ieee754dp y)
 {
        return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0);
 }
 
-
-/*
- * Like strtod
- */
-ieee754dp ieee754dp_fstr(const char *s, char **endp);
-char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af);
-
-
 /*
  * The control status register
  */
 struct _ieee754_csr {
-#ifdef __BIG_ENDIAN
-       unsigned pad0:7;
-       unsigned nod:1;         /* set 1 for no denormalised numbers */
-       unsigned c:1;           /* condition */
-       unsigned pad1:5;
-       unsigned cx:6;          /* exceptions this operation */
-       unsigned mx:5;          /* exception enable  mask */
-       unsigned sx:5;          /* exceptions total */
-       unsigned rm:2;          /* current rounding mode */
-#endif
-#ifdef __LITTLE_ENDIAN
-       unsigned rm:2;          /* current rounding mode */
-       unsigned sx:5;          /* exceptions total */
-       unsigned mx:5;          /* exception enable  mask */
-       unsigned cx:6;          /* exceptions this operation */
-       unsigned pad1:5;
-       unsigned c:1;           /* condition */
-       unsigned nod:1;         /* set 1 for no denormalised numbers */
-       unsigned pad0:7;
-#endif
+       __BITFIELD_FIELD(unsigned pad0:7,
+       __BITFIELD_FIELD(unsigned nod:1,        /* set 1 for no denormalised numbers */
+       __BITFIELD_FIELD(unsigned c:1,          /* condition */
+       __BITFIELD_FIELD(unsigned pad1:5,
+       __BITFIELD_FIELD(unsigned cx:6,         /* exceptions this operation */
+       __BITFIELD_FIELD(unsigned mx:5,         /* exception enable  mask */
+       __BITFIELD_FIELD(unsigned sx:5,         /* exceptions total */
+       __BITFIELD_FIELD(unsigned rm:2,         /* current rounding mode */
+       ;))))))))
 };
 #define ieee754_csr (*(struct _ieee754_csr *)(&current->thread.fpu.fcr31))
 
@@ -377,8 +254,8 @@ static inline int ieee754_sxtest(unsigned n)
 }
 
 /* debugging */
-ieee754sp ieee754sp_dump(char *s, ieee754sp x);
-ieee754dp ieee754dp_dump(char *s, ieee754dp x);
+union ieee754sp ieee754sp_dump(char *s, union ieee754sp x);
+union ieee754dp ieee754dp_dump(char *s, union ieee754dp x);
 
 #define IEEE754_SPCVAL_PZERO   0
 #define IEEE754_SPCVAL_NZERO   1
@@ -398,10 +275,10 @@ ieee754dp ieee754dp_dump(char *s, ieee754dp x);
 #define IEEE754_SPCVAL_P1E31   15      /* + 1.0e31 */
 #define IEEE754_SPCVAL_P1E63   16      /* + 1.0e63 */
 
-extern const struct ieee754dp_konst __ieee754dp_spcvals[];
-extern const struct ieee754sp_konst __ieee754sp_spcvals[];
-#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals)
-#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals)
+extern const union ieee754dp __ieee754dp_spcvals[];
+extern const union ieee754sp __ieee754sp_spcvals[];
+#define ieee754dp_spcvals ((const union ieee754dp *)__ieee754dp_spcvals)
+#define ieee754sp_spcvals ((const union ieee754sp *)__ieee754sp_spcvals)
 
 /*
  * Return infinity with given sign
@@ -431,28 +308,15 @@ extern const struct ieee754sp_konst __ieee754sp_spcvals[];
 /*
  * Indefinite integer value
  */
-#define ieee754si_indef()      INT_MAX
-#ifdef LONG_LONG_MAX
-#define ieee754di_indef()      LONG_LONG_MAX
-#else
-#define ieee754di_indef()      ((s64)(~0ULL>>1))
-#endif
-
-/* IEEE exception context, passed to handler */
-struct ieee754xctx {
-       const char *op;         /* operation name */
-       int rt;                 /* result type */
-       union {
-               ieee754sp sp;   /* single precision */
-               ieee754dp dp;   /* double precision */
-#ifdef IEEE854_XP
-               ieee754xp xp;   /* extended precision */
-#endif
-               int si;         /* standard signed integer (32bits) */
-               s64 di;         /* extended signed integer (64bits) */
-       } rv;                   /* default result format implied by op */
-       va_list ap;
-};
+static inline int ieee754si_indef(void)
+{
+       return INT_MAX;
+}
+
+static inline s64 ieee754di_indef(void)
+{
+       return S64_MAX;
+}
 
 /* result types for xctx.rt */
 #define IEEE754_RT_SP  0
@@ -461,8 +325,6 @@ struct ieee754xctx {
 #define IEEE754_RT_SI  3
 #define IEEE754_RT_DI  4
 
-extern void ieee754_xcpt(struct ieee754xctx *xcp);
-
 /* compat */
 #define ieee754dp_fix(x)       ieee754dp_tint(x)
 #define ieee754sp_fix(x)       ieee754sp_tint(x)
index 9599bdd32585c2d016a98f87c78ed99066fb9586..a04e8a7e5ac37b5ace56bbb0993741d7e001e951 100644 (file)
@@ -16,7 +16,7 @@
  *
  *  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.
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  *
  *  Nov 7, 2000
  *  Modified to build and operate in Linux kernel environment.
  *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
  */
 
-#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/printk.h>
 #include "ieee754.h"
+#include "ieee754sp.h"
+#include "ieee754dp.h"
 
-#define DP_EBIAS       1023
-#define DP_EMIN                (-1022)
-#define DP_EMAX                1023
-#define DP_FBITS       52
-
-#define SP_EBIAS       127
-#define SP_EMIN                (-126)
-#define SP_EMAX                127
-#define SP_FBITS       23
-
-#define DP_MBIT(x)     ((u64)1 << (x))
-#define DP_HIDDEN_BIT  DP_MBIT(DP_FBITS)
-#define DP_SIGN_BIT    DP_MBIT(63)
-
-
-#define SP_MBIT(x)     ((u32)1 << (x))
-#define SP_HIDDEN_BIT  SP_MBIT(SP_FBITS)
-#define SP_SIGN_BIT    SP_MBIT(31)
-
-
-#define SPSIGN(sp)     (sp.parts.sign)
-#define SPBEXP(sp)     (sp.parts.bexp)
-#define SPMANT(sp)     (sp.parts.mant)
-
-#define DPSIGN(dp)     (dp.parts.sign)
-#define DPBEXP(dp)     (dp.parts.bexp)
-#define DPMANT(dp)     (dp.parts.mant)
-
-ieee754dp ieee754dp_dump(char *m, ieee754dp x)
+union ieee754dp ieee754dp_dump(char *m, union ieee754dp x)
 {
        int i;
 
@@ -96,7 +71,7 @@ ieee754dp ieee754dp_dump(char *m, ieee754dp x)
        return x;
 }
 
-ieee754sp ieee754sp_dump(char *m, ieee754sp x)
+union ieee754sp ieee754sp_dump(char *m, union ieee754sp x)
 {
        int i;
 
index 068e56be8de91227c3ec8c65ca2d5c785e3c2360..fd134675fc2e847444070e2f26213ee642477396 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
+#include <linux/compiler.h>
 
 #include "ieee754dp.h"
 
-int ieee754dp_class(ieee754dp x)
+int ieee754dp_class(union ieee754dp x)
 {
        COMPXDP;
        EXPLODEXDP;
        return xc;
 }
 
-int ieee754dp_isnan(ieee754dp x)
+int ieee754dp_isnan(union ieee754dp x)
 {
        return ieee754dp_class(x) >= IEEE754_CLASS_SNAN;
 }
 
-int ieee754dp_issnan(ieee754dp x)
+static inline int ieee754dp_issnan(union ieee754dp x)
 {
        assert(ieee754dp_isnan(x));
-       return ((DPMANT(x) & DP_MBIT(DP_MBITS-1)) == DP_MBIT(DP_MBITS-1));
+       return ((DPMANT(x) & DP_MBIT(DP_FBITS-1)) == DP_MBIT(DP_FBITS-1));
 }
 
 
-ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...)
-{
-       struct ieee754xctx ax;
-       if (!TSTX())
-               return r;
-
-       ax.op = op;
-       ax.rt = IEEE754_RT_DP;
-       ax.rv.dp = r;
-       va_start(ax.ap, op);
-       ieee754_xcpt(&ax);
-       va_end(ax.ap);
-       return ax.rv.dp;
-}
-
-ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...)
+union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r)
 {
-       struct ieee754xctx ax;
-
        assert(ieee754dp_isnan(r));
 
        if (!ieee754dp_issnan(r))       /* QNAN does not cause invalid op !! */
                return r;
 
-       if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) {
+       if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) {
                /* not enabled convert to a quiet NaN */
-               DPMANT(r) &= (~DP_MBIT(DP_MBITS-1));
+               DPMANT(r) &= (~DP_MBIT(DP_FBITS-1));
                if (ieee754dp_isnan(r))
                        return r;
                else
                        return ieee754dp_indef();
        }
 
-       ax.op = op;
-       ax.rt = 0;
-       ax.rv.dp = r;
-       va_start(ax.ap, op);
-       ieee754_xcpt(&ax);
-       va_end(ax.ap);
-       return ax.rv.dp;
+       return r;
 }
 
-ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y)
-{
-       assert(ieee754dp_isnan(x));
-       assert(ieee754dp_isnan(y));
-
-       if (DPMANT(x) > DPMANT(y))
-               return x;
-       else
-               return y;
-}
-
-
-static u64 get_rounding(int sn, u64 xm)
+static u64 ieee754dp_get_rounding(int sn, u64 xm)
 {
        /* inexact must round of 3 bits
         */
        if (xm & (DP_MBIT(3) - 1)) {
                switch (ieee754_csr.rm) {
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        break;
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        xm += 0x3 + ((xm >> 3) & 1);
                        /* xm += (xm&0x8)?0x4:0x3 */
                        break;
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if (!sn)        /* ?? */
                                xm += 0x8;
                        break;
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if (sn) /* ?? */
                                xm += 0x8;
                        break;
@@ -130,11 +92,11 @@ static u64 get_rounding(int sn, u64 xm)
  * xe is an unbiased exponent
  * xm is 3bit extended precision value.
  */
-ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
+union ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
 {
        assert(xm);             /* we don't gen exact zeros (probably should) */
 
-       assert((xm >> (DP_MBITS + 1 + 3)) == 0);        /* no execess */
+       assert((xm >> (DP_FBITS + 1 + 3)) == 0);        /* no execess */
        assert(xm & (DP_HIDDEN_BIT << 3));
 
        if (xe < DP_EMIN) {
@@ -142,32 +104,32 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
                int es = DP_EMIN - xe;
 
                if (ieee754_csr.nod) {
-                       SETCX(IEEE754_UNDERFLOW);
-                       SETCX(IEEE754_INEXACT);
+                       ieee754_setcx(IEEE754_UNDERFLOW);
+                       ieee754_setcx(IEEE754_INEXACT);
 
                        switch(ieee754_csr.rm) {
-                       case IEEE754_RN:
-                       case IEEE754_RZ:
+                       case FPU_CSR_RN:
+                       case FPU_CSR_RZ:
                                return ieee754dp_zero(sn);
-                       case IEEE754_RU:    /* toward +Infinity */
-                               if(sn == 0)
+                       case FPU_CSR_RU:    /* toward +Infinity */
+                               if (sn == 0)
                                        return ieee754dp_min(0);
                                else
                                        return ieee754dp_zero(1);
-                       case IEEE754_RD:    /* toward -Infinity */
-                               if(sn == 0)
+                       case FPU_CSR_RD:    /* toward -Infinity */
+                               if (sn == 0)
                                        return ieee754dp_zero(0);
                                else
                                        return ieee754dp_min(1);
                        }
                }
 
-               if (xe == DP_EMIN - 1
-                               && get_rounding(sn, xm) >> (DP_MBITS + 1 + 3))
+               if (xe == DP_EMIN - 1 &&
+                   ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3))
                {
                        /* Not tiny after rounding */
-                       SETCX(IEEE754_INEXACT);
-                       xm = get_rounding(sn, xm);
+                       ieee754_setcx(IEEE754_INEXACT);
+                       xm = ieee754dp_get_rounding(sn, xm);
                        xm >>= 1;
                        /* Clear grs bits */
                        xm &= ~(DP_MBIT(3) - 1);
@@ -183,17 +145,17 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
                }
        }
        if (xm & (DP_MBIT(3) - 1)) {
-               SETCX(IEEE754_INEXACT);
+               ieee754_setcx(IEEE754_INEXACT);
                if ((xm & (DP_HIDDEN_BIT << 3)) == 0) {
-                       SETCX(IEEE754_UNDERFLOW);
+                       ieee754_setcx(IEEE754_UNDERFLOW);
                }
 
                /* inexact must round of 3 bits
                 */
-               xm = get_rounding(sn, xm);
+               xm = ieee754dp_get_rounding(sn, xm);
                /* adjust exponent for rounding add overflowing
                 */
-               if (xm >> (DP_MBITS + 3 + 1)) {
+               if (xm >> (DP_FBITS + 3 + 1)) {
                        /* add causes mantissa overflow */
                        xm >>= 1;
                        xe++;
@@ -202,24 +164,24 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
        /* strip grs bits */
        xm >>= 3;
 
-       assert((xm >> (DP_MBITS + 1)) == 0);    /* no execess */
+       assert((xm >> (DP_FBITS + 1)) == 0);    /* no execess */
        assert(xe >= DP_EMIN);
 
        if (xe > DP_EMAX) {
-               SETCX(IEEE754_OVERFLOW);
-               SETCX(IEEE754_INEXACT);
+               ieee754_setcx(IEEE754_OVERFLOW);
+               ieee754_setcx(IEEE754_INEXACT);
                /* -O can be table indexed by (rm,sn) */
                switch (ieee754_csr.rm) {
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        return ieee754dp_inf(sn);
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        return ieee754dp_max(sn);
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if (sn == 0)
                                return ieee754dp_inf(0);
                        else
                                return ieee754dp_max(1);
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if (sn == 0)
                                return ieee754dp_max(0);
                        else
@@ -232,10 +194,10 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
                /* we underflow (tiny/zero) */
                assert(xe == DP_EMIN);
                if (ieee754_csr.mx & IEEE754_UNDERFLOW)
-                       SETCX(IEEE754_UNDERFLOW);
+                       ieee754_setcx(IEEE754_UNDERFLOW);
                return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
        } else {
-               assert((xm >> (DP_MBITS + 1)) == 0);    /* no execess */
+               assert((xm >> (DP_FBITS + 1)) == 0);    /* no execess */
                assert(xm & DP_HIDDEN_BIT);
 
                return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
index f139c724c59afd8e5cf769fd750c456116f27edf..61fd6fd31350f6555d55c72ad4b0deab601158a9 100644 (file)
@@ -6,8 +6,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
+#include <linux/compiler.h>
 
 #include "ieee754int.h"
 
 #define assert(expr) ((void)0)
 
+#define DP_EBIAS       1023
+#define DP_EMIN                (-1022)
+#define DP_EMAX                1023
+#define DP_FBITS       52
+#define DP_MBITS       52
+
+#define DP_MBIT(x)     ((u64)1 << (x))
+#define DP_HIDDEN_BIT  DP_MBIT(DP_FBITS)
+#define DP_SIGN_BIT    DP_MBIT(63)
+
+#define DPSIGN(dp)     (dp.sign)
+#define DPBEXP(dp)     (dp.bexp)
+#define DPMANT(dp)     (dp.mant)
+
+static inline int ieee754dp_finite(union ieee754dp x)
+{
+       return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS;
+}
+
 /* 3bit extended double precision sticky right shift */
 #define XDPSRS(v,rs)   \
-  ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0))
+       ((rs > (DP_FBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0))
 
 #define XDPSRSX1() \
-  (xe++, (xm = (xm >> 1) | (xm & 1)))
+       (xe++, (xm = (xm >> 1) | (xm & 1)))
 
 #define XDPSRS1(v)     \
-  (((v) >> 1) | ((v) & 1))
+       (((v) >> 1) | ((v) & 1))
 
 /* convert denormal to normalized with extended exponent */
 #define DPDNORMx(m,e) \
-  while( (m >> DP_MBITS) == 0) { m <<= 1; e--; }
+       while ((m >> DP_FBITS) == 0) { m <<= 1; e--; }
 #define DPDNORMX       DPDNORMx(xm, xe)
 #define DPDNORMY       DPDNORMx(ym, ye)
 
-static inline ieee754dp builddp(int s, int bx, u64 m)
+static inline union ieee754dp builddp(int s, int bx, u64 m)
 {
-       ieee754dp r;
+       union ieee754dp r;
 
        assert((s) == 0 || (s) == 1);
        assert((bx) >= DP_EMIN - 1 + DP_EBIAS
               && (bx) <= DP_EMAX + 1 + DP_EBIAS);
-       assert(((m) >> DP_MBITS) == 0);
+       assert(((m) >> DP_FBITS) == 0);
 
-       r.parts.sign = s;
-       r.parts.bexp = bx;
-       r.parts.mant = m;
-       return r;
-}
+       r.sign = s;
+       r.bexp = bx;
+       r.mant = m;
 
-extern int ieee754dp_isnan(ieee754dp);
-extern int ieee754dp_issnan(ieee754dp);
-extern int ieee754si_xcpt(int, const char *, ...);
-extern s64 ieee754di_xcpt(s64, const char *, ...);
-extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...);
-extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...);
-extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp);
-extern ieee754dp ieee754dp_format(int, int, u64);
-
-
-#define DPNORMRET2(s, e, m, name, a0, a1) \
-{ \
-    ieee754dp V = ieee754dp_format(s, e, m); \
-    if(TSTX()) \
-      return ieee754dp_xcpt(V, name, a0, a1); \
-    else \
-      return V; \
+       return r;
 }
 
-#define DPNORMRET1(s, e, m, name, a0)  DPNORMRET2(s, e, m, name, a0, a0)
+extern int ieee754dp_isnan(union ieee754dp);
+extern union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp);
+extern union ieee754dp ieee754dp_format(int, int, u64);
index 4b6c6fb353047e1b9b7185a0cda2e7e95b866d51..f0365bb86747db8a64ddaff74eb9eb1b90e4cef2 100644 (file)
@@ -6,8 +6,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
-
+#ifndef __IEEE754INT_H
+#define __IEEE754INT_H
 
 #include "ieee754.h"
 
-#define DP_EBIAS       1023
-#define DP_EMIN                (-1022)
-#define DP_EMAX                1023
-#define DP_MBITS       52
-
-#define SP_EBIAS       127
-#define SP_EMIN                (-126)
-#define SP_EMAX                127
-#define SP_MBITS       23
-
-#define DP_MBIT(x)     ((u64)1 << (x))
-#define DP_HIDDEN_BIT  DP_MBIT(DP_MBITS)
-#define DP_SIGN_BIT    DP_MBIT(63)
-
-#define SP_MBIT(x)     ((u32)1 << (x))
-#define SP_HIDDEN_BIT  SP_MBIT(SP_MBITS)
-#define SP_SIGN_BIT    SP_MBIT(31)
-
-
-#define SPSIGN(sp)     (sp.parts.sign)
-#define SPBEXP(sp)     (sp.parts.bexp)
-#define SPMANT(sp)     (sp.parts.mant)
-
-#define DPSIGN(dp)     (dp.parts.sign)
-#define DPBEXP(dp)     (dp.parts.bexp)
-#define DPMANT(dp)     (dp.parts.mant)
-
 #define CLPAIR(x, y)   ((x)*6+(y))
 
-#define CLEARCX \
-  (ieee754_csr.cx = 0)
-
-#define SETCX(x) \
-  (ieee754_csr.cx |= (x), ieee754_csr.sx |= (x))
+static inline void ieee754_clearcx(void)
+{
+       ieee754_csr.cx = 0;
+}
 
-#define SETANDTESTCX(x) \
-  (SETCX(x), ieee754_csr.mx & (x))
+static inline void ieee754_setcx(const unsigned int flags)
+{
+       ieee754_csr.cx |= flags;
+       ieee754_csr.sx |= flags;
+}
 
-#define TSTX() \
-       (ieee754_csr.cx & ieee754_csr.mx)
+static inline int ieee754_setandtestcx(const unsigned int x)
+{
+       ieee754_setcx(x);
 
+       return ieee754_csr.mx & x;
+}
 
 #define COMPXSP \
-  unsigned xm; int xe; int xs __maybe_unused; int xc
+       unsigned xm; int xe; int xs __maybe_unused; int xc
 
 #define COMPYSP \
-  unsigned ym; int ye; int ys; int yc
-
-#define EXPLODESP(v, vc, vs, ve, vm) \
-{\
-    vs = SPSIGN(v);\
-    ve = SPBEXP(v);\
-    vm = SPMANT(v);\
-    if(ve == SP_EMAX+1+SP_EBIAS){\
-       if(vm == 0)\
-         vc = IEEE754_CLASS_INF;\
-       else if(vm & SP_MBIT(SP_MBITS-1)) \
-         vc = IEEE754_CLASS_SNAN;\
-       else \
-         vc = IEEE754_CLASS_QNAN;\
-    } else if(ve == SP_EMIN-1+SP_EBIAS) {\
-       if(vm) {\
-           ve = SP_EMIN;\
-           vc = IEEE754_CLASS_DNORM;\
-       } else\
-         vc = IEEE754_CLASS_ZERO;\
-    } else {\
-       ve -= SP_EBIAS;\
-       vm |= SP_HIDDEN_BIT;\
-       vc = IEEE754_CLASS_NORM;\
-    }\
+       unsigned ym; int ye; int ys; int yc
+
+#define EXPLODESP(v, vc, vs, ve, vm)                                   \
+{                                                                      \
+       vs = SPSIGN(v);                                                 \
+       ve = SPBEXP(v);                                                 \
+       vm = SPMANT(v);                                                 \
+       if (ve == SP_EMAX+1+SP_EBIAS) {                                 \
+               if (vm == 0)                                            \
+                       vc = IEEE754_CLASS_INF;                         \
+               else if (vm & SP_MBIT(SP_FBITS-1))                      \
+                       vc = IEEE754_CLASS_SNAN;                        \
+       else                                                            \
+               vc = IEEE754_CLASS_QNAN;                                \
+       } else if (ve == SP_EMIN-1+SP_EBIAS) {                          \
+               if (vm) {                                               \
+                       ve = SP_EMIN;                                   \
+                       vc = IEEE754_CLASS_DNORM;                       \
+               } else                                                  \
+                       vc = IEEE754_CLASS_ZERO;                        \
+       } else {                                                        \
+               ve -= SP_EBIAS;                                         \
+               vm |= SP_HIDDEN_BIT;                                    \
+               vc = IEEE754_CLASS_NORM;                                \
+       }                                                               \
 }
 #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm)
 #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym)
 
 
 #define COMPXDP \
-u64 xm; int xe; int xs __maybe_unused; int xc
+       u64 xm; int xe; int xs __maybe_unused; int xc
 
 #define COMPYDP \
-u64 ym; int ye; int ys; int yc
-
-#define EXPLODEDP(v, vc, vs, ve, vm) \
-{\
-    vm = DPMANT(v);\
-    vs = DPSIGN(v);\
-    ve = DPBEXP(v);\
-    if(ve == DP_EMAX+1+DP_EBIAS){\
-       if(vm == 0)\
-         vc = IEEE754_CLASS_INF;\
-       else if(vm & DP_MBIT(DP_MBITS-1)) \
-         vc = IEEE754_CLASS_SNAN;\
-       else \
-         vc = IEEE754_CLASS_QNAN;\
-    } else if(ve == DP_EMIN-1+DP_EBIAS) {\
-       if(vm) {\
-           ve = DP_EMIN;\
-           vc = IEEE754_CLASS_DNORM;\
-       } else\
-         vc = IEEE754_CLASS_ZERO;\
-    } else {\
-       ve -= DP_EBIAS;\
-       vm |= DP_HIDDEN_BIT;\
-       vc = IEEE754_CLASS_NORM;\
-    }\
+       u64 ym; int ye; int ys; int yc
+
+#define EXPLODEDP(v, vc, vs, ve, vm)                                   \
+{                                                                      \
+       vm = DPMANT(v);                                                 \
+       vs = DPSIGN(v);                                                 \
+       ve = DPBEXP(v);                                                 \
+       if (ve == DP_EMAX+1+DP_EBIAS) {                                 \
+               if (vm == 0)                                            \
+                       vc = IEEE754_CLASS_INF;                         \
+               else if (vm & DP_MBIT(DP_FBITS-1))                      \
+                       vc = IEEE754_CLASS_SNAN;                        \
+               else                                                    \
+                       vc = IEEE754_CLASS_QNAN;                        \
+       } else if (ve == DP_EMIN-1+DP_EBIAS) {                          \
+               if (vm) {                                               \
+                       ve = DP_EMIN;                                   \
+                       vc = IEEE754_CLASS_DNORM;                       \
+       } else                                                          \
+               vc = IEEE754_CLASS_ZERO;                                \
+       } else {                                                        \
+               ve -= DP_EBIAS;                                         \
+               vm |= DP_HIDDEN_BIT;                                    \
+               vc = IEEE754_CLASS_NORM;                                \
+       }                                                               \
 }
 #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm)
 #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym)
 
-#define FLUSHDP(v, vc, vs, ve, vm) \
-       if(vc==IEEE754_CLASS_DNORM) {\
-           if(ieee754_csr.nod) {\
-               SETCX(IEEE754_INEXACT);\
-               vc = IEEE754_CLASS_ZERO;\
-               ve = DP_EMIN-1+DP_EBIAS;\
-               vm = 0;\
-               v = ieee754dp_zero(vs);\
-           }\
+#define FLUSHDP(v, vc, vs, ve, vm)                                     \
+       if (vc==IEEE754_CLASS_DNORM) {                                  \
+               if (ieee754_csr.nod) {                                  \
+                       ieee754_setcx(IEEE754_INEXACT);                 \
+                       vc = IEEE754_CLASS_ZERO;                        \
+                       ve = DP_EMIN-1+DP_EBIAS;                        \
+                       vm = 0;                                         \
+                       v = ieee754dp_zero(vs);                         \
+               }                                                       \
        }
 
-#define FLUSHSP(v, vc, vs, ve, vm) \
-       if(vc==IEEE754_CLASS_DNORM) {\
-           if(ieee754_csr.nod) {\
-               SETCX(IEEE754_INEXACT);\
-               vc = IEEE754_CLASS_ZERO;\
-               ve = SP_EMIN-1+SP_EBIAS;\
-               vm = 0;\
-               v = ieee754sp_zero(vs);\
-           }\
+#define FLUSHSP(v, vc, vs, ve, vm)                                     \
+       if (vc==IEEE754_CLASS_DNORM) {                                  \
+               if (ieee754_csr.nod) {                                  \
+                       ieee754_setcx(IEEE754_INEXACT);                 \
+                       vc = IEEE754_CLASS_ZERO;                        \
+                       ve = SP_EMIN-1+SP_EBIAS;                        \
+                       vm = 0;                                         \
+                       v = ieee754sp_zero(vs);                         \
+               }                                                       \
        }
 
 #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm)
 #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym)
 #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm)
 #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym)
+
+#endif /* __IEEE754INT_H  */
diff --git a/arch/mips/math-emu/ieee754m.c b/arch/mips/math-emu/ieee754m.c
deleted file mode 100644 (file)
index 24190f3..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * floor, trunc, ceil
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754.h"
-
-ieee754dp ieee754dp_floor(ieee754dp x)
-{
-       ieee754dp i;
-
-       if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
-               return ieee754dp_sub(i, ieee754dp_one(0));
-       else
-               return i;
-}
-
-ieee754dp ieee754dp_ceil(ieee754dp x)
-{
-       ieee754dp i;
-
-       if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
-               return ieee754dp_add(i, ieee754dp_one(0));
-       else
-               return i;
-}
-
-ieee754dp ieee754dp_trunc(ieee754dp x)
-{
-       ieee754dp i;
-
-       (void) ieee754dp_modf(x, &i);
-       return i;
-}
index 15d1e36cfe64a26c62b10a78133cd9a8415ff9ae..d348efe914454725bcbcafa3bf54d300dd59a43c 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
+#include <linux/compiler.h>
 
 #include "ieee754sp.h"
 
-int ieee754sp_class(ieee754sp x)
+int ieee754sp_class(union ieee754sp x)
 {
        COMPXSP;
        EXPLODEXSP;
        return xc;
 }
 
-int ieee754sp_isnan(ieee754sp x)
+int ieee754sp_isnan(union ieee754sp x)
 {
        return ieee754sp_class(x) >= IEEE754_CLASS_SNAN;
 }
 
-int ieee754sp_issnan(ieee754sp x)
+static inline int ieee754sp_issnan(union ieee754sp x)
 {
        assert(ieee754sp_isnan(x));
-       return (SPMANT(x) & SP_MBIT(SP_MBITS-1));
+       return (SPMANT(x) & SP_MBIT(SP_FBITS-1));
 }
 
 
-ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...)
-{
-       struct ieee754xctx ax;
-
-       if (!TSTX())
-               return r;
-
-       ax.op = op;
-       ax.rt = IEEE754_RT_SP;
-       ax.rv.sp = r;
-       va_start(ax.ap, op);
-       ieee754_xcpt(&ax);
-       va_end(ax.ap);
-       return ax.rv.sp;
-}
-
-ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...)
+union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r)
 {
-       struct ieee754xctx ax;
-
        assert(ieee754sp_isnan(r));
 
        if (!ieee754sp_issnan(r))       /* QNAN does not cause invalid op !! */
                return r;
 
-       if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) {
+       if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) {
                /* not enabled convert to a quiet NaN */
-               SPMANT(r) &= (~SP_MBIT(SP_MBITS-1));
+               SPMANT(r) &= (~SP_MBIT(SP_FBITS-1));
                if (ieee754sp_isnan(r))
                        return r;
                else
                        return ieee754sp_indef();
        }
 
-       ax.op = op;
-       ax.rt = 0;
-       ax.rv.sp = r;
-       va_start(ax.ap, op);
-       ieee754_xcpt(&ax);
-       va_end(ax.ap);
-       return ax.rv.sp;
-}
-
-ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y)
-{
-       assert(ieee754sp_isnan(x));
-       assert(ieee754sp_isnan(y));
-
-       if (SPMANT(x) > SPMANT(y))
-               return x;
-       else
-               return y;
+       return r;
 }
 
-
-static unsigned get_rounding(int sn, unsigned xm)
+static unsigned ieee754sp_get_rounding(int sn, unsigned xm)
 {
        /* inexact must round of 3 bits
         */
        if (xm & (SP_MBIT(3) - 1)) {
                switch (ieee754_csr.rm) {
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        break;
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        xm += 0x3 + ((xm >> 3) & 1);
                        /* xm += (xm&0x8)?0x4:0x3 */
                        break;
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if (!sn)        /* ?? */
                                xm += 0x8;
                        break;
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if (sn) /* ?? */
                                xm += 0x8;
                        break;
@@ -131,11 +92,11 @@ static unsigned get_rounding(int sn, unsigned xm)
  * xe is an unbiased exponent
  * xm is 3bit extended precision value.
  */
-ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
+union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
 {
        assert(xm);             /* we don't gen exact zeros (probably should) */
 
-       assert((xm >> (SP_MBITS + 1 + 3)) == 0);        /* no execess */
+       assert((xm >> (SP_FBITS + 1 + 3)) == 0);        /* no execess */
        assert(xm & (SP_HIDDEN_BIT << 3));
 
        if (xe < SP_EMIN) {
@@ -143,38 +104,37 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
                int es = SP_EMIN - xe;
 
                if (ieee754_csr.nod) {
-                       SETCX(IEEE754_UNDERFLOW);
-                       SETCX(IEEE754_INEXACT);
+                       ieee754_setcx(IEEE754_UNDERFLOW);
+                       ieee754_setcx(IEEE754_INEXACT);
 
                        switch(ieee754_csr.rm) {
-                       case IEEE754_RN:
-                       case IEEE754_RZ:
+                       case FPU_CSR_RN:
+                       case FPU_CSR_RZ:
                                return ieee754sp_zero(sn);
-                       case IEEE754_RU:      /* toward +Infinity */
-                               if(sn == 0)
+                       case FPU_CSR_RU:      /* toward +Infinity */
+                               if (sn == 0)
                                        return ieee754sp_min(0);
                                else
                                        return ieee754sp_zero(1);
-                       case IEEE754_RD:      /* toward -Infinity */
-                               if(sn == 0)
+                       case FPU_CSR_RD:      /* toward -Infinity */
+                               if (sn == 0)
                                        return ieee754sp_zero(0);
                                else
                                        return ieee754sp_min(1);
                        }
                }
 
-               if (xe == SP_EMIN - 1
-                               && get_rounding(sn, xm) >> (SP_MBITS + 1 + 3))
+               if (xe == SP_EMIN - 1 &&
+                   ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3))
                {
                        /* Not tiny after rounding */
-                       SETCX(IEEE754_INEXACT);
-                       xm = get_rounding(sn, xm);
+                       ieee754_setcx(IEEE754_INEXACT);
+                       xm = ieee754sp_get_rounding(sn, xm);
                        xm >>= 1;
                        /* Clear grs bits */
                        xm &= ~(SP_MBIT(3) - 1);
                        xe++;
-               }
-               else {
+               } else {
                        /* sticky right shift es bits
                         */
                        SPXSRSXn(es);
@@ -183,17 +143,17 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
                }
        }
        if (xm & (SP_MBIT(3) - 1)) {
-               SETCX(IEEE754_INEXACT);
+               ieee754_setcx(IEEE754_INEXACT);
                if ((xm & (SP_HIDDEN_BIT << 3)) == 0) {
-                       SETCX(IEEE754_UNDERFLOW);
+                       ieee754_setcx(IEEE754_UNDERFLOW);
                }
 
                /* inexact must round of 3 bits
                 */
-               xm = get_rounding(sn, xm);
+               xm = ieee754sp_get_rounding(sn, xm);
                /* adjust exponent for rounding add overflowing
                 */
-               if (xm >> (SP_MBITS + 1 + 3)) {
+               if (xm >> (SP_FBITS + 1 + 3)) {
                        /* add causes mantissa overflow */
                        xm >>= 1;
                        xe++;
@@ -202,24 +162,24 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
        /* strip grs bits */
        xm >>= 3;
 
-       assert((xm >> (SP_MBITS + 1)) == 0);    /* no execess */
+       assert((xm >> (SP_FBITS + 1)) == 0);    /* no execess */
        assert(xe >= SP_EMIN);
 
        if (xe > SP_EMAX) {
-               SETCX(IEEE754_OVERFLOW);
-               SETCX(IEEE754_INEXACT);
+               ieee754_setcx(IEEE754_OVERFLOW);
+               ieee754_setcx(IEEE754_INEXACT);
                /* -O can be table indexed by (rm,sn) */
                switch (ieee754_csr.rm) {
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        return ieee754sp_inf(sn);
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        return ieee754sp_max(sn);
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if (sn == 0)
                                return ieee754sp_inf(0);
                        else
                                return ieee754sp_max(1);
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if (sn == 0)
                                return ieee754sp_max(0);
                        else
@@ -232,10 +192,10 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
                /* we underflow (tiny/zero) */
                assert(xe == SP_EMIN);
                if (ieee754_csr.mx & IEEE754_UNDERFLOW)
-                       SETCX(IEEE754_UNDERFLOW);
+                       ieee754_setcx(IEEE754_UNDERFLOW);
                return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
        } else {
-               assert((xm >> (SP_MBITS + 1)) == 0);    /* no execess */
+               assert((xm >> (SP_FBITS + 1)) == 0);    /* no execess */
                assert(xm & SP_HIDDEN_BIT);
 
                return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
index 754fd54649b51787eed7756cc496fed150c9d180..ad268e3323183a4915db23e942d26f19dc717037 100644 (file)
@@ -6,8 +6,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
+#include <linux/compiler.h>
 
 #include "ieee754int.h"
 
 #define assert(expr) ((void)0)
 
+#define SP_EBIAS       127
+#define SP_EMIN                (-126)
+#define SP_EMAX                127
+#define SP_FBITS       23
+#define SP_MBITS       23
+
+#define SP_MBIT(x)     ((u32)1 << (x))
+#define SP_HIDDEN_BIT  SP_MBIT(SP_FBITS)
+#define SP_SIGN_BIT    SP_MBIT(31)
+
+#define SPSIGN(sp)     (sp.sign)
+#define SPBEXP(sp)     (sp.bexp)
+#define SPMANT(sp)     (sp.mant)
+
+static inline int ieee754sp_finite(union ieee754sp x)
+{
+       return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
+}
+
 /* 3bit extended single precision sticky right shift */
-#define SPXSRSXn(rs) \
-  (xe += rs, \
-   xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0))
+#define SPXSRSXn(rs)                                                   \
+       (xe += rs,                                                      \
+        xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0))
 
 #define SPXSRSX1() \
-  (xe++, (xm = (xm >> 1) | (xm & 1)))
+       (xe++, (xm = (xm >> 1) | (xm & 1)))
 
-#define SPXSRSYn(rs) \
-   (ye+=rs, \
-    ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0))
+#define SPXSRSYn(rs)                                                           \
+       (ye+=rs,                                                                \
+        ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0))
 
 #define SPXSRSY1() \
-   (ye++, (ym = (ym >> 1) | (ym & 1)))
+       (ye++, (ym = (ym >> 1) | (ym & 1)))
 
 /* convert denormal to normalized with extended exponent */
 #define SPDNORMx(m,e) \
-  while( (m >> SP_MBITS) == 0) { m <<= 1; e--; }
+       while ((m >> SP_FBITS) == 0) { m <<= 1; e--; }
 #define SPDNORMX       SPDNORMx(xm, xe)
 #define SPDNORMY       SPDNORMx(ym, ye)
 
-static inline ieee754sp buildsp(int s, int bx, unsigned m)
+static inline union ieee754sp buildsp(int s, int bx, unsigned m)
 {
-       ieee754sp r;
+       union ieee754sp r;
 
        assert((s) == 0 || (s) == 1);
        assert((bx) >= SP_EMIN - 1 + SP_EBIAS
               && (bx) <= SP_EMAX + 1 + SP_EBIAS);
-       assert(((m) >> SP_MBITS) == 0);
+       assert(((m) >> SP_FBITS) == 0);
 
-       r.parts.sign = s;
-       r.parts.bexp = bx;
-       r.parts.mant = m;
+       r.sign = s;
+       r.bexp = bx;
+       r.mant = m;
 
        return r;
 }
 
-extern int ieee754sp_isnan(ieee754sp);
-extern int ieee754sp_issnan(ieee754sp);
-extern int ieee754si_xcpt(int, const char *, ...);
-extern s64 ieee754di_xcpt(s64, const char *, ...);
-extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...);
-extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...);
-extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp);
-extern ieee754sp ieee754sp_format(int, int, unsigned);
-
-
-#define SPNORMRET2(s, e, m, name, a0, a1) \
-{ \
-    ieee754sp V = ieee754sp_format(s, e, m); \
-    if(TSTX()) \
-      return ieee754sp_xcpt(V, name, a0, a1); \
-    else \
-      return V; \
-}
-
-#define SPNORMRET1(s, e, m, name, a0)  SPNORMRET2(s, e, m, name, a0, a0)
+extern int ieee754sp_isnan(union ieee754sp);
+extern union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp);
+extern union ieee754sp ieee754sp_format(int, int, unsigned);
diff --git a/arch/mips/math-emu/ieee754xcpt.c b/arch/mips/math-emu/ieee754xcpt.c
deleted file mode 100644 (file)
index 9671671..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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.
- *
- * ########################################################################
- */
-
-/**************************************************************************
- *  Nov 7, 2000
- *  Added preprocessor hacks to map to Linux kernel diagnostics.
- *
- *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include "ieee754.h"
-
-/*
- * Very naff exception handler (you can plug in your own and
- * override this).
- */
-
-static const char *const rtnames[] = {
-       "sp", "dp", "xp", "si", "di"
-};
-
-void ieee754_xcpt(struct ieee754xctx *xcp)
-{
-       printk(KERN_DEBUG "floating point exception in \"%s\", type=%s\n",
-               xcp->op, rtnames[xcp->rt]);
-}
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
deleted file mode 100644 (file)
index eb58a85..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
- *
- *  This program is free software; you can distribute 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 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.
- *
- * Routines corresponding to Linux kernel FP context
- * manipulation primitives for the Algorithmics MIPS
- * FPU Emulator
- */
-#include <linux/sched.h>
-#include <asm/processor.h>
-#include <asm/signal.h>
-#include <asm/uaccess.h>
-
-#include <asm/fpu.h>
-#include <asm/fpu_emulator.h>
-
-#define SIGNALLING_NAN 0x7ff800007ff80000LL
-
-void fpu_emulator_init_fpu(void)
-{
-       static int first = 1;
-       int i;
-
-       if (first) {
-               first = 0;
-               printk("Algorithmics/MIPS FPU Emulator v1.5\n");
-       }
-
-       current->thread.fpu.fcr31 = 0;
-       for (i = 0; i < 32; i++)
-               set_fpr64(&current->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
-}
diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c
new file mode 100644 (file)
index 0000000..95ed9f9
--- /dev/null
@@ -0,0 +1,62 @@
+#include <linux/cpumask.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <asm/fpu_emulator.h>
+#include <asm/local.h>
+
+DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
+
+static int fpuemu_stat_get(void *data, u64 *val)
+{
+       int cpu;
+       unsigned long sum = 0;
+
+       for_each_online_cpu(cpu) {
+               struct mips_fpu_emulator_stats *ps;
+               local_t *pv;
+
+               ps = &per_cpu(fpuemustats, cpu);
+               pv = (void *)ps + (unsigned long)data;
+               sum += local_read(pv);
+       }
+       *val = sum;
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
+
+extern struct dentry *mips_debugfs_dir;
+static int __init debugfs_fpuemu(void)
+{
+       struct dentry *d, *dir;
+
+       if (!mips_debugfs_dir)
+               return -ENODEV;
+       dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir);
+       if (!dir)
+               return -ENOMEM;
+
+#define FPU_EMU_STAT_OFFSET(m)                                         \
+       offsetof(struct mips_fpu_emulator_stats, m)
+
+#define FPU_STAT_CREATE(m)                                             \
+do {                                                                   \
+       d = debugfs_create_file(#m , S_IRUGO, dir,                      \
+                               (void *)FPU_EMU_STAT_OFFSET(m),         \
+                               &fops_fpuemu_stat);                     \
+       if (!d)                                                         \
+               return -ENOMEM;                                         \
+} while (0)
+
+       FPU_STAT_CREATE(emulated);
+       FPU_STAT_CREATE(loads);
+       FPU_STAT_CREATE(stores);
+       FPU_STAT_CREATE(cp1ops);
+       FPU_STAT_CREATE(cp1xops);
+       FPU_STAT_CREATE(errors);
+
+       return 0;
+}
+__initcall(debugfs_fpuemu);
diff --git a/arch/mips/math-emu/me-micromips.c b/arch/mips/math-emu/me-micromips.c
new file mode 100644 (file)
index 0000000..b0e6e41
--- /dev/null
@@ -0,0 +1,348 @@
+#include <asm/inst.h>
+
+/* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */
+static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0};
+static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0};
+static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0};
+static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0};
+
+/*
+ * This functions translates a 32-bit microMIPS instruction
+ * into a 32-bit MIPS32 instruction. Returns 0 on success
+ * and SIGILL otherwise.
+ */
+int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
+{
+       union mips_instruction insn = *insn_ptr;
+       union mips_instruction mips32_insn = insn;
+       int func, fmt, op;
+
+       switch (insn.mm_i_format.opcode) {
+       case mm_ldc132_op:
+               mips32_insn.mm_i_format.opcode = ldc1_op;
+               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
+               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
+               break;
+       case mm_lwc132_op:
+               mips32_insn.mm_i_format.opcode = lwc1_op;
+               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
+               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
+               break;
+       case mm_sdc132_op:
+               mips32_insn.mm_i_format.opcode = sdc1_op;
+               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
+               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
+               break;
+       case mm_swc132_op:
+               mips32_insn.mm_i_format.opcode = swc1_op;
+               mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
+               mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
+               break;
+       case mm_pool32i_op:
+               /* NOTE: offset is << by 1 if in microMIPS mode. */
+               if ((insn.mm_i_format.rt == mm_bc1f_op) ||
+                   (insn.mm_i_format.rt == mm_bc1t_op)) {
+                       mips32_insn.fb_format.opcode = cop1_op;
+                       mips32_insn.fb_format.bc = bc_op;
+                       mips32_insn.fb_format.flag =
+                               (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0;
+               } else
+                       return SIGILL;
+               break;
+       case mm_pool32f_op:
+               switch (insn.mm_fp0_format.func) {
+               case mm_32f_01_op:
+               case mm_32f_11_op:
+               case mm_32f_02_op:
+               case mm_32f_12_op:
+               case mm_32f_41_op:
+               case mm_32f_51_op:
+               case mm_32f_42_op:
+               case mm_32f_52_op:
+                       op = insn.mm_fp0_format.func;
+                       if (op == mm_32f_01_op)
+                               func = madd_s_op;
+                       else if (op == mm_32f_11_op)
+                               func = madd_d_op;
+                       else if (op == mm_32f_02_op)
+                               func = nmadd_s_op;
+                       else if (op == mm_32f_12_op)
+                               func = nmadd_d_op;
+                       else if (op == mm_32f_41_op)
+                               func = msub_s_op;
+                       else if (op == mm_32f_51_op)
+                               func = msub_d_op;
+                       else if (op == mm_32f_42_op)
+                               func = nmsub_s_op;
+                       else
+                               func = nmsub_d_op;
+                       mips32_insn.fp6_format.opcode = cop1x_op;
+                       mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr;
+                       mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft;
+                       mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs;
+                       mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd;
+                       mips32_insn.fp6_format.func = func;
+                       break;
+               case mm_32f_10_op:
+                       func = -1;      /* Invalid */
+                       op = insn.mm_fp5_format.op & 0x7;
+                       if (op == mm_ldxc1_op)
+                               func = ldxc1_op;
+                       else if (op == mm_sdxc1_op)
+                               func = sdxc1_op;
+                       else if (op == mm_lwxc1_op)
+                               func = lwxc1_op;
+                       else if (op == mm_swxc1_op)
+                               func = swxc1_op;
+
+                       if (func != -1) {
+                               mips32_insn.r_format.opcode = cop1x_op;
+                               mips32_insn.r_format.rs =
+                                       insn.mm_fp5_format.base;
+                               mips32_insn.r_format.rt =
+                                       insn.mm_fp5_format.index;
+                               mips32_insn.r_format.rd = 0;
+                               mips32_insn.r_format.re = insn.mm_fp5_format.fd;
+                               mips32_insn.r_format.func = func;
+                       } else
+                               return SIGILL;
+                       break;
+               case mm_32f_40_op:
+                       op = -1;        /* Invalid */
+                       if (insn.mm_fp2_format.op == mm_fmovt_op)
+                               op = 1;
+                       else if (insn.mm_fp2_format.op == mm_fmovf_op)
+                               op = 0;
+                       if (op != -1) {
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt =
+                                       sdps_format[insn.mm_fp2_format.fmt];
+                               mips32_insn.fp0_format.ft =
+                                       (insn.mm_fp2_format.cc<<2) + op;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp2_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp2_format.fd;
+                               mips32_insn.fp0_format.func = fmovc_op;
+                       } else
+                               return SIGILL;
+                       break;
+               case mm_32f_60_op:
+                       func = -1;      /* Invalid */
+                       if (insn.mm_fp0_format.op == mm_fadd_op)
+                               func = fadd_op;
+                       else if (insn.mm_fp0_format.op == mm_fsub_op)
+                               func = fsub_op;
+                       else if (insn.mm_fp0_format.op == mm_fmul_op)
+                               func = fmul_op;
+                       else if (insn.mm_fp0_format.op == mm_fdiv_op)
+                               func = fdiv_op;
+                       if (func != -1) {
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt =
+                                       sdps_format[insn.mm_fp0_format.fmt];
+                               mips32_insn.fp0_format.ft =
+                                       insn.mm_fp0_format.ft;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp0_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp0_format.fd;
+                               mips32_insn.fp0_format.func = func;
+                       } else
+                               return SIGILL;
+                       break;
+               case mm_32f_70_op:
+                       func = -1;      /* Invalid */
+                       if (insn.mm_fp0_format.op == mm_fmovn_op)
+                               func = fmovn_op;
+                       else if (insn.mm_fp0_format.op == mm_fmovz_op)
+                               func = fmovz_op;
+                       if (func != -1) {
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt =
+                                       sdps_format[insn.mm_fp0_format.fmt];
+                               mips32_insn.fp0_format.ft =
+                                       insn.mm_fp0_format.ft;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp0_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp0_format.fd;
+                               mips32_insn.fp0_format.func = func;
+                       } else
+                               return SIGILL;
+                       break;
+               case mm_32f_73_op:    /* POOL32FXF */
+                       switch (insn.mm_fp1_format.op) {
+                       case mm_movf0_op:
+                       case mm_movf1_op:
+                       case mm_movt0_op:
+                       case mm_movt1_op:
+                               if ((insn.mm_fp1_format.op & 0x7f) ==
+                                   mm_movf0_op)
+                                       op = 0;
+                               else
+                                       op = 1;
+                               mips32_insn.r_format.opcode = spec_op;
+                               mips32_insn.r_format.rs = insn.mm_fp4_format.fs;
+                               mips32_insn.r_format.rt =
+                                       (insn.mm_fp4_format.cc << 2) + op;
+                               mips32_insn.r_format.rd = insn.mm_fp4_format.rt;
+                               mips32_insn.r_format.re = 0;
+                               mips32_insn.r_format.func = movc_op;
+                               break;
+                       case mm_fcvtd0_op:
+                       case mm_fcvtd1_op:
+                       case mm_fcvts0_op:
+                       case mm_fcvts1_op:
+                               if ((insn.mm_fp1_format.op & 0x7f) ==
+                                   mm_fcvtd0_op) {
+                                       func = fcvtd_op;
+                                       fmt = swl_format[insn.mm_fp3_format.fmt];
+                               } else {
+                                       func = fcvts_op;
+                                       fmt = dwl_format[insn.mm_fp3_format.fmt];
+                               }
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt = fmt;
+                               mips32_insn.fp0_format.ft = 0;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp3_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp3_format.rt;
+                               mips32_insn.fp0_format.func = func;
+                               break;
+                       case mm_fmov0_op:
+                       case mm_fmov1_op:
+                       case mm_fabs0_op:
+                       case mm_fabs1_op:
+                       case mm_fneg0_op:
+                       case mm_fneg1_op:
+                               if ((insn.mm_fp1_format.op & 0x7f) ==
+                                   mm_fmov0_op)
+                                       func = fmov_op;
+                               else if ((insn.mm_fp1_format.op & 0x7f) ==
+                                        mm_fabs0_op)
+                                       func = fabs_op;
+                               else
+                                       func = fneg_op;
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt =
+                                       sdps_format[insn.mm_fp3_format.fmt];
+                               mips32_insn.fp0_format.ft = 0;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp3_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp3_format.rt;
+                               mips32_insn.fp0_format.func = func;
+                               break;
+                       case mm_ffloorl_op:
+                       case mm_ffloorw_op:
+                       case mm_fceill_op:
+                       case mm_fceilw_op:
+                       case mm_ftruncl_op:
+                       case mm_ftruncw_op:
+                       case mm_froundl_op:
+                       case mm_froundw_op:
+                       case mm_fcvtl_op:
+                       case mm_fcvtw_op:
+                               if (insn.mm_fp1_format.op == mm_ffloorl_op)
+                                       func = ffloorl_op;
+                               else if (insn.mm_fp1_format.op == mm_ffloorw_op)
+                                       func = ffloor_op;
+                               else if (insn.mm_fp1_format.op == mm_fceill_op)
+                                       func = fceill_op;
+                               else if (insn.mm_fp1_format.op == mm_fceilw_op)
+                                       func = fceil_op;
+                               else if (insn.mm_fp1_format.op == mm_ftruncl_op)
+                                       func = ftruncl_op;
+                               else if (insn.mm_fp1_format.op == mm_ftruncw_op)
+                                       func = ftrunc_op;
+                               else if (insn.mm_fp1_format.op == mm_froundl_op)
+                                       func = froundl_op;
+                               else if (insn.mm_fp1_format.op == mm_froundw_op)
+                                       func = fround_op;
+                               else if (insn.mm_fp1_format.op == mm_fcvtl_op)
+                                       func = fcvtl_op;
+                               else
+                                       func = fcvtw_op;
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt =
+                                       sd_format[insn.mm_fp1_format.fmt];
+                               mips32_insn.fp0_format.ft = 0;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp1_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp1_format.rt;
+                               mips32_insn.fp0_format.func = func;
+                               break;
+                       case mm_frsqrt_op:
+                       case mm_fsqrt_op:
+                       case mm_frecip_op:
+                               if (insn.mm_fp1_format.op == mm_frsqrt_op)
+                                       func = frsqrt_op;
+                               else if (insn.mm_fp1_format.op == mm_fsqrt_op)
+                                       func = fsqrt_op;
+                               else
+                                       func = frecip_op;
+                               mips32_insn.fp0_format.opcode = cop1_op;
+                               mips32_insn.fp0_format.fmt =
+                                       sdps_format[insn.mm_fp1_format.fmt];
+                               mips32_insn.fp0_format.ft = 0;
+                               mips32_insn.fp0_format.fs =
+                                       insn.mm_fp1_format.fs;
+                               mips32_insn.fp0_format.fd =
+                                       insn.mm_fp1_format.rt;
+                               mips32_insn.fp0_format.func = func;
+                               break;
+                       case mm_mfc1_op:
+                       case mm_mtc1_op:
+                       case mm_cfc1_op:
+                       case mm_ctc1_op:
+                       case mm_mfhc1_op:
+                       case mm_mthc1_op:
+                               if (insn.mm_fp1_format.op == mm_mfc1_op)
+                                       op = mfc_op;
+                               else if (insn.mm_fp1_format.op == mm_mtc1_op)
+                                       op = mtc_op;
+                               else if (insn.mm_fp1_format.op == mm_cfc1_op)
+                                       op = cfc_op;
+                               else if (insn.mm_fp1_format.op == mm_ctc1_op)
+                                       op = ctc_op;
+                               else if (insn.mm_fp1_format.op == mm_mfhc1_op)
+                                       op = mfhc_op;
+                               else
+                                       op = mthc_op;
+                               mips32_insn.fp1_format.opcode = cop1_op;
+                               mips32_insn.fp1_format.op = op;
+                               mips32_insn.fp1_format.rt =
+                                       insn.mm_fp1_format.rt;
+                               mips32_insn.fp1_format.fs =
+                                       insn.mm_fp1_format.fs;
+                               mips32_insn.fp1_format.fd = 0;
+                               mips32_insn.fp1_format.func = 0;
+                               break;
+                       default:
+                               return SIGILL;
+                       }
+                       break;
+               case mm_32f_74_op:      /* c.cond.fmt */
+                       mips32_insn.fp0_format.opcode = cop1_op;
+                       mips32_insn.fp0_format.fmt =
+                               sdps_format[insn.mm_fp4_format.fmt];
+                       mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt;
+                       mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs;
+                       mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2;
+                       mips32_insn.fp0_format.func =
+                               insn.mm_fp4_format.cond | MM_MIPS32_COND_FC;
+                       break;
+               default:
+                       return SIGILL;
+               }
+               break;
+       default:
+               return SIGILL;
+       }
+
+       *insn_ptr = mips32_insn;
+       return 0;
+}
index c446e64637e212d3a852bc0ccb3a9e8671436f20..2d84d460cb677e0841f59be14598dd9a6c6b2ceb 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
+union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y)
 {
+       int s;
+
        COMPXSP;
        COMPYSP;
 
        EXPLODEXSP;
        EXPLODEYSP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXSP;
        FLUSHYSP;
@@ -51,8 +48,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "add", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,14 +65,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
                return x;
 
 
-               /* Infinity handling
-                */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
                if (xs == ys)
                        return x;
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
@@ -87,15 +84,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
                return x;
 
-               /* Zero handling
-                */
-
+       /*
+        * Zero handling
+        */
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
                if (xs == ys)
                        return x;
                else
-                       return ieee754sp_zero(ieee754_csr.rm ==
-                                             IEEE754_RD);
+                       return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
@@ -108,6 +104,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
 
+               /* FALL THROUGH */
+
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
                break;
@@ -122,33 +120,38 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
        assert(xm & SP_HIDDEN_BIT);
        assert(ym & SP_HIDDEN_BIT);
 
-       /* provide guard,round and stick bit space */
+       /*
+        * Provide guard, round and stick bit space.
+        */
        xm <<= 3;
        ym <<= 3;
 
        if (xe > ye) {
-               /* have to shift y fraction right to align
+               /*
+                * Have to shift y fraction right to align.
                 */
-               int s = xe - ye;
+               s = xe - ye;
                SPXSRSYn(s);
        } else if (ye > xe) {
-               /* have to shift x fraction right to align
+               /*
+                * Have to shift x fraction right to align.
                 */
-               int s = ye - xe;
+               s = ye - xe;
                SPXSRSXn(s);
        }
        assert(xe == ye);
        assert(xe <= SP_EMAX);
 
        if (xs == ys) {
-               /* generate 28 bit result of adding two 27 bit numbers
-                * leaving result in xm,xs,xe
+               /*
+                * Generate 28 bit result of adding two 27 bit numbers
+                * leaving result in xm, xs and xe.
                 */
                xm = xm + ym;
                xe = xe;
                xs = xs;
 
-               if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */
+               if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */
                        SPXSRSX1();
                }
        } else {
@@ -162,15 +165,16 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
                        xs = ys;
                }
                if (xm == 0)
-                       return ieee754sp_zero(ieee754_csr.rm ==
-                                             IEEE754_RD);
+                       return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
-               /* normalize in extended single precision */
-               while ((xm >> (SP_MBITS + 3)) == 0) {
+               /*
+                * Normalize in extended single precision
+                */
+               while ((xm >> (SP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
-
        }
-       SPNORMRET2(xs, xe, xm, "add", x, y);
+
+       return ieee754sp_format(xs, xe, xm);
 }
index 716cf37e24653b78f98ad26826ef1dc5f17f91dd..addbccb2f556c410af5a92f55abc06bab2c5ef98 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig)
+int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cmp, int sig)
 {
+       int vx;
+       int vy;
+
        COMPXSP;
        COMPYSP;
 
@@ -35,21 +33,21 @@ int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig)
        EXPLODEYSP;
        FLUSHXSP;
        FLUSHYSP;
-       CLEARCX;        /* Even clear inexact flag here */
+       ieee754_clearcx();      /* Even clear inexact flag here */
 
        if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) {
                if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
-                       SETCX(IEEE754_INVALID_OPERATION);
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
                if (cmp & IEEE754_CUN)
                        return 1;
                if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
-                       if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION))
-                               return ieee754si_xcpt(0, "fcmpf", x);
+                       if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION))
+                               return 0;
                }
                return 0;
        } else {
-               int vx = x.bits;
-               int vy = y.bits;
+               vx = x.bits;
+               vy = y.bits;
 
                if (vx < 0)
                        vx = -vx ^ SP_SIGN_BIT;
index d7747928c95492986fdcb3b671abf2e6d126b32f..721f317aa8778bc8a0a71c6c76252ebe269a72b4 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
+union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y)
 {
+       unsigned rm;
+       int re;
+       unsigned bm;
+
        COMPXSP;
        COMPYSP;
 
        EXPLODEXSP;
        EXPLODEYSP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXSP;
        FLUSHYSP;
@@ -51,8 +50,8 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "div", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,12 +67,12 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
                return x;
 
 
-               /* Infinity handling
-                */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
@@ -85,17 +84,17 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
                return ieee754sp_inf(xs ^ ys);
 
-               /* Zero handling
-                */
-
+       /*
+        * Zero handling
+        */
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-               SETCX(IEEE754_ZERO_DIVIDE);
-               return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y);
+               ieee754_setcx(IEEE754_ZERO_DIVIDE);
+               return ieee754sp_inf(xs ^ ys);
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
@@ -122,35 +121,33 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
        xm <<= 3;
        ym <<= 3;
 
-       {
-               /* now the dirty work */
-
-               unsigned rm = 0;
-               int re = xe - ye;
-               unsigned bm;
-
-               for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) {
-                       if (xm >= ym) {
-                               xm -= ym;
-                               rm |= bm;
-                               if (xm == 0)
-                                       break;
-                       }
-                       xm <<= 1;
-               }
-               rm <<= 1;
-               if (xm)
-                       rm |= 1;        /* have remainder, set sticky */
+       /* now the dirty work */
 
-               assert(rm);
+       rm = 0;
+       re = xe - ye;
 
-               /* normalise rm to rounding precision ?
-                */
-               while ((rm >> (SP_MBITS + 3)) == 0) {
-                       rm <<= 1;
-                       re--;
+       for (bm = SP_MBIT(SP_FBITS + 2); bm; bm >>= 1) {
+               if (xm >= ym) {
+                       xm -= ym;
+                       rm |= bm;
+                       if (xm == 0)
+                               break;
                }
+               xm <<= 1;
+       }
+
+       rm <<= 1;
+       if (xm)
+               rm |= 1;        /* have remainder, set sticky */
 
-               SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
+       assert(rm);
+
+       /* normalise rm to rounding precision ?
+        */
+       while ((rm >> (SP_FBITS + 3)) == 0) {
+               rm <<= 1;
+               re--;
        }
+
+       return ieee754sp_format(xs == ys ? 0 : 1, re, rm);
 }
index e1515aae0166d4653eb395a38555b9b7b0630997..1b266fb16973093016a96eb5c77197eebfc390ef 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
+#include "ieee754dp.h"
 
-ieee754sp ieee754sp_fdp(ieee754dp x)
+union ieee754sp ieee754sp_fdp(union ieee754dp x)
 {
+       u32 rm;
+
        COMPXDP;
-       ieee754sp nan;
+       union ieee754sp nan;
 
        EXPLODEXDP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXDP;
 
        switch (xc) {
        case IEEE754_CLASS_SNAN:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp");
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
+
        case IEEE754_CLASS_QNAN:
                nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32)
-                               (xm >> (DP_MBITS - SP_MBITS)));
+                               (xm >> (DP_FBITS - SP_FBITS)));
                if (!ieee754sp_isnan(nan))
                        nan = ieee754sp_indef();
-               return ieee754sp_nanxcpt(nan, "fdp", x);
+               return ieee754sp_nanxcpt(nan);
+
        case IEEE754_CLASS_INF:
                return ieee754sp_inf(xs);
+
        case IEEE754_CLASS_ZERO:
                return ieee754sp_zero(xs);
+
        case IEEE754_CLASS_DNORM:
                /* can't possibly be sp representable */
-               SETCX(IEEE754_UNDERFLOW);
-               SETCX(IEEE754_INEXACT);
-               if ((ieee754_csr.rm == IEEE754_RU && !xs) ||
-                               (ieee754_csr.rm == IEEE754_RD && xs))
-                       return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x);
-               return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x);
+               ieee754_setcx(IEEE754_UNDERFLOW);
+               ieee754_setcx(IEEE754_INEXACT);
+               if ((ieee754_csr.rm == FPU_CSR_RU && !xs) ||
+                               (ieee754_csr.rm == FPU_CSR_RD && xs))
+                       return ieee754sp_mind(xs);
+               return ieee754sp_zero(xs);
+
        case IEEE754_CLASS_NORM:
                break;
        }
 
-       {
-               u32 rm;
-
-               /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift
-                */
-               rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) |
-                   ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0);
+       /*
+        * Convert from DP_FBITS to SP_FBITS+3 with sticky right shift.
+        */
+       rm = (xm >> (DP_FBITS - (SP_FBITS + 3))) |
+            ((xm << (64 - (DP_FBITS - (SP_FBITS + 3)))) != 0);
 
-               SPNORMRET1(xs, xe, rm, "fdp", x);
-       }
+       return ieee754sp_format(xs, xe, rm);
 }
index 9694d6c016cb12081d94c139ef5b97efa9f378d4..d5d8495b2cc4d1690a8ce09c0dca41bd7381dea7 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_fint(int x)
+union ieee754sp ieee754sp_fint(int x)
 {
        unsigned xm;
        int xe;
        int xs;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        if (x == 0)
                return ieee754sp_zero(0);
@@ -50,30 +45,21 @@ ieee754sp ieee754sp_fint(int x)
        } else {
                xm = x;
        }
-       xe = SP_MBITS + 3;
+       xe = SP_FBITS + 3;
 
-       if (xm >> (SP_MBITS + 1 + 3)) {
+       if (xm >> (SP_FBITS + 1 + 3)) {
                /* shunt out overflow bits
                 */
-               while (xm >> (SP_MBITS + 1 + 3)) {
+               while (xm >> (SP_FBITS + 1 + 3)) {
                        SPXSRSX1();
                }
        } else {
                /* normalize in grs extended single precision
                 */
-               while ((xm >> (SP_MBITS + 3)) == 0) {
+               while ((xm >> (SP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
        }
-       SPNORMRET1(xs, xe, xm, "fint", x);
-}
-
-
-ieee754sp ieee754sp_funs(unsigned int u)
-{
-       if ((int) u < 0)
-               return ieee754sp_add(ieee754sp_1e31(),
-                                    ieee754sp_fint(u & ~(1 << 31)));
-       return ieee754sp_fint(u);
+       return ieee754sp_format(xs, xe, xm);
 }
index 16a651f2986544c489d6a5db0a06ac5a4543cc66..012e30ce7589fe2b409af91a8b63c8d2706b555e 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_flong(s64 x)
+union ieee754sp ieee754sp_flong(s64 x)
 {
        u64 xm;         /* <--- need 64-bit mantissa temp */
        int xe;
        int xs;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        if (x == 0)
                return ieee754sp_zero(0);
@@ -50,29 +45,20 @@ ieee754sp ieee754sp_flong(s64 x)
        } else {
                xm = x;
        }
-       xe = SP_MBITS + 3;
+       xe = SP_FBITS + 3;
 
-       if (xm >> (SP_MBITS + 1 + 3)) {
+       if (xm >> (SP_FBITS + 1 + 3)) {
                /* shunt out overflow bits
                 */
-               while (xm >> (SP_MBITS + 1 + 3)) {
+               while (xm >> (SP_FBITS + 1 + 3)) {
                        SPXSRSX1();
                }
        } else {
                /* normalize in grs extended single precision */
-               while ((xm >> (SP_MBITS + 3)) == 0) {
+               while ((xm >> (SP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
        }
-       SPNORMRET1(xs, xe, xm, "sp_flong", x);
-}
-
-
-ieee754sp ieee754sp_fulong(u64 u)
-{
-       if ((s64) u < 0)
-               return ieee754sp_add(ieee754sp_1e63(),
-                                    ieee754sp_flong(u & ~(1ULL << 63)));
-       return ieee754sp_flong(u);
+       return ieee754sp_format(xs, xe, xm);
 }
diff --git a/arch/mips/math-emu/sp_frexp.c b/arch/mips/math-emu/sp_frexp.c
deleted file mode 100644 (file)
index 5bc993c..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754sp.h"
-
-/* close to ieeep754sp_logb
-*/
-ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr)
-{
-       COMPXSP;
-       CLEARCX;
-       EXPLODEXSP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-       case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
-       case IEEE754_CLASS_ZERO:
-               *eptr = 0;
-               return x;
-       case IEEE754_CLASS_DNORM:
-               SPDNORMX;
-               break;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       *eptr = xe + 1;
-       return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
-}
diff --git a/arch/mips/math-emu/sp_logb.c b/arch/mips/math-emu/sp_logb.c
deleted file mode 100644 (file)
index 9c14e0c..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754sp.h"
-
-ieee754sp ieee754sp_logb(ieee754sp x)
-{
-       COMPXSP;
-
-       CLEARCX;
-
-       EXPLODEXSP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-               return ieee754sp_nanxcpt(x, "logb", x);
-       case IEEE754_CLASS_QNAN:
-               return x;
-       case IEEE754_CLASS_INF:
-               return ieee754sp_inf(0);
-       case IEEE754_CLASS_ZERO:
-               return ieee754sp_inf(1);
-       case IEEE754_CLASS_DNORM:
-               SPDNORMX;
-               break;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       return ieee754sp_fint(xe);
-}
diff --git a/arch/mips/math-emu/sp_modf.c b/arch/mips/math-emu/sp_modf.c
deleted file mode 100644 (file)
index 25a0fba..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754sp.h"
-
-/* modf function is always exact for a finite number
-*/
-ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp *ip)
-{
-       COMPXSP;
-
-       CLEARCX;
-
-       EXPLODEXSP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-       case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
-       case IEEE754_CLASS_ZERO:
-               *ip = x;
-               return x;
-       case IEEE754_CLASS_DNORM:
-               /* far to small */
-               *ip = ieee754sp_zero(xs);
-               return x;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       if (xe < 0) {
-               *ip = ieee754sp_zero(xs);
-               return x;
-       }
-       if (xe >= SP_MBITS) {
-               *ip = x;
-               return ieee754sp_zero(xs);
-       }
-       /* generate ipart mantissa by clearing bottom bits
-        */
-       *ip = buildsp(xs, xe + SP_EBIAS,
-                     ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) &
-                     ~SP_HIDDEN_BIT);
-
-       /* generate fpart mantissa by clearing top bits
-        * and normalizing (must be able to normalize)
-        */
-       xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe));
-       if (xm == 0)
-               return ieee754sp_zero(xs);
-
-       while ((xm >> SP_MBITS) == 0) {
-               xm <<= 1;
-               xe--;
-       }
-       return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
-}
index fa4675cf2aad13d2deef5b4d86f6c059d1fdb1ec..890c13a2965e78ffb5aca93eb3105e74b0e8ee58 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
+union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y)
 {
+       int re;
+       int rs;
+       unsigned rm;
+       unsigned short lxm;
+       unsigned short hxm;
+       unsigned short lym;
+       unsigned short hym;
+       unsigned lrm;
+       unsigned hrm;
+       unsigned t;
+       unsigned at;
+
        COMPXSP;
        COMPYSP;
 
        EXPLODEXSP;
        EXPLODEYSP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXSP;
        FLUSHYSP;
@@ -51,8 +58,8 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,12 +75,13 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
                return x;
 
 
-               /* Infinity handling */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_indef();
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
@@ -108,63 +116,50 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
        assert(xm & SP_HIDDEN_BIT);
        assert(ym & SP_HIDDEN_BIT);
 
-       {
-               int re = xe + ye;
-               int rs = xs ^ ys;
-               unsigned rm;
-
-               /* shunt to top of word */
-               xm <<= 32 - (SP_MBITS + 1);
-               ym <<= 32 - (SP_MBITS + 1);
-
-               /* multiply 32bits xm,ym to give high 32bits rm with stickness
-                */
-               {
-                       unsigned short lxm = xm & 0xffff;
-                       unsigned short hxm = xm >> 16;
-                       unsigned short lym = ym & 0xffff;
-                       unsigned short hym = ym >> 16;
-                       unsigned lrm;
-                       unsigned hrm;
-
-                       lrm = lxm * lym;        /* 16 * 16 => 32 */
-                       hrm = hxm * hym;        /* 16 * 16 => 32 */
-
-                       {
-                               unsigned t = lxm * hym; /* 16 * 16 => 32 */
-                               {
-                                       unsigned at = lrm + (t << 16);
-                                       hrm += at < lrm;
-                                       lrm = at;
-                               }
-                               hrm = hrm + (t >> 16);
-                       }
-
-                       {
-                               unsigned t = hxm * lym; /* 16 * 16 => 32 */
-                               {
-                                       unsigned at = lrm + (t << 16);
-                                       hrm += at < lrm;
-                                       lrm = at;
-                               }
-                               hrm = hrm + (t >> 16);
-                       }
-                       rm = hrm | (lrm != 0);
-               }
-
-               /*
-                * sticky shift down to normal rounding precision
-                */
-               if ((int) rm < 0) {
-                       rm = (rm >> (32 - (SP_MBITS + 1 + 3))) |
-                           ((rm << (SP_MBITS + 1 + 3)) != 0);
-                       re++;
-               } else {
-                       rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) |
-                           ((rm << (SP_MBITS + 1 + 3 + 1)) != 0);
-               }
-               assert(rm & (SP_HIDDEN_BIT << 3));
-
-               SPNORMRET2(rs, re, rm, "mul", x, y);
+       re = xe + ye;
+       rs = xs ^ ys;
+
+       /* shunt to top of word */
+       xm <<= 32 - (SP_FBITS + 1);
+       ym <<= 32 - (SP_FBITS + 1);
+
+       /*
+        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
+        */
+       lxm = xm & 0xffff;
+       hxm = xm >> 16;
+       lym = ym & 0xffff;
+       hym = ym >> 16;
+
+       lrm = lxm * lym;        /* 16 * 16 => 32 */
+       hrm = hxm * hym;        /* 16 * 16 => 32 */
+
+       t = lxm * hym; /* 16 * 16 => 32 */
+       at = lrm + (t << 16);
+       hrm += at < lrm;
+       lrm = at;
+       hrm = hrm + (t >> 16);
+
+       t = hxm * lym; /* 16 * 16 => 32 */
+       at = lrm + (t << 16);
+       hrm += at < lrm;
+       lrm = at;
+       hrm = hrm + (t >> 16);
+
+       rm = hrm | (lrm != 0);
+
+       /*
+        * Sticky shift down to normal rounding precision.
+        */
+       if ((int) rm < 0) {
+               rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
+                   ((rm << (SP_FBITS + 1 + 3)) != 0);
+               re++;
+       } else {
+               rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
+                    ((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
        }
+       assert(rm & (SP_HIDDEN_BIT << 3));
+
+       return ieee754sp_format(rs, re, rm);
 }
diff --git a/arch/mips/math-emu/sp_scalb.c b/arch/mips/math-emu/sp_scalb.c
deleted file mode 100644 (file)
index dd76196..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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 "ieee754sp.h"
-
-ieee754sp ieee754sp_scalb(ieee754sp x, int n)
-{
-       COMPXSP;
-
-       CLEARCX;
-
-       EXPLODEXSP;
-
-       switch (xc) {
-       case IEEE754_CLASS_SNAN:
-               return ieee754sp_nanxcpt(x, "scalb", x, n);
-       case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
-       case IEEE754_CLASS_ZERO:
-               return x;
-       case IEEE754_CLASS_DNORM:
-               SPDNORMX;
-               break;
-       case IEEE754_CLASS_NORM:
-               break;
-       }
-       SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
-}
-
-
-ieee754sp ieee754sp_ldexp(ieee754sp x, int n)
-{
-       return ieee754sp_scalb(x, n);
-}
index ae4fcfafd85335533bd117967faa9d3f975da595..f1ffaa9a17e042a40e199a468dcde3a4fff244ab 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-int ieee754sp_finite(ieee754sp x)
-{
-       return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
-}
-
-ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y)
-{
-       CLEARCX;
-       SPSIGN(x) = SPSIGN(y);
-       return x;
-}
-
-
-ieee754sp ieee754sp_neg(ieee754sp x)
+union ieee754sp ieee754sp_neg(union ieee754sp x)
 {
        COMPXSP;
 
        EXPLODEXSP;
-       CLEARCX;
+       ieee754_clearcx();
        FLUSHXSP;
 
        /*
@@ -55,30 +37,29 @@ ieee754sp ieee754sp_neg(ieee754sp x)
        SPSIGN(x) ^= 1;
 
        if (xc == IEEE754_CLASS_SNAN) {
-               ieee754sp y = ieee754sp_indef();
-               SETCX(IEEE754_INVALID_OPERATION);
+               union ieee754sp y = ieee754sp_indef();
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
                SPSIGN(y) = SPSIGN(x);
-               return ieee754sp_nanxcpt(y, "neg");
+               return ieee754sp_nanxcpt(y);
        }
 
        return x;
 }
 
-
-ieee754sp ieee754sp_abs(ieee754sp x)
+union ieee754sp ieee754sp_abs(union ieee754sp x)
 {
        COMPXSP;
 
        EXPLODEXSP;
-       CLEARCX;
+       ieee754_clearcx();
        FLUSHXSP;
 
        /* Clear sign ALWAYS, irrespective of NaN */
        SPSIGN(x) = 0;
 
        if (xc == IEEE754_CLASS_SNAN) {
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "abs");
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
        }
 
        return x;
index fed20175f5fb5f516b28b650987ce1b2c15f61d0..b7c098a86f951013f74d5d3838fef5ae014cbd9b 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_sqrt(ieee754sp x)
+union ieee754sp ieee754sp_sqrt(union ieee754sp x)
 {
        int ix, s, q, m, t, i;
        unsigned int r;
@@ -35,34 +30,38 @@ ieee754sp ieee754sp_sqrt(ieee754sp x)
        /* take care of Inf and NaN */
 
        EXPLODEXSP;
-       CLEARCX;
+       ieee754_clearcx();
        FLUSHXSP;
 
        /* x == INF or NAN? */
        switch (xc) {
        case IEEE754_CLASS_QNAN:
                /* sqrt(Nan) = Nan */
-               return ieee754sp_nanxcpt(x, "sqrt");
+               return ieee754sp_nanxcpt(x);
+
        case IEEE754_CLASS_SNAN:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt");
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
+
        case IEEE754_CLASS_ZERO:
                /* sqrt(0) = 0 */
                return x;
+
        case IEEE754_CLASS_INF:
                if (xs) {
                        /* sqrt(-Inf) = Nan */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt");
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754sp_nanxcpt(ieee754sp_indef());
                }
                /* sqrt(+Inf) = Inf */
                return x;
+
        case IEEE754_CLASS_DNORM:
        case IEEE754_CLASS_NORM:
                if (xs) {
                        /* sqrt(-x) = Nan */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt");
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754sp_nanxcpt(ieee754sp_indef());
                }
                break;
        }
@@ -99,12 +98,12 @@ ieee754sp ieee754sp_sqrt(ieee754sp x)
        }
 
        if (ix != 0) {
-               SETCX(IEEE754_INEXACT);
+               ieee754_setcx(IEEE754_INEXACT);
                switch (ieee754_csr.rm) {
-               case IEEE754_RP:
+               case FPU_CSR_RU:
                        q += 2;
                        break;
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        q += (q & 1);
                        break;
                }
index e595c6f3d0bb9d4e3711eecb002635d38af45209..8592e49032b876d9e4eb1921e9385b05814e5e19 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
+union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y)
 {
+       int s;
+
        COMPXSP;
        COMPYSP;
 
        EXPLODEXSP;
        EXPLODEYSP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        FLUSHXSP;
        FLUSHYSP;
@@ -51,8 +48,8 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "sub", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_nanxcpt(ieee754sp_indef());
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
@@ -68,14 +65,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
                return x;
 
 
-               /* Infinity handling
-                */
-
+       /*
+        * Infinity handling
+        */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
                if (xs != ys)
                        return x;
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754sp_indef();
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
@@ -87,15 +84,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
                return x;
 
-               /* Zero handling
-                */
-
+       /*
+        * Zero handling
+        */
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
                if (xs != ys)
                        return x;
                else
-                       return ieee754sp_zero(ieee754_csr.rm ==
-                                             IEEE754_RD);
+                       return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
@@ -104,7 +100,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
                /* quick fix up */
-               DPSIGN(y) ^= 1;
+               SPSIGN(y) ^= 1;
                return y;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
@@ -133,14 +129,16 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
        ym <<= 3;
 
        if (xe > ye) {
-               /* have to shift y fraction right to align
+               /*
+                * have to shift y fraction right to align
                 */
-               int s = xe - ye;
+               s = xe - ye;
                SPXSRSYn(s);
        } else if (ye > xe) {
-               /* have to shift x fraction right to align
+               /*
+                * have to shift x fraction right to align
                 */
-               int s = ye - xe;
+               s = ye - xe;
                SPXSRSXn(s);
        }
        assert(xe == ye);
@@ -153,7 +151,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
                xe = xe;
                xs = xs;
 
-               if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */
+               if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */
                        SPXSRSX1();     /* shift preserving sticky */
                }
        } else {
@@ -167,17 +165,18 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
                        xs = ys;
                }
                if (xm == 0) {
-                       if (ieee754_csr.rm == IEEE754_RD)
+                       if (ieee754_csr.rm == FPU_CSR_RD)
                                return ieee754sp_zero(1);       /* round negative inf. => sign = -1 */
                        else
                                return ieee754sp_zero(0);       /* other round modes   => sign = 1 */
                }
                /* normalize to rounding precision
                 */
-               while ((xm >> (SP_MBITS + 3)) == 0) {
+               while ((xm >> (SP_FBITS + 3)) == 0) {
                        xm <<= 1;
                        xe--;
                }
        }
-       SPNORMRET2(xs, xe, xm, "sub", x, y);
+
+       return ieee754sp_format(xs, xe, xm);
 }
index 0fe9acc7716edecdf005be7836bb4544bcca9473..091299a317980b6bf0cfd84f0958b1f271d2bf9d 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
-#include <linux/kernel.h>
 #include "ieee754sp.h"
 
-int ieee754sp_tint(ieee754sp x)
+int ieee754sp_tint(union ieee754sp x)
 {
+       u32 residue;
+       int round;
+       int sticky;
+       int odd;
+
        COMPXSP;
 
-       CLEARCX;
+       ieee754_clearcx();
 
        EXPLODEXSP;
        FLUSHXSP;
@@ -40,10 +39,12 @@ int ieee754sp_tint(ieee754sp x)
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
        case IEEE754_CLASS_INF:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754si_indef();
+
        case IEEE754_CLASS_ZERO:
                return 0;
+
        case IEEE754_CLASS_DNORM:
        case IEEE754_CLASS_NORM:
                break;
@@ -54,18 +55,13 @@ int ieee754sp_tint(ieee754sp x)
                        return -0x80000000;
                /* Set invalid. We will only use overflow for floating
                   point overflow */
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754si_indef();
        }
        /* oh gawd */
-       if (xe > SP_MBITS) {
-               xm <<= xe - SP_MBITS;
+       if (xe > SP_FBITS) {
+               xm <<= xe - SP_FBITS;
        } else {
-               u32 residue;
-               int round;
-               int sticky;
-               int odd;
-
                if (xe < -1) {
                        residue = xm;
                        round = 0;
@@ -76,51 +72,38 @@ int ieee754sp_tint(ieee754sp x)
                        * so we do it in two steps. Be aware that xe
                        * may be -1 */
                        residue = xm << (xe + 1);
-                       residue <<= 31 - SP_MBITS;
+                       residue <<= 31 - SP_FBITS;
                        round = (residue >> 31) != 0;
                        sticky = (residue << 1) != 0;
-                       xm >>= SP_MBITS - xe;
+                       xm >>= SP_FBITS - xe;
                }
                odd = (xm & 0x1) != 0x0;
                switch (ieee754_csr.rm) {
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        if (round && (sticky || odd))
                                xm++;
                        break;
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        break;
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if ((round || sticky) && !xs)
                                xm++;
                        break;
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if ((round || sticky) && xs)
                                xm++;
                        break;
                }
                if ((xm >> 31) != 0) {
                        /* This can happen after rounding */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x);
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754si_indef();
                }
                if (round || sticky)
-                       SETCX(IEEE754_INEXACT);
+                       ieee754_setcx(IEEE754_INEXACT);
        }
        if (xs)
                return -xm;
        else
                return xm;
 }
-
-
-unsigned int ieee754sp_tuns(ieee754sp x)
-{
-       ieee754sp hb = ieee754sp_1e31();
-
-       /* what if x < 0 ?? */
-       if (ieee754sp_lt(x, hb))
-               return (unsigned) ieee754sp_tint(x);
-
-       return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) |
-           ((unsigned) 1 << 31);
-}
index d0ca6e22be29278daf1d52fe7c7c9129d1c0d403..9f3c742c1cea6ac264d1d4d66ef56b6916f675cb 100644 (file)
@@ -5,8 +5,6 @@
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
  *
- * ########################################################################
- *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
  *  published by the Free Software Foundation.
  *
  *  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.
- *
- * ########################################################################
+ *  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-
 #include "ieee754sp.h"
+#include "ieee754dp.h"
 
-s64 ieee754sp_tlong(ieee754sp x)
+s64 ieee754sp_tlong(union ieee754sp x)
 {
+       u32 residue;
+       int round;
+       int sticky;
+       int odd;
+
        COMPXDP;                /* <-- need 64-bit mantissa tmp */
 
-       CLEARCX;
+       ieee754_clearcx();
 
        EXPLODEXSP;
        FLUSHXSP;
@@ -39,10 +40,12 @@ s64 ieee754sp_tlong(ieee754sp x)
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
        case IEEE754_CLASS_INF:
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754di_indef();
+
        case IEEE754_CLASS_ZERO:
                return 0;
+
        case IEEE754_CLASS_DNORM:
        case IEEE754_CLASS_NORM:
                break;
@@ -53,69 +56,51 @@ s64 ieee754sp_tlong(ieee754sp x)
                        return -0x8000000000000000LL;
                /* Set invalid. We will only use overflow for floating
                   point overflow */
-               SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754di_indef();
        }
        /* oh gawd */
-       if (xe > SP_MBITS) {
-               xm <<= xe - SP_MBITS;
-       } else if (xe < SP_MBITS) {
-               u32 residue;
-               int round;
-               int sticky;
-               int odd;
-
+       if (xe > SP_FBITS) {
+               xm <<= xe - SP_FBITS;
+       } else if (xe < SP_FBITS) {
                if (xe < -1) {
                        residue = xm;
                        round = 0;
                        sticky = residue != 0;
                        xm = 0;
                } else {
-                       residue = xm << (32 - SP_MBITS + xe);
+                       residue = xm << (32 - SP_FBITS + xe);
                        round = (residue >> 31) != 0;
                        sticky = (residue << 1) != 0;
-                       xm >>= SP_MBITS - xe;
+                       xm >>= SP_FBITS - xe;
                }
                odd = (xm & 0x1) != 0x0;
                switch (ieee754_csr.rm) {
-               case IEEE754_RN:
+               case FPU_CSR_RN:
                        if (round && (sticky || odd))
                                xm++;
                        break;
-               case IEEE754_RZ:
+               case FPU_CSR_RZ:
                        break;
-               case IEEE754_RU:        /* toward +Infinity */
+               case FPU_CSR_RU:        /* toward +Infinity */
                        if ((round || sticky) && !xs)
                                xm++;
                        break;
-               case IEEE754_RD:        /* toward -Infinity */
+               case FPU_CSR_RD:        /* toward -Infinity */
                        if ((round || sticky) && xs)
                                xm++;
                        break;
                }
                if ((xm >> 63) != 0) {
                        /* This can happen after rounding */
-                       SETCX(IEEE754_INVALID_OPERATION);
-                       return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754di_indef();
                }
                if (round || sticky)
-                       SETCX(IEEE754_INEXACT);
+                       ieee754_setcx(IEEE754_INEXACT);
        }
        if (xs)
                return -xm;
        else
                return xm;
 }
-
-
-u64 ieee754sp_tulong(ieee754sp x)
-{
-       ieee754sp hb = ieee754sp_1e63();
-
-       /* what if x < 0 ?? */
-       if (ieee754sp_lt(x, hb))
-               return (u64) ieee754sp_tlong(x);
-
-       return (u64) ieee754sp_tlong(ieee754sp_sub(x, hb)) |
-           (1ULL << 63);
-}
index a580642555b6f0e7f087ade117ce062cb303d429..348356c99514f0cdfb8876b9f22c0464ab8e3734 100644 (file)
@@ -1,6 +1,8 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += resource.h
+
 header-y += bitsperlong.h
 header-y += byteorder.h
 header-y += errno.h
@@ -13,7 +15,6 @@ header-y += msgbuf.h
 header-y += pdc.h
 header-y += posix_types.h
 header-y += ptrace.h
-header-y += resource.h
 header-y += sembuf.h
 header-y += setup.h
 header-y += shmbuf.h
diff --git a/arch/parisc/include/uapi/asm/resource.h b/arch/parisc/include/uapi/asm/resource.h
deleted file mode 100644 (file)
index 8b06343..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _ASM_PARISC_RESOURCE_H
-#define _ASM_PARISC_RESOURCE_H
-
-#define _STK_LIM_MAX   10 * _STK_LIM
-#include <asm-generic/resource.h>
-
-#endif
index 4c0cedf4e2c7dda768378223deb024c03a94b7c9..68cde2f8a12c52d6657675f1ee6fb5355f625d87 100644 (file)
@@ -113,8 +113,13 @@ else
 endif
 endif
 
-CFLAGS-$(CONFIG_PPC64) := -mtraceback=no -mcall-aixdesc
-CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1)
+CFLAGS-$(CONFIG_PPC64) := -mtraceback=no
+ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
+CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,-mcall-aixdesc)
+AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2)
+else
+CFLAGS-$(CONFIG_PPC64) += -mcall-aixdesc
+endif
 CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,-mminimal-toc)
 CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions)
 CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 $(MULTIPLEWORD)
@@ -151,7 +156,7 @@ endif
 CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
 
 KBUILD_CPPFLAGS        += -Iarch/$(ARCH)
-KBUILD_AFLAGS  += -Iarch/$(ARCH)
+KBUILD_AFLAGS  += -Iarch/$(ARCH) $(AFLAGS-y)
 KBUILD_CFLAGS  += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
 CPP            = $(CC) -E $(KBUILD_CFLAGS)
 
@@ -159,6 +164,11 @@ CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)
 
 KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
 
+ifeq ($(CONFIG_476FPE_ERR46),y)
+       KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
+               -T $(srctree)/arch/powerpc/platforms/44x/ppc476_modules.lds
+endif
+
 # No AltiVec or VSX instructions when building kernel
 KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
 KBUILD_CFLAGS += $(call cc-option,-mno-vsx)
index a1f8c7f1ec60138db045ae6b46b57bec62169538..426dce7ae7c4974db360c15bd6b6c9257d6564d1 100644 (file)
@@ -22,8 +22,14 @@ all: $(obj)/zImage
 BOOTCFLAGS    := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                 -fno-strict-aliasing -Os -msoft-float -pipe \
                 -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \
-                -isystem $(shell $(CROSS32CC) -print-file-name=include) \
-                -mbig-endian
+                -isystem $(shell $(CROSS32CC) -print-file-name=include)
+ifdef CONFIG_PPC64_BOOT_WRAPPER
+BOOTCFLAGS     += -m64
+endif
+ifdef CONFIG_CPU_BIG_ENDIAN
+BOOTCFLAGS     += -mbig-endian
+endif
+
 BOOTAFLAGS     := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
 
 ifdef CONFIG_DEBUG_INFO
@@ -47,6 +53,7 @@ $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
 $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
 $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405
 $(obj)/treeboot-currituck.o: BOOTCFLAGS += -mcpu=405
+$(obj)/treeboot-akebono.o: BOOTCFLAGS += -mcpu=405
 $(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405
 
 
@@ -86,6 +93,7 @@ src-plat-$(CONFIG_44x) += treeboot-ebony.c cuboot-ebony.c treeboot-bamboo.c \
                                cuboot-taishan.c cuboot-katmai.c \
                                cuboot-warp.c cuboot-yosemite.c \
                                treeboot-iss4xx.c treeboot-currituck.c \
+                               treeboot-akebono.c \
                                simpleboot.c fixed-head.S virtex.c
 src-plat-$(CONFIG_8xx) += cuboot-8xx.c fixed-head.S ep88xc.c redboot-8xx.c
 src-plat-$(CONFIG_PPC_MPC52xx) += cuboot-52xx.c
@@ -99,6 +107,11 @@ src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.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 epapr-wrapper.c
+src-plat-$(CONFIG_PPC_PSERIES) += pseries-head.S
+src-plat-$(CONFIG_PPC_POWERNV) += pseries-head.S
+src-plat-$(CONFIG_PPC_IBM_CELL_BLADE) += pseries-head.S
+src-plat-$(CONFIG_PPC_CELLEB) += pseries-head.S
+src-plat-$(CONFIG_PPC_CELL_QPACE) += pseries-head.S
 
 src-wlib := $(sort $(src-wlib-y))
 src-plat := $(sort $(src-plat-y))
@@ -137,7 +150,11 @@ $(addprefix $(obj)/,$(libfdt) $(libfdtheader)): $(obj)/%: $(srctree)/scripts/dtc
 $(obj)/empty.c:
        @touch $@
 
-$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds: $(obj)/%: $(srctree)/$(src)/%.S
+$(obj)/zImage.lds: $(obj)/%: $(srctree)/$(src)/%.S
+       $(CROSS32CC) $(cpp_flags) -E -Wp,-MD,$(depfile) -P -Upowerpc \
+               -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+
+$(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds : $(obj)/%: $(srctree)/$(src)/%.S
        @cp $< $@
 
 clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
@@ -235,6 +252,7 @@ image-$(CONFIG_YOSEMITE)            += cuImage.yosemite
 image-$(CONFIG_ISS4xx)                 += treeImage.iss4xx \
                                           treeImage.iss4xx-mpic
 image-$(CONFIG_CURRITUCK)                      += treeImage.currituck
+image-$(CONFIG_AKEBONO)                        += treeImage.akebono
 
 # Board ports in arch/powerpc/platform/8xx/Kconfig
 image-$(CONFIG_MPC86XADS)              += cuImage.mpc866ads
index 349b5530d2c4c31394cdb03080f4491fcbe047ed..9d9f6f334d3cc022f8c1ee39c30fe802863b38b0 100644 (file)
@@ -6,6 +6,8 @@
  *
  * Copyright 2000 Paul Mackerras.
  *
+ * Adapted for 64 bit little endian images by Andrew Tauferner.
+ *
  * This program is free software; 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
@@ -55,36 +57,61 @@ unsigned int rpanote[N_RPA_DESCR] = {
 
 #define ROUNDUP(len)   (((len) + 3) & ~3)
 
-unsigned char buf[512];
+unsigned char buf[1024];
+#define ELFDATA2LSB     1
+#define ELFDATA2MSB     2
+static int e_data = ELFDATA2MSB;
+#define ELFCLASS32      1
+#define ELFCLASS64      2
+static int e_class = ELFCLASS32;
 
 #define GET_16BE(off)  ((buf[off] << 8) + (buf[(off)+1]))
-#define GET_32BE(off)  ((GET_16BE(off) << 16) + GET_16BE((off)+2))
-
-#define PUT_16BE(off, v)       (buf[off] = ((v) >> 8) & 0xff, \
-                                buf[(off) + 1] = (v) & 0xff)
-#define PUT_32BE(off, v)       (PUT_16BE((off), (v) >> 16), \
-                                PUT_16BE((off) + 2, (v)))
+#define GET_32BE(off)  ((GET_16BE(off) << 16U) + GET_16BE((off)+2U))
+#define GET_64BE(off)  ((((unsigned long long)GET_32BE(off)) << 32ULL) + \
+                       ((unsigned long long)GET_32BE((off)+4ULL)))
+#define PUT_16BE(off, v)(buf[off] = ((v) >> 8) & 0xff, \
+                        buf[(off) + 1] = (v) & 0xff)
+#define PUT_32BE(off, v)(PUT_16BE((off), (v) >> 16L), PUT_16BE((off) + 2, (v)))
+#define PUT_64BE(off, v)((PUT_32BE((off), (v) >> 32L), \
+                         PUT_32BE((off) + 4, (v))))
+
+#define GET_16LE(off)  ((buf[off]) + (buf[(off)+1] << 8))
+#define GET_32LE(off)  (GET_16LE(off) + (GET_16LE((off)+2U) << 16U))
+#define GET_64LE(off)  ((unsigned long long)GET_32LE(off) + \
+                       (((unsigned long long)GET_32LE((off)+4ULL)) << 32ULL))
+#define PUT_16LE(off, v) (buf[off] = (v) & 0xff, \
+                         buf[(off) + 1] = ((v) >> 8) & 0xff)
+#define PUT_32LE(off, v) (PUT_16LE((off), (v)), PUT_16LE((off) + 2, (v) >> 16L))
+#define PUT_64LE(off, v) (PUT_32LE((off), (v)), PUT_32LE((off) + 4, (v) >> 32L))
+
+#define GET_16(off)    (e_data == ELFDATA2MSB ? GET_16BE(off) : GET_16LE(off))
+#define GET_32(off)    (e_data == ELFDATA2MSB ? GET_32BE(off) : GET_32LE(off))
+#define GET_64(off)    (e_data == ELFDATA2MSB ? GET_64BE(off) : GET_64LE(off))
+#define PUT_16(off, v) (e_data == ELFDATA2MSB ? PUT_16BE(off, v) : \
+                        PUT_16LE(off, v))
+#define PUT_32(off, v)  (e_data == ELFDATA2MSB ? PUT_32BE(off, v) : \
+                        PUT_32LE(off, v))
+#define PUT_64(off, v)  (e_data == ELFDATA2MSB ? PUT_64BE(off, v) : \
+                        PUT_64LE(off, v))
 
 /* Structure of an ELF file */
 #define E_IDENT                0       /* ELF header */
-#define        E_PHOFF         28
-#define E_PHENTSIZE    42
-#define E_PHNUM                44
-#define E_HSIZE                52      /* size of ELF header */
+#define        E_PHOFF         (e_class == ELFCLASS32 ? 28 : 32)
+#define E_PHENTSIZE    (e_class == ELFCLASS32 ? 42 : 54)
+#define E_PHNUM                (e_class == ELFCLASS32 ? 44 : 56)
+#define E_HSIZE                (e_class == ELFCLASS32 ? 52 : 64)
 
 #define EI_MAGIC       0       /* offsets in E_IDENT area */
 #define EI_CLASS       4
 #define EI_DATA                5
 
 #define PH_TYPE                0       /* ELF program header */
-#define PH_OFFSET      4
-#define PH_FILESZ      16
-#define PH_HSIZE       32      /* size of program header */
+#define PH_OFFSET      (e_class == ELFCLASS32 ? 4 : 8)
+#define PH_FILESZ      (e_class == ELFCLASS32 ? 16 : 32)
+#define PH_HSIZE       (e_class == ELFCLASS32 ? 32 : 56)
 
 #define PT_NOTE                4       /* Program header type = note */
 
-#define ELFCLASS32     1
-#define ELFDATA2MSB    2
 
 unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
 
@@ -92,8 +119,8 @@ int
 main(int ac, char **av)
 {
        int fd, n, i;
-       int ph, ps, np;
-       int nnote, nnote2, ns;
+       unsigned long ph, ps, np;
+       long nnote, nnote2, ns;
 
        if (ac != 2) {
                fprintf(stderr, "Usage: %s elf-file\n", av[0]);
@@ -114,26 +141,27 @@ main(int ac, char **av)
                exit(1);
        }
 
-       if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
+       if (memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
+               goto notelf;
+       e_class = buf[E_IDENT+EI_CLASS];
+       if (e_class != ELFCLASS32 && e_class != ELFCLASS64)
+               goto notelf;
+       e_data = buf[E_IDENT+EI_DATA];
+       if (e_data != ELFDATA2MSB && e_data != ELFDATA2LSB)
+               goto notelf;
+       if (n < E_HSIZE)
                goto notelf;
 
-       if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
-           || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
-               fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
-                       av[1]);
-               exit(1);
-       }
-
-       ph = GET_32BE(E_PHOFF);
-       ps = GET_16BE(E_PHENTSIZE);
-       np = GET_16BE(E_PHNUM);
+       ph = (e_class == ELFCLASS32 ? GET_32(E_PHOFF) : GET_64(E_PHOFF));
+       ps = GET_16(E_PHENTSIZE);
+       np = GET_16(E_PHNUM);
        if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
                goto notelf;
        if (ph + (np + 2) * ps + nnote + nnote2 > n)
                goto nospace;
 
        for (i = 0; i < np; ++i) {
-               if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
+               if (GET_32(ph + PH_TYPE) == PT_NOTE) {
                        fprintf(stderr, "%s already has a note entry\n",
                                av[1]);
                        exit(0);
@@ -148,15 +176,22 @@ main(int ac, char **av)
 
        /* fill in the program header entry */
        ns = ph + 2 * ps;
-       PUT_32BE(ph + PH_TYPE, PT_NOTE);
-       PUT_32BE(ph + PH_OFFSET, ns);
-       PUT_32BE(ph + PH_FILESZ, nnote);
+       PUT_32(ph + PH_TYPE, PT_NOTE);
+       if (e_class == ELFCLASS32)
+               PUT_32(ph + PH_OFFSET, ns);
+       else
+               PUT_64(ph + PH_OFFSET, ns);
+
+       if (e_class == ELFCLASS32)
+               PUT_32(ph + PH_FILESZ, nnote);
+       else
+               PUT_64(ph + PH_FILESZ, nnote);
 
        /* fill in the note area we point to */
        /* XXX we should probably make this a proper section */
-       PUT_32BE(ns, strlen(arch) + 1);
-       PUT_32BE(ns + 4, N_DESCR * 4);
-       PUT_32BE(ns + 8, 0x1275);
+       PUT_32(ns, strlen(arch) + 1);
+       PUT_32(ns + 4, N_DESCR * 4);
+       PUT_32(ns + 8, 0x1275);
        strcpy((char *) &buf[ns + 12], arch);
        ns += 12 + strlen(arch) + 1;
        for (i = 0; i < N_DESCR; ++i, ns += 4)
@@ -164,21 +199,28 @@ main(int ac, char **av)
 
        /* fill in the second program header entry and the RPA note area */
        ph += ps;
-       PUT_32BE(ph + PH_TYPE, PT_NOTE);
-       PUT_32BE(ph + PH_OFFSET, ns);
-       PUT_32BE(ph + PH_FILESZ, nnote2);
+       PUT_32(ph + PH_TYPE, PT_NOTE);
+       if (e_class == ELFCLASS32)
+               PUT_32(ph + PH_OFFSET, ns);
+       else
+               PUT_64(ph + PH_OFFSET, ns);
+
+       if (e_class == ELFCLASS32)
+               PUT_32(ph + PH_FILESZ, nnote);
+       else
+               PUT_64(ph + PH_FILESZ, nnote2);
 
        /* fill in the note area we point to */
-       PUT_32BE(ns, strlen(rpaname) + 1);
-       PUT_32BE(ns + 4, sizeof(rpanote));
-       PUT_32BE(ns + 8, 0x12759999);
+       PUT_32(ns, strlen(rpaname) + 1);
+       PUT_32(ns + 4, sizeof(rpanote));
+       PUT_32(ns + 8, 0x12759999);
        strcpy((char *) &buf[ns + 12], rpaname);
        ns += 12 + ROUNDUP(strlen(rpaname) + 1);
        for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
                PUT_32BE(ns, rpanote[i]);
 
        /* Update the number of program headers */
-       PUT_16BE(E_PHNUM, np + 2);
+       PUT_16(E_PHNUM, np + 2);
 
        /* write back */
        lseek(fd, (long) 0, SEEK_SET);
index 0f7428a37efbeb247d63686d627ba260c7c03337..14de4f8778a7fa36ff1e0bfb1b49641913ee05a8 100644 (file)
@@ -1,17 +1,20 @@
 /*
  * Copyright (C) Paul Mackerras 1997.
  *
+ * Adapted for 64 bit LE PowerPC by Andrew Tauferner
+ *
  * This program is free software; 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.
  *
- * NOTE: this code runs in 32 bit mode, is position-independent,
- * and is packaged as ELF32.
  */
 
 #include "ppc_asm.h"
 
+RELA = 7
+RELACOUNT = 0x6ffffff9
+
        .text
        /* A procedure descriptor used when booting this as a COFF file.
         * When making COFF, this comes first in the link and we're
 _zimage_start_opd:
        .long   0x500000, 0, 0, 0
 
+#ifdef __powerpc64__
+.balign 8
+p_start:       .llong  _start
+p_etext:       .llong  _etext
+p_bss_start:   .llong  __bss_start
+p_end:         .llong  _end
+
+p_toc:         .llong  __toc_start + 0x8000 - p_base
+p_dyn:         .llong  __dynamic_start - p_base
+p_rela:                .llong  __rela_dyn_start - p_base
+p_prom:                .llong  0
+       .weak   _platform_stack_top
+p_pstack:      .llong  _platform_stack_top
+#else
 p_start:       .long   _start
 p_etext:       .long   _etext
 p_bss_start:   .long   __bss_start
@@ -28,6 +45,7 @@ p_end:                .long   _end
 
        .weak   _platform_stack_top
 p_pstack:      .long   _platform_stack_top
+#endif
 
        .weak   _zimage_start
        .globl  _zimage_start
@@ -38,6 +56,7 @@ _zimage_start_lib:
           and the address where we're running. */
        bl      .+4
 p_base:        mflr    r10             /* r10 now points to runtime addr of p_base */
+#ifndef __powerpc64__
        /* grab the link address of the dynamic section in r11 */
        addis   r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
        lwz     r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
@@ -51,8 +70,6 @@ p_base:       mflr    r10             /* r10 now points to runtime addr of p_base */
 
        /* The dynamic section contains a series of tagged entries.
         * We need the RELA and RELACOUNT entries. */
-RELA = 7
-RELACOUNT = 0x6ffffff9
        li      r9,0
        li      r0,0
 9:     lwz     r8,0(r12)       /* get tag */
@@ -120,9 +137,164 @@ RELACOUNT = 0x6ffffff9
        li      r0,0
        stwu    r0,-16(r1)      /* establish a stack frame */
 6:
+#else /* __powerpc64__ */
+       /* Save the prom pointer at p_prom. */
+       std     r5,(p_prom-p_base)(r10)
+
+       /* Set r2 to the TOC. */
+       ld      r2,(p_toc-p_base)(r10)
+       add     r2,r2,r10
+
+       /* Grab the link address of the dynamic section in r11. */
+       ld      r11,-32768(r2)
+       cmpwi   r11,0
+       beq     3f              /* if not linked -pie then no dynamic section */
+
+       ld      r11,(p_dyn-p_base)(r10)
+       add     r11,r11,r10
+       ld      r9,(p_rela-p_base)(r10)
+       add     r9,r9,r10
 
+       li      r7,0
+       li      r8,0
+9:     ld      r6,0(r11)       /* get tag */
+       cmpdi   r6,0
+       beq     12f              /* end of list */
+       cmpdi   r6,RELA
+       bne     10f
+       ld      r7,8(r11)       /* get RELA pointer in r7 */
+       b       11f
+10:    addis   r6,r6,(-RELACOUNT)@ha
+       cmpdi   r6,RELACOUNT@l
+       bne     11f
+       ld      r8,8(r11)       /* get RELACOUNT value in r8 */
+11:    addi    r11,r11,16
+       b       9b
+12:
+       cmpdi   r7,0            /* check we have both RELA and RELACOUNT */
+       cmpdi   cr1,r8,0
+       beq     3f
+       beq     cr1,3f
+
+       /* Calcuate the runtime offset. */
+       subf    r7,r7,r9
+
+       /* Run through the list of relocations and process the
+        * R_PPC64_RELATIVE ones. */
+       mtctr   r8
+13:    ld      r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
+       cmpdi   r0,22           /* R_PPC64_RELATIVE */
+       bne     3f
+       ld      r6,0(r9)        /* reloc->r_offset */
+       ld      r0,16(r9)       /* reloc->r_addend */
+       add     r0,r0,r7
+       stdx    r0,r7,r6
+       addi    r9,r9,24
+       bdnz    13b
+
+       /* Do a cache flush for our text, in case the loader didn't */
+3:     ld      r9,p_start-p_base(r10)  /* note: these are relocated now */
+       ld      r8,p_etext-p_base(r10)
+4:     dcbf    r0,r9
+       icbi    r0,r9
+       addi    r9,r9,0x20
+       cmpld   cr0,r9,r8
+       blt     4b
+       sync
+       isync
+
+       /* Clear the BSS */
+       ld      r9,p_bss_start-p_base(r10)
+       ld      r8,p_end-p_base(r10)
+       li      r0,0
+5:     std     r0,0(r9)
+       addi    r9,r9,8
+       cmpld   cr0,r9,r8
+       blt     5b
+
+       /* Possibly set up a custom stack */
+       ld      r8,p_pstack-p_base(r10)
+       cmpdi   r8,0
+       beq     6f
+       ld      r1,0(r8)
+       li      r0,0
+       stdu    r0,-16(r1)      /* establish a stack frame */
+6:
+#endif  /* __powerpc64__ */
        /* Call platform_init() */
        bl      platform_init
 
        /* Call start */
        b       start
+
+#ifdef __powerpc64__
+
+#define PROM_FRAME_SIZE 512
+#define SAVE_GPR(n, base)       std     n,8*(n)(base)
+#define REST_GPR(n, base)       ld      n,8*(n)(base)
+#define SAVE_2GPRS(n, base)     SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)     SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)     SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)    SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_2GPRS(n, base)     REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)     REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)     REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)    REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+/* prom handles the jump into and return from firmware.  The prom args pointer
+   is loaded in r3. */
+.globl prom
+prom:
+       mflr    r0
+       std     r0,16(r1)
+       stdu    r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
+
+       SAVE_GPR(2, r1)
+       SAVE_GPR(13, r1)
+       SAVE_8GPRS(14, r1)
+       SAVE_10GPRS(22, r1)
+       mfcr    r10
+       std     r10,8*32(r1)
+       mfmsr   r10
+       std     r10,8*33(r1)
+
+       /* remove MSR_LE from msr but keep MSR_SF */
+       mfmsr   r10
+       rldicr  r10,r10,0,62
+       mtsrr1  r10
+
+       /* Load FW address, set LR to label 1, and jump to FW */
+       bl      0f
+0:     mflr    r10
+       addi    r11,r10,(1f-0b)
+       mtlr    r11
+
+       ld      r10,(p_prom-0b)(r10)
+       mtsrr0  r10
+
+       rfid
+
+1:     /* Return from OF */
+       FIXUP_ENDIAN
+
+       /* Restore registers and return. */
+       rldicl  r1,r1,0,32
+
+       /* Restore the MSR (back to 64 bits) */
+       ld      r10,8*(33)(r1)
+       mtmsr   r10
+       isync
+
+       /* Restore other registers */
+       REST_GPR(2, r1)
+       REST_GPR(13, r1)
+       REST_8GPRS(14, r1)
+       REST_10GPRS(22, r1)
+       ld      r10,8*32(r1)
+       mtcr    r10
+
+       addi    r1,r1,PROM_FRAME_SIZE
+       ld      r0,16(r1)
+       mtlr    r0
+       blr
+#endif
index cc73f7a95e26c488b5afabc1b6691d9f7456920a..bf8f4ede192851249bbc6b1a2b0114072ead5d3f 100644 (file)
                asm volatile("mfdcrx %0,%1" : "=r"(rval) : "r"(rn)); \
                rval; \
        })
+#define mtdcrx(rn, val) \
+       ({      \
+               asm volatile("mtdcrx %0,%1" : : "r"(rn), "r" (val)); \
+       })
 
 /* 440GP/440GX SDRAM controller DCRs */
 #define DCRN_SDRAM0_CFGADDR                            0x010
diff --git a/arch/powerpc/boot/dts/akebono.dts b/arch/powerpc/boot/dts/akebono.dts
new file mode 100644 (file)
index 0000000..f92ecfe
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Device Tree Source for IBM Embedded PPC 476 Platform
+ *
+ * Copyright Â© 2013 Tony Breeds IBM Corporation
+ * Copyright Â© 2013 Alistair Popple IBM Corporation
+ *
+ * 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/;
+
+/memreserve/ 0x01f00000 0x00100000;    // spin table
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+       model = "ibm,akebono";
+       compatible = "ibm,akebono", "ibm,476gtr";
+       dcr-parent = <&{/cpus/cpu@0}>;
+
+       aliases {
+               serial0 = &UART0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,476";
+                       reg = <0>;
+                       clock-frequency = <1600000000>; // 1.6 GHz
+                       timebase-frequency = <100000000>; // 100Mhz
+                       i-cache-line-size = <32>;
+                       d-cache-line-size = <32>;
+                       i-cache-size = <32768>;
+                       d-cache-size = <32768>;
+                       dcr-controller;
+                       dcr-access-method = "native";
+                       status = "ok";
+               };
+               cpu@1 {
+                       device_type = "cpu";
+                       model = "PowerPC,476";
+                       reg = <1>;
+                       clock-frequency = <1600000000>; // 1.6 GHz
+                       timebase-frequency = <100000000>; // 100Mhz
+                       i-cache-line-size = <32>;
+                       d-cache-line-size = <32>;
+                       i-cache-size = <32768>;
+                       d-cache-size = <32768>;
+                       dcr-controller;
+                       dcr-access-method = "native";
+                       status = "disabled";
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0x01f00000>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x0>; // filled in by zImage
+       };
+
+       MPIC: interrupt-controller {
+               compatible = "chrp,open-pic";
+               interrupt-controller;
+               dcr-reg = <0xffc00000 0x00040000>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               single-cpu-affinity;
+       };
+
+       plb {
+               compatible = "ibm,plb6";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               clock-frequency = <200000000>; // 200Mhz
+
+               HSTA0: hsta@310000e0000 {
+                       compatible = "ibm,476gtr-hsta-msi", "ibm,hsta-msi";
+                       reg = <0x310 0x000e0000 0x0 0xf0>;
+                       interrupt-parent = <&MPIC>;
+                       interrupts = <108 0
+                                     109 0
+                                     110 0
+                                     111 0
+                                     112 0
+                                     113 0
+                                     114 0
+                                     115 0
+                                     116 0
+                                     117 0
+                                     118 0
+                                     119 0
+                                     120 0
+                                     121 0
+                                     122 0
+                                     123 0>;
+               };
+
+               MAL0: mcmal {
+                       compatible = "ibm,mcmal-476gtr", "ibm,mcmal2";
+                       dcr-reg = <0xc0000000 0x062>;
+                       num-tx-chans = <1>;
+                       num-rx-chans = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&MPIC>;
+                       interrupts = <  /*TXEOB*/ 77 0x4
+                                       /*RXEOB*/ 78 0x4
+                                       /*SERR*/  76 0x4
+                                       /*TXDE*/  79 0x4
+                                       /*RXDE*/  80 0x4>;
+               };
+
+               SATA0: sata@30000010000 {
+                       compatible = "ibm,476gtr-ahci";
+                       reg = <0x300 0x00010000 0x0 0x10000>;
+                       interrupt-parent = <&MPIC>;
+                       interrupts = <93 2>;
+               };
+
+               EHCI0: ehci@30010000000 {
+                       compatible = "ibm,476gtr-ehci", "generic-ehci";
+                       reg = <0x300 0x10000000 0x0 0x10000>;
+                       interrupt-parent = <&MPIC>;
+                       interrupts = <85 2>;
+               };
+
+               SD0: sd@30000000000 {
+                       compatible = "ibm,476gtr-sdhci", "generic-sdhci";
+                       reg = <0x300 0x00000000 0x0 0x10000>;
+                       interrupts = <91 2>;
+                       interrupt-parent = <&MPIC>;
+               };
+
+               OHCI0: ohci@30010010000 {
+                       compatible = "ibm,476gtr-ohci", "generic-ohci";
+                       reg = <0x300 0x10010000 0x0 0x10000>;
+                       interrupt-parent = <&MPIC>;
+                       interrupts = <89 1>;
+                       };
+
+               OHCI1: ohci@30010020000 {
+                       compatible = "ibm,476gtr-ohci", "generic-ohci";
+                       reg = <0x300 0x10020000 0x0 0x10000>;
+                       interrupt-parent = <&MPIC>;
+                       interrupts = <88 1>;
+                       };
+
+               POB0: opb {
+                       compatible = "ibm,opb-4xx", "ibm,opb";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       /* Wish there was a nicer way of specifying a full
+                        * 32-bit range
+                        */
+                       ranges = <0x00000000 0x0000033f 0x00000000 0x80000000
+                                 0x80000000 0x0000033f 0x80000000 0x80000000>;
+                       clock-frequency = <100000000>;
+
+                       RGMII0: emac-rgmii-wol@50004 {
+                               compatible = "ibm,rgmii-wol-476gtr", "ibm,rgmii-wol";
+                               reg = <0x50004 0x00000008>;
+                               has-mdio;
+                       };
+
+                       EMAC0: ethernet@30000 {
+                               device_type = "network";
+                               compatible = "ibm,emac-476gtr", "ibm,emac4sync";
+                               interrupt-parent = <&EMAC0>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &MPIC 81 0x4
+                                                /*Wake*/   0x1 &MPIC 82 0x4>;
+                               reg = <0x30000 0x78>;
+
+                               /* local-mac-address will normally be added by
+                                * the wrapper. If your device doesn't support
+                                * passing data to the wrapper (in the form
+                                * local-mac-addr=<hwaddr>) then you will need
+                                * to set it manually here. */
+                               //local-mac-address = [000000000000];
+
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <0>;
+                               mal-rx-channel = <0>;
+                               cell-index = <0>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               rx-fifo-size-gige = <16384>;
+                               phy-mode = "rgmii";
+                               phy-map = <0x00000000>;
+                               rgmii-wol-device = <&RGMII0>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                       };
+
+                       UART0: serial@10000 {
+                               device_type = "serial";
+                               compatible = "ns16750", "ns16550";
+                               reg = <0x10000 0x00000008>;
+                               virtual-reg = <0xe8010000>;
+                               clock-frequency = <1851851>;
+                               current-speed = <38400>;
+                               interrupt-parent = <&MPIC>;
+                               interrupts = <39 2>;
+                       };
+
+                       IIC0: i2c@00000000 {
+                               compatible = "ibm,iic-476gtr", "ibm,iic";
+                               reg = <0x0 0x00000020>;
+                               interrupt-parent = <&MPIC>;
+                               interrupts = <37 2>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               rtc@68 {
+                                       compatible = "stm,m41t80", "m41st85";
+                                       reg = <0x68>;
+                               };
+                       };
+
+                       IIC1: i2c@00000100 {
+                               compatible = "ibm,iic-476gtr", "ibm,iic";
+                               reg = <0x100 0x00000020>;
+                               interrupt-parent = <&MPIC>;
+                               interrupts = <38 2>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               avr@58 {
+                                       compatible = "ibm,akebono-avr";
+                                       reg = <0x58>;
+                               };
+                       };
+
+                       FPGA0: fpga@ebc00000 {
+                               compatible = "ibm,akebono-fpga";
+                               reg = <0xebc00000 0x8>;
+                       };
+               };
+
+               PCIE0: pciex@10100000000 {
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+                       primary;
+                       port = <0x0>; /* port number */
+                       reg = <0x00000101 0x00000000 0x0 0x10000000            /* Config space access */
+                              0x00000100 0x00000000 0x0 0x00001000>;   /* UTL Registers space access */
+                       dcr-reg = <0xc0 0x20>;
+
+//                                pci_space  < pci_addr          > < cpu_addr          > < size       >
+                       ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
+                                 0x01000000 0x0        0x0        0x00000140 0x0        0x0 0x00010000>;
+
+                       /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+                        * PCI devices must be able to write to the HSTA module.
+                        */
+                       dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
+
+                       /* This drives busses 0 to 0xf */
+                       bus-range = <0x0 0xf>;
+
+                       /* Legacy interrupts (note the weird polarity, the bridge seems
+                        * to invert PCIe legacy interrupts).
+                        * We are de-swizzling here because the numbers are actually for
+                        * port of the root complex virtual P2P bridge. But I want
+                        * to avoid putting a node for it in the tree, so the numbers
+                        * below are basically de-swizzled numbers.
+                        * The real slot is on idsel 0, so the swizzling is 1:1
+                        */
+                       interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+                       interrupt-map = <
+                               0x0 0x0 0x0 0x1 &MPIC 45 0x2 /* int A */
+                               0x0 0x0 0x0 0x2 &MPIC 46 0x2 /* int B */
+                               0x0 0x0 0x0 0x3 &MPIC 47 0x2 /* int C */
+                               0x0 0x0 0x0 0x4 &MPIC 48 0x2 /* int D */>;
+               };
+
+               PCIE1: pciex@20100000000 {
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+                       primary;
+                       port = <0x1>; /* port number */
+                       reg = <0x00000201 0x00000000 0x0 0x10000000            /* Config space access */
+                              0x00000200 0x00000000 0x0 0x00001000>;   /* UTL Registers space access */
+                       dcr-reg = <0x100 0x20>;
+
+//                                pci_space  < pci_addr          > < cpu_addr          > < size       >
+                       ranges = <0x02000000 0x00000000 0x80000000 0x00000210 0x80000000 0x0 0x80000000
+                                 0x01000000 0x0        0x0        0x00000240 0x0        0x0 0x00010000>;
+
+                       /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+                        * PCI devices must be able to write to the HSTA module.
+                        */
+                       dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
+
+                       /* This drives busses 0 to 0xf */
+                       bus-range = <0x0 0xf>;
+
+                       /* Legacy interrupts (note the weird polarity, the bridge seems
+                        * to invert PCIe legacy interrupts).
+                        * We are de-swizzling here because the numbers are actually for
+                        * port of the root complex virtual P2P bridge. But I want
+                        * to avoid putting a node for it in the tree, so the numbers
+                        * below are basically de-swizzled numbers.
+                        * The real slot is on idsel 0, so the swizzling is 1:1
+                        */
+                       interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+                       interrupt-map = <
+                               0x0 0x0 0x0 0x1 &MPIC 53 0x2 /* int A */
+                               0x0 0x0 0x0 0x2 &MPIC 54 0x2 /* int B */
+                               0x0 0x0 0x0 0x3 &MPIC 55 0x2 /* int C */
+                               0x0 0x0 0x0 0x4 &MPIC 56 0x2 /* int D */>;
+               };
+
+               PCIE2: pciex@18100000000 {
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+                       primary;
+                       port = <0x2>; /* port number */
+                       reg = <0x00000181 0x00000000 0x0 0x10000000            /* Config space access */
+                              0x00000180 0x00000000 0x0 0x00001000>;   /* UTL Registers space access */
+                       dcr-reg = <0xe0 0x20>;
+
+//                                pci_space  < pci_addr          > < cpu_addr          > < size       >
+                       ranges = <0x02000000 0x00000000 0x80000000 0x00000190 0x80000000 0x0 0x80000000
+                                 0x01000000 0x0        0x0        0x000001c0 0x0        0x0 0x00010000>;
+
+                       /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+                        * PCI devices must be able to write to the HSTA module.
+                        */
+                       dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
+
+                       /* This drives busses 0 to 0xf */
+                       bus-range = <0x0 0xf>;
+
+                       /* Legacy interrupts (note the weird polarity, the bridge seems
+                        * to invert PCIe legacy interrupts).
+                        * We are de-swizzling here because the numbers are actually for
+                        * port of the root complex virtual P2P bridge. But I want
+                        * to avoid putting a node for it in the tree, so the numbers
+                        * below are basically de-swizzled numbers.
+                        * The real slot is on idsel 0, so the swizzling is 1:1
+                        */
+                       interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+                       interrupt-map = <
+                               0x0 0x0 0x0 0x1 &MPIC 61 0x2 /* int A */
+                               0x0 0x0 0x0 0x2 &MPIC 62 0x2 /* int B */
+                               0x0 0x0 0x0 0x3 &MPIC 63 0x2 /* int C */
+                               0x0 0x0 0x0 0x4 &MPIC 64 0x2 /* int D */>;
+               };
+
+               PCIE3: pciex@28100000000 {
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+                       primary;
+                       port = <0x3>; /* port number */
+                       reg = <0x00000281 0x00000000 0x0 0x10000000            /* Config space access */
+                              0x00000280 0x00000000 0x0 0x00001000>;   /* UTL Registers space access */
+                       dcr-reg = <0x120 0x20>;
+
+//                                pci_space  < pci_addr          > < cpu_addr          > < size       >
+                       ranges = <0x02000000 0x00000000 0x80000000 0x00000290 0x80000000 0x0 0x80000000
+                                 0x01000000 0x0        0x0        0x000002c0 0x0        0x0 0x00010000>;
+
+                       /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+                        * PCI devices must be able to write to the HSTA module.
+                        */
+                       dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
+
+                       /* This drives busses 0 to 0xf */
+                       bus-range = <0x0 0xf>;
+
+                       /* Legacy interrupts (note the weird polarity, the bridge seems
+                        * to invert PCIe legacy interrupts).
+                        * We are de-swizzling here because the numbers are actually for
+                        * port of the root complex virtual P2P bridge. But I want
+                        * to avoid putting a node for it in the tree, so the numbers
+                        * below are basically de-swizzled numbers.
+                        * The real slot is on idsel 0, so the swizzling is 1:1
+                        */
+                       interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+                       interrupt-map = <
+                               0x0 0x0 0x0 0x1 &MPIC 69 0x2 /* int A */
+                               0x0 0x0 0x0 0x2 &MPIC 70 0x2 /* int B */
+                               0x0 0x0 0x0 0x3 &MPIC 71 0x2 /* int C */
+                               0x0 0x0 0x0 0x4 &MPIC 72 0x2 /* int D */>;
+               };
+       };
+
+       chosen {
+               linux,stdout-path = &UART0;
+       };
+};
index 651e4f55acdbf6f6187b1792315c780f127effde..57f86cdf9f36e4fcde7f844731bfa3047be45d0a 100644 (file)
                };
 
                dma@2c000 {
-                       compatible = "fsl,mpc8308-dma", "fsl,mpc5121-dma";
+                       compatible = "fsl,mpc8308-dma";
                        reg = <0x2c000 0x1800>;
                        interrupts = <3 0x8
                                        94 0x8>;
index 9ce45f2efd34907014d8b228823cb0d6d3254ead..d0211f0413c6469d71cd6feda3d59b5630e174a8 100644 (file)
                };
 
                dma@2c000 {
-                       compatible = "fsl,mpc8308-dma", "fsl,mpc5121-dma";
+                       compatible = "fsl,mpc8308-dma";
                        reg = <0x2c000 0x1800>;
                        interrupts = <3 0x8
                                        94 0x8>;
index 1567a0c0f05c6639a96ce4947dfb9bdf23eda8fc..316552dea4d8c20e5b279ecde40f8d1e81ffee37 100644 (file)
@@ -26,7 +26,11 @@ int parse_elf64(void *hdr, struct elf_info *info)
              elf64->e_ident[EI_MAG2]  == ELFMAG2       &&
              elf64->e_ident[EI_MAG3]  == ELFMAG3       &&
              elf64->e_ident[EI_CLASS] == ELFCLASS64    &&
+#ifdef __LITTLE_ENDIAN__
+             elf64->e_ident[EI_DATA]  == ELFDATA2LSB   &&
+#else
              elf64->e_ident[EI_DATA]  == ELFDATA2MSB   &&
+#endif
              (elf64->e_type            == ET_EXEC ||
               elf64->e_type            == ET_DYN)      &&
              elf64->e_machine         == EM_PPC64))
index a28f02165e97032c8eda569e97b06a4dc81fb0f9..d367a0aece2aac8b067a6c7bf51c43ef3d488eda 100644 (file)
@@ -139,18 +139,18 @@ static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
  * edit the command line passed to vmlinux (by setting /chosen/bootargs).
  * The buffer is put in it's own section so that tools may locate it easier.
  */
-static char cmdline[COMMAND_LINE_SIZE]
+static char cmdline[BOOT_COMMAND_LINE_SIZE]
        __attribute__((__section__("__builtin_cmdline")));
 
 static void prep_cmdline(void *chosen)
 {
        if (cmdline[0] == '\0')
-               getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
+               getprop(chosen, "bootargs", cmdline, BOOT_COMMAND_LINE_SIZE-1);
 
        printf("\n\rLinux/PowerPC load: %s", cmdline);
        /* If possible, edit the command line */
        if (console_ops.edit_cmdline)
-               console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
+               console_ops.edit_cmdline(cmdline, BOOT_COMMAND_LINE_SIZE);
        printf("\n\r");
 
        /* Put the command line back into the devtree for the kernel */
@@ -174,7 +174,7 @@ void start(void)
         * built-in command line wasn't set by an external tool */
        if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
                memmove(cmdline, loader_info.cmdline,
-                       min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
+                       min(loader_info.cmdline_len, BOOT_COMMAND_LINE_SIZE-1));
 
        if (console_ops.open && (console_ops.open() < 0))
                exit();
index 62e2f43ec1df1144d3a790e1f3cf3e3263fdca47..7ca910cb2fc64f0ad8fa85ed2f5b056495773324 100644 (file)
@@ -40,8 +40,8 @@ static void *of_try_claim(unsigned long size)
 #ifdef DEBUG
                printf("    trying: 0x%08lx\n\r", claim_base);
 #endif
-               addr = (unsigned long)of_claim(claim_base, size, 0);
-               if ((void *)addr != (void *)-1)
+               addr = (unsigned long) of_claim(claim_base, size, 0);
+               if (addr != PROM_ERROR)
                        break;
        }
        if (addr == 0)
index e4c68f7391c5c430613087054c45de516fe1cc6a..c8c1750aba0cc23aed26298785f53d4fd3676fee 100644 (file)
@@ -1,12 +1,15 @@
 #ifndef _PPC_BOOT_OF_H_
 #define _PPC_BOOT_OF_H_
 
+#include "swab.h"
+
 typedef void *phandle;
-typedef void *ihandle;
+typedef u32 ihandle;
 
 void of_init(void *promptr);
 int of_call_prom(const char *service, int nargs, int nret, ...);
-void *of_claim(unsigned long virt, unsigned long size, unsigned long align);
+unsigned int of_claim(unsigned long virt, unsigned long size,
+       unsigned long align);
 void *of_vmlinux_alloc(unsigned long size);
 void of_exit(void);
 void *of_finddevice(const char *name);
@@ -18,4 +21,16 @@ int of_setprop(const void *phandle, const char *name, const void *buf,
 /* Console functions */
 void of_console_init(void);
 
+typedef u32                    __be32;
+
+#ifdef __LITTLE_ENDIAN__
+#define cpu_to_be32(x) swab32(x)
+#define be32_to_cpu(x) swab32(x)
+#else
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#endif
+
+#define PROM_ERROR (-1u)
+
 #endif /* _PPC_BOOT_OF_H_ */
index ce0e0242445325feb7251ae9214705e90c42864a..8b754702460aee3e51eabd016d71c888abd4a719 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "of.h"
 
-static void *of_stdout_handle;
+static unsigned int of_stdout_handle;
 
 static int of_console_open(void)
 {
@@ -27,8 +27,10 @@ static int of_console_open(void)
        if (((devp = of_finddevice("/chosen")) != NULL)
            && (of_getprop(devp, "stdout", &of_stdout_handle,
                           sizeof(of_stdout_handle))
-               == sizeof(of_stdout_handle)))
+               == sizeof(of_stdout_handle))) {
+               of_stdout_handle = be32_to_cpu(of_stdout_handle);
                return 0;
+       }
 
        return -1;
 }
index b0ec9cf3eaaf6e6bf44f9a77aeb079761a2d628c..46c98a47d9493a7ae54940070cb7ceb0cc716a59 100644 (file)
 
 #include "of.h"
 
+typedef u32 prom_arg_t;
+
+/* The following structure is used to communicate with open firmware.
+ * All arguments in and out are in big endian format. */
+struct prom_args {
+       __be32 service; /* Address of service name string. */
+       __be32 nargs;   /* Number of input arguments. */
+       __be32 nret;    /* Number of output arguments. */
+       __be32 args[10];        /* Input/output arguments. */
+};
+
+#ifdef __powerpc64__
+extern int prom(void *);
+#else
 static int (*prom) (void *);
+#endif
 
 void of_init(void *promptr)
 {
+#ifndef __powerpc64__
        prom = (int (*)(void *))promptr;
+#endif
 }
 
+#define ADDR(x)                (u32)(unsigned long)(x)
+
 int of_call_prom(const char *service, int nargs, int nret, ...)
 {
        int i;
-       struct prom_args {
-               const char *service;
-               int nargs;
-               int nret;
-               unsigned int args[12];
-       } args;
+       struct prom_args args;
        va_list list;
 
-       args.service = service;
-       args.nargs = nargs;
-       args.nret = nret;
+       args.service = cpu_to_be32(ADDR(service));
+       args.nargs = cpu_to_be32(nargs);
+       args.nret = cpu_to_be32(nret);
 
        va_start(list, nret);
        for (i = 0; i < nargs; i++)
-               args.args[i] = va_arg(list, unsigned int);
+               args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
        va_end(list);
 
        for (i = 0; i < nret; i++)
                args.args[nargs+i] = 0;
 
        if (prom(&args) < 0)
-               return -1;
+               return PROM_ERROR;
 
-       return (nret > 0)? args.args[nargs]: 0;
+       return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
 }
 
 static int of_call_prom_ret(const char *service, int nargs, int nret,
-                           unsigned int *rets, ...)
+                           prom_arg_t *rets, ...)
 {
        int i;
-       struct prom_args {
-               const char *service;
-               int nargs;
-               int nret;
-               unsigned int args[12];
-       } args;
+       struct prom_args args;
        va_list list;
 
-       args.service = service;
-       args.nargs = nargs;
-       args.nret = nret;
+       args.service = cpu_to_be32(ADDR(service));
+       args.nargs = cpu_to_be32(nargs);
+       args.nret = cpu_to_be32(nret);
 
        va_start(list, rets);
        for (i = 0; i < nargs; i++)
-               args.args[i] = va_arg(list, unsigned int);
+               args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
        va_end(list);
 
        for (i = 0; i < nret; i++)
                args.args[nargs+i] = 0;
 
        if (prom(&args) < 0)
-               return -1;
+               return PROM_ERROR;
 
-       if (rets != (void *) 0)
+       if (rets != NULL)
                for (i = 1; i < nret; ++i)
-                       rets[i-1] = args.args[nargs+i];
+                       rets[i-1] = be32_to_cpu(args.args[nargs+i]);
 
-       return (nret > 0)? args.args[nargs]: 0;
+       return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
 }
 
 /* returns true if s2 is a prefix of s1 */
@@ -103,7 +112,7 @@ static int string_match(const char *s1, const char *s2)
  */
 static int need_map = -1;
 static ihandle chosen_mmu;
-static phandle memory;
+static ihandle memory;
 
 static int check_of_version(void)
 {
@@ -132,10 +141,10 @@ static int check_of_version(void)
                printf("no mmu\n");
                return 0;
        }
-       memory = (ihandle) of_call_prom("open", 1, 1, "/memory");
-       if (memory == (ihandle) -1) {
-               memory = (ihandle) of_call_prom("open", 1, 1, "/memory@0");
-               if (memory == (ihandle) -1) {
+       memory = of_call_prom("open", 1, 1, "/memory");
+       if (memory == PROM_ERROR) {
+               memory = of_call_prom("open", 1, 1, "/memory@0");
+               if (memory == PROM_ERROR) {
                        printf("no memory node\n");
                        return 0;
                }
@@ -144,40 +153,41 @@ static int check_of_version(void)
        return 1;
 }
 
-void *of_claim(unsigned long virt, unsigned long size, unsigned long align)
+unsigned int of_claim(unsigned long virt, unsigned long size,
+                     unsigned long align)
 {
        int ret;
-       unsigned int result;
+       prom_arg_t result;
 
        if (need_map < 0)
                need_map = check_of_version();
        if (align || !need_map)
-               return (void *) of_call_prom("claim", 3, 1, virt, size, align);
+               return of_call_prom("claim", 3, 1, virt, size, align);
 
        ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory,
                               align, size, virt);
        if (ret != 0 || result == -1)
-               return (void *) -1;
+               return  -1;
        ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
                               align, size, virt);
        /* 0x12 == coherent + read/write */
        ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu,
                           0x12, size, virt, virt);
-       return (void *) virt;
+       return virt;
 }
 
 void *of_vmlinux_alloc(unsigned long size)
 {
        unsigned long start = (unsigned long)_start, end = (unsigned long)_end;
-       void *addr;
+       unsigned long addr;
        void *p;
 
        /* With some older POWER4 firmware we need to claim the area the kernel
         * will reside in.  Newer firmwares don't need this so we just ignore
         * the return value.
         */
-       addr = of_claim(start, end - start, 0);
-       printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %p\r\n",
+       addr = (unsigned long) of_claim(start, end - start, 0);
+       printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %lx\r\n",
               start, end, end - start, addr);
 
        p = malloc(size);
@@ -197,7 +207,7 @@ void of_exit(void)
  */
 void *of_finddevice(const char *name)
 {
-       return (phandle) of_call_prom("finddevice", 1, 1, name);
+       return (void *) (unsigned long) of_call_prom("finddevice", 1, 1, name);
 }
 
 int of_getprop(const void *phandle, const char *name, void *buf,
index b3218ce451bb9be8081dd77cc75f0a3114468be1..8aad3c55aeda2885e331b8c7ebd52436c219e74b 100644 (file)
@@ -15,7 +15,7 @@
 #include "types.h"
 #include "string.h"
 
-#define        COMMAND_LINE_SIZE       512
+#define        BOOT_COMMAND_LINE_SIZE  2048
 #define        MAX_PATH_LEN            256
 #define        MAX_PROP_LEN            256 /* What should this be? */
 
index eb0e98be69e0bc8c7aece45746f20c6fcd03ff23..35ea60c1f07020e1ce4c68e587ca8cafbc723d89 100644 (file)
 #define SPRN_TBRL      268
 #define SPRN_TBRU      269
 
+#define FIXUP_ENDIAN                                              \
+       tdi   0, 0, 0x48; /* Reverse endian of b . + 8          */ \
+       b     $+36;       /* Skip trampoline if endian is good  */ \
+       .long 0x05009f42; /* bcl 20,31,$+4                      */ \
+       .long 0xa602487d; /* mflr r10                           */ \
+       .long 0x1c004a39; /* addi r10,r10,28                    */ \
+       .long 0xa600607d; /* mfmsr r11                          */ \
+       .long 0x01006b69; /* xori r11,r11,1                     */ \
+       .long 0xa6035a7d; /* mtsrr0 r10                         */ \
+       .long 0xa6037b7d; /* mtsrr1 r11                         */ \
+       .long 0x2400004c  /* rfid                               */
+
 #endif /* _PPC64_PPC_ASM_H */
index 9954d98871d061dfc9abb8c33fefcbbe00d8d2ea..4ec2d86d3c50571a2a62f27c31f00739595ed219 100644 (file)
@@ -47,13 +47,13 @@ BSS_STACK(4096);
  * The buffer is put in it's own section so that tools may locate it easier.
  */
 
-static char cmdline[COMMAND_LINE_SIZE]
+static char cmdline[BOOT_COMMAND_LINE_SIZE]
        __attribute__((__section__("__builtin_cmdline")));
 
 static void prep_cmdline(void *chosen)
 {
        if (cmdline[0] == '\0')
-               getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
+               getprop(chosen, "bootargs", cmdline, BOOT_COMMAND_LINE_SIZE-1);
        else
                setprop_str(chosen, "bootargs", cmdline);
 
diff --git a/arch/powerpc/boot/pseries-head.S b/arch/powerpc/boot/pseries-head.S
new file mode 100644 (file)
index 0000000..6ef6e02
--- /dev/null
@@ -0,0 +1,8 @@
+#include "ppc_asm.h"
+
+       .text
+
+       .globl _zimage_start
+_zimage_start:
+       FIXUP_ENDIAN
+       b _zimage_start_lib
index 5b57800bbc675e11efabec8601a8b9000ce4c196..a701261b17818118f824221e81a7177d09f004b4 100644 (file)
@@ -21,6 +21,18 @@ size_t strnlen(const char * s, size_t count)
        return sc - s;
 }
 
+#ifdef __powerpc64__
+
+# define do_div(n, base) ({                                            \
+       unsigned int __base = (base);                                   \
+       unsigned int __rem;                                             \
+       __rem = ((unsigned long long)(n)) % __base;                     \
+       (n) = ((unsigned long long)(n)) / __base;                       \
+       __rem;                                                          \
+})
+
+#else
+
 extern unsigned int __div64_32(unsigned long long *dividend,
                               unsigned int divisor);
 
@@ -39,6 +51,8 @@ extern unsigned int __div64_32(unsigned long long *dividend,
        __rem;                                                          \
  })
 
+#endif /* __powerpc64__ */
+
 static int skip_atoi(const char **s)
 {
        int i, c;
diff --git a/arch/powerpc/boot/swab.h b/arch/powerpc/boot/swab.h
new file mode 100644 (file)
index 0000000..d0e1431
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _PPC_BOOT_SWAB_H_
+#define _PPC_BOOT_SWAB_H_
+
+static inline u16 swab16(u16 x)
+{
+       return  ((x & (u16)0x00ffU) << 8) |
+               ((x & (u16)0xff00U) >> 8);
+}
+
+static inline u32 swab32(u32 x)
+{
+       return  ((x & (u32)0x000000ffUL) << 24) |
+               ((x & (u32)0x0000ff00UL) <<  8) |
+               ((x & (u32)0x00ff0000UL) >>  8) |
+               ((x & (u32)0xff000000UL) >> 24);
+}
+
+static inline u64 swab64(u64 x)
+{
+       return  (u64)((x & (u64)0x00000000000000ffULL) << 56) |
+               (u64)((x & (u64)0x000000000000ff00ULL) << 40) |
+               (u64)((x & (u64)0x0000000000ff0000ULL) << 24) |
+               (u64)((x & (u64)0x00000000ff000000ULL) <<  8) |
+               (u64)((x & (u64)0x000000ff00000000ULL) >>  8) |
+               (u64)((x & (u64)0x0000ff0000000000ULL) >> 24) |
+               (u64)((x & (u64)0x00ff000000000000ULL) >> 40) |
+               (u64)((x & (u64)0xff00000000000000ULL) >> 56);
+}
+#endif /* _PPC_BOOT_SWAB_H_ */
diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c
new file mode 100644 (file)
index 0000000..b73174c
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright Â© 2013 Tony Breeds IBM Corporation
+ * Copyright Â© 2013 Alistair Popple IBM Corporation
+ *
+ * Based on earlier code:
+ *   Copyright (C) Paul Mackerras 1997.
+ *
+ *   Matt Porter <mporter@kernel.crashing.org>
+ *   Copyright 2002-2005 MontaVista Software Inc.
+ *
+ *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *   Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ *    Copyright 2007 David Gibson, IBM Corporation.
+ *    Copyright 2010 Ben. Herrenschmidt, IBM Corporation.
+ *    Copyright Â© 2011 David Kleikamp IBM 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.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+#include "reg.h"
+#include "io.h"
+#include "dcr.h"
+#include "4xx.h"
+#include "44x.h"
+#include "libfdt.h"
+
+BSS_STACK(4096);
+
+#define SPRN_PIR       0x11E   /* Processor Indentification Register */
+#define USERDATA_LEN   256     /* Length of userdata passed in by PIBS */
+#define MAX_RANKS      0x4
+#define DDR3_MR0CF     0x80010011U
+#define CCTL0_MCO2     0x8000080FU
+#define CCTL0_MCO3     0x80000810U
+#define CCTL0_MCO4     0x80000811U
+#define CCTL0_MCO5     0x80000812U
+#define CCTL0_MCO6     0x80000813U
+
+static unsigned long long ibm_akebono_memsize;
+static long long unsigned mac_addr;
+
+static unsigned long long ibm_akebono_detect_memsize(void)
+{
+       u32 reg;
+       unsigned i;
+       unsigned long long memsize = 0;
+
+       for (i = 0; i < MAX_RANKS; i++) {
+               reg = mfdcrx(DDR3_MR0CF + i);
+
+               if (!(reg & 1))
+                       continue;
+
+               reg &= 0x0000f000;
+               reg >>= 12;
+               memsize += (0x800000ULL << reg);
+       }
+
+       return memsize;
+}
+
+static void ibm_akebono_fixups(void)
+{
+       void *emac;
+       u32 reg;
+
+       dt_fixup_memory(0x0ULL,  ibm_akebono_memsize);
+
+       /* Fixup the SD timeout frequency */
+       mtdcrx(CCTL0_MCO4, 0x1);
+
+       /* Disable SD high-speed mode (which seems to be broken) */
+       reg = mfdcrx(CCTL0_MCO2) & ~0x2;
+       mtdcrx(CCTL0_MCO2, reg);
+
+       /* Set the MAC address */
+       emac = finddevice("/plb/opb/ethernet");
+       if (emac > 0) {
+               if (mac_addr)
+                       setprop(emac, "local-mac-address",
+                               ((u8 *) &mac_addr) + 2 , 6);
+       }
+}
+
+void platform_init(char *userdata)
+{
+       unsigned long end_of_ram, avail_ram;
+       u32 pir_reg;
+       int node, size;
+       const u32 *timebase;
+       int len, i, userdata_len;
+       char *end;
+
+       userdata[USERDATA_LEN - 1] = '\0';
+       userdata_len = strlen(userdata);
+       for (i = 0; i < userdata_len - 15; i++) {
+               if (strncmp(&userdata[i], "local-mac-addr=", 15) == 0) {
+                       if (i > 0 && userdata[i - 1] != ' ') {
+                               /* We've only found a substring ending
+                                * with local-mac-addr so this isn't
+                                * our mac address. */
+                               continue;
+                       }
+
+                       mac_addr = strtoull(&userdata[i + 15], &end, 16);
+
+                       /* Remove the "local-mac-addr=<...>" from the kernel
+                        * command line, including the tailing space if
+                        * present. */
+                       if (*end == ' ')
+                               end++;
+
+                       len = ((int) end) - ((int) &userdata[i]);
+                       memmove(&userdata[i], end,
+                               userdata_len - (len + i) + 1);
+                       break;
+               }
+       }
+
+       loader_info.cmdline = userdata;
+       loader_info.cmdline_len = 256;
+
+       ibm_akebono_memsize = ibm_akebono_detect_memsize();
+       if (ibm_akebono_memsize >> 32)
+               end_of_ram = ~0UL;
+       else
+               end_of_ram = ibm_akebono_memsize;
+       avail_ram = end_of_ram - (unsigned long)_end;
+
+       simple_alloc_init(_end, avail_ram, 128, 64);
+       platform_ops.fixups = ibm_akebono_fixups;
+       platform_ops.exit = ibm44x_dbcr_reset;
+       pir_reg = mfspr(SPRN_PIR);
+
+       /* Make sure FDT blob is sane */
+       if (fdt_check_header(_dtb_start) != 0)
+               fatal("Invalid device tree blob\n");
+
+       node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
+                                            "cpu", sizeof("cpu"));
+       if (!node)
+               fatal("Cannot find cpu node\n");
+       timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
+       if (timebase && (size == 4))
+               timebase_period_ns = 1000000000 / *timebase;
+
+       fdt_set_boot_cpuid_phys(_dtb_start, pir_reg);
+       fdt_init(_dtb_start);
+
+       serial_console_init();
+}
index 6636b1d7821b6e5d5bcd8126674a8f3d8499601f..243b8497d58b847a2877523c45df04f2f1326b32 100644 (file)
@@ -45,7 +45,7 @@ udelay:
        mfspr   r4,SPRN_PVR
        srwi    r4,r4,16
        cmpwi   0,r4,1          /* 601 ? */
-       bne     .udelay_not_601
+       bne     .Ludelay_not_601
 00:    li      r0,86   /* Instructions / microsecond? */
        mtctr   r0
 10:    addi    r0,r0,0 /* NOP */
@@ -54,7 +54,7 @@ udelay:
        bne     00b
        blr
 
-.udelay_not_601:
+.Ludelay_not_601:
        mulli   r4,r3,1000      /* nanoseconds */
        /*  Change r4 to be the number of ticks using:
         *      (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
index d27a25518b018b03df07110919104ff6811e1b00..ae0f88ec4a3295e570c1032f6feb323aa5038473 100755 (executable)
@@ -40,6 +40,7 @@ cacheit=
 binary=
 gzip=.gz
 pie=
+format=
 
 # cross-compilation prefix
 CROSS=
@@ -136,6 +137,14 @@ if [ -z "$kernel" ]; then
     kernel=vmlinux
 fi
 
+elfformat="`${CROSS}objdump -p "$kernel" | grep 'file format' | awk '{print $4}'`"
+case "$elfformat" in
+    elf64-powerpcle)   format=elf64lppc        ;;
+    elf64-powerpc)     format=elf32ppc ;;
+    elf32-powerpc)     format=elf32ppc ;;
+esac
+
+
 platformo=$object/"$platform".o
 lds=$object/zImage.lds
 ext=strip
@@ -152,8 +161,12 @@ of)
     make_space=n
     ;;
 pseries)
-    platformo="$object/of.o $object/epapr.o"
+    platformo="$object/pseries-head.o $object/of.o $object/epapr.o"
     link_address='0x4000000'
+    if [ "$format" != "elf32ppc" ]; then
+       link_address=
+       pie=-pie
+    fi
     make_space=n
     ;;
 maple)
@@ -257,6 +270,9 @@ gamecube|wii)
 treeboot-currituck)
     link_address='0x1000000'
     ;;
+treeboot-akebono)
+    link_address='0x1000000'
+    ;;
 treeboot-iss4xx-mpic)
     platformo="$object/treeboot-iss4xx.o"
     ;;
@@ -379,7 +395,7 @@ if [ "$platform" != "miboot" ]; then
     if [ -n "$link_address" ] ; then
         text_start="-Ttext $link_address"
     fi
-    ${CROSS}ld -m elf32ppc -T $lds $text_start $pie -o "$ofile" \
+    ${CROSS}ld -m $format -T $lds $text_start $pie -o "$ofile" \
        $platformo $tmp $object/wrapper.a
     rm $tmp
 fi
index 2bd8731f13655a97550064a46f7f890c16b6c05f..861e72109df2da0b54c98a94584b8b4ff853026b 100644 (file)
@@ -1,4 +1,10 @@
+#include <asm-generic/vmlinux.lds.h>
+
+#ifdef CONFIG_PPC64_BOOT_WRAPPER
+OUTPUT_ARCH(powerpc:common64)
+#else
 OUTPUT_ARCH(powerpc:common)
+#endif
 ENTRY(_zimage_start)
 EXTERN(_zimage_start)
 SECTIONS
@@ -16,7 +22,9 @@ SECTIONS
     *(.rodata*)
     *(.data*)
     *(.sdata*)
+#ifndef CONFIG_PPC64_BOOT_WRAPPER
     *(.got2)
+#endif
   }
   .dynsym : { *(.dynsym) }
   .dynstr : { *(.dynstr) }
@@ -27,7 +35,13 @@ SECTIONS
   }
   .hash : { *(.hash) }
   .interp : { *(.interp) }
-  .rela.dyn : { *(.rela*) }
+  .rela.dyn :
+  {
+#ifdef CONFIG_PPC64_BOOT_WRAPPER
+    __rela_dyn_start = .;
+#endif
+    *(.rela*)
+  }
 
   . = ALIGN(8);
   .kernel:dtb :
@@ -53,6 +67,15 @@ SECTIONS
     _initrd_end =  .;
   }
 
+#ifdef CONFIG_PPC64_BOOT_WRAPPER
+  .got :
+  {
+    __toc_start = .;
+    *(.got)
+    *(.toc)
+  }
+#endif
+
   . = ALIGN(4096);
   .bss       :
   {
diff --git a/arch/powerpc/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig
new file mode 100644 (file)
index 0000000..7e2530c
--- /dev/null
@@ -0,0 +1,148 @@
+CONFIG_44x=y
+CONFIG_SMP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_SLUB_CPU_PARTIAL is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_POWERNV_MSI is not set
+CONFIG_PPC_47x=y
+# CONFIG_EBONY is not set
+CONFIG_AKEBONO=y
+CONFIG_HIGHMEM=y
+CONFIG_HZ_100=y
+CONFIG_IRQ_ALL_CPUS=y
+# CONFIG_COMPACTION is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+# CONFIG_SUSPEND is not set
+CONFIG_PCI_MSI=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=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_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=35000
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_ATA_SFF is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+CONFIG_IBM_EMAC=y
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NET_VENDOR_XILINX is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+# CONFIG_USB_DEFAULT_PERSIST is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PCI is not set
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="n"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x00010000
+CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x33f
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1_PPC=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
index 97e02f985df8e47946438ecc1b0ba2f040ee7bf5..37991e154ef88faf50b7b8b447c1772877a253bf 100644 (file)
@@ -42,15 +42,47 @@ void __patch_exception(int exc, unsigned long addr);
 } while (0)
 #endif
 
+#define OP_RT_RA_MASK  0xffff0000UL
+#define LIS_R2         0x3c020000UL
+#define ADDIS_R2_R12   0x3c4c0000UL
+#define ADDI_R2_R2     0x38420000UL
+
 static inline unsigned long ppc_function_entry(void *func)
 {
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC64)
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+       u32 *insn = func;
+
+       /*
+        * A PPC64 ABIv2 function may have a local and a global entry
+        * point. We need to use the local entry point when patching
+        * functions, so identify and step over the global entry point
+        * sequence.
+        *
+        * The global entry point sequence is always of the form:
+        *
+        * addis r2,r12,XXXX
+        * addi  r2,r2,XXXX
+        *
+        * A linker optimisation may convert the addis to lis:
+        *
+        * lis   r2,XXXX
+        * addi  r2,r2,XXXX
+        */
+       if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
+            ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
+           ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2))
+               return (unsigned long)(insn + 2);
+       else
+               return (unsigned long)func;
+#else
        /*
-        * On PPC64 the function pointer actually points to the function's
-        * descriptor. The first entry in the descriptor is the address
-        * of the function text.
+        * On PPC64 ABIv1 the function pointer actually points to the
+        * function's descriptor. The first entry in the descriptor is the
+        * address of the function text.
         */
        return ((func_descr_t *)func)->entry;
+#endif
 #else
        return (unsigned long)func;
 #endif
index b6f5a33b8ee2d839dd5911935adab4738fa48ef8..40014921ffff238fc84c4dbd25b2b02661b8b3d6 100644 (file)
@@ -2,9 +2,9 @@
 #define _ASM_POWERPC_CONTEXT_TRACKING_H
 
 #ifdef CONFIG_CONTEXT_TRACKING
-#define SCHEDULE_USER bl       .schedule_user
+#define SCHEDULE_USER bl       schedule_user
 #else
-#define SCHEDULE_USER bl       .schedule
+#define SCHEDULE_USER bl       schedule
 #endif
 
 #endif
index d4dd41fb951b343918dda3db91399702d0e86423..d12529f34524f12bae93d0c2af4b3feb3b01adce 100644 (file)
@@ -32,6 +32,22 @@ struct device_node;
 
 #ifdef CONFIG_EEH
 
+/* EEH subsystem flags */
+#define EEH_ENABLED            0x1     /* EEH enabled          */
+#define EEH_FORCE_DISABLED     0x2     /* EEH disabled         */
+#define EEH_PROBE_MODE_DEV     0x4     /* From PCI device      */
+#define EEH_PROBE_MODE_DEVTREE 0x8     /* From device tree     */
+
+/*
+ * Delay for PE reset, all in ms
+ *
+ * PCI specification has reset hold time of 100 milliseconds.
+ * We have 250 milliseconds here. The PCI bus settlement time
+ * is specified as 1.5 seconds and we have 1.8 seconds.
+ */
+#define EEH_PE_RST_HOLD_TIME           250
+#define EEH_PE_RST_SETTLE_TIME         1800
+
 /*
  * The struct is used to trace PE related EEH functionality.
  * In theory, there will have one instance of the struct to
@@ -53,7 +69,7 @@ struct device_node;
 
 #define EEH_PE_ISOLATED                (1 << 0)        /* Isolated PE          */
 #define EEH_PE_RECOVERING      (1 << 1)        /* Recovering PE        */
-#define EEH_PE_PHB_DEAD                (1 << 2)        /* Dead PHB             */
+#define EEH_PE_RESET           (1 << 2)        /* PE reset in progress */
 
 #define EEH_PE_KEEP            (1 << 8)        /* Keep PE on hotplug   */
 
@@ -92,6 +108,8 @@ struct eeh_pe {
 
 #define EEH_DEV_NO_HANDLER     (1 << 8)        /* No error handler     */
 #define EEH_DEV_SYSFS          (1 << 9)        /* Sysfs created        */
+#define EEH_DEV_REMOVED                (1 << 10)       /* Removed permanently  */
+#define EEH_DEV_FRESET         (1 << 11)       /* Fundamental reset    */
 
 struct eeh_dev {
        int mode;                       /* EEH mode                     */
@@ -99,7 +117,9 @@ struct eeh_dev {
        int config_addr;                /* Config address               */
        int pe_config_addr;             /* PE config address            */
        u32 config_space[16];           /* Saved PCI config space       */
-       u8 pcie_cap;                    /* Saved PCIe capability        */
+       int pcix_cap;                   /* Saved PCIx capability        */
+       int pcie_cap;                   /* Saved PCIe capability        */
+       int aer_cap;                    /* Saved AER capability         */
        struct eeh_pe *pe;              /* Associated PE                */
        struct list_head list;          /* Form link list in the PE     */
        struct pci_controller *phb;     /* Associated PHB               */
@@ -171,37 +191,40 @@ struct eeh_ops {
        int (*restore_config)(struct device_node *dn);
 };
 
+extern int eeh_subsystem_flags;
 extern struct eeh_ops *eeh_ops;
-extern bool eeh_subsystem_enabled;
 extern raw_spinlock_t confirm_error_lock;
-extern int eeh_probe_mode;
 
 static inline bool eeh_enabled(void)
 {
-       return eeh_subsystem_enabled;
+       if ((eeh_subsystem_flags & EEH_FORCE_DISABLED) ||
+           !(eeh_subsystem_flags & EEH_ENABLED))
+               return false;
+
+       return true;
 }
 
 static inline void eeh_set_enable(bool mode)
 {
-       eeh_subsystem_enabled = mode;
+       if (mode)
+               eeh_subsystem_flags |= EEH_ENABLED;
+       else
+               eeh_subsystem_flags &= ~EEH_ENABLED;
 }
 
-#define EEH_PROBE_MODE_DEV     (1<<0)  /* From PCI device      */
-#define EEH_PROBE_MODE_DEVTREE (1<<1)  /* From device tree     */
-
 static inline void eeh_probe_mode_set(int flag)
 {
-       eeh_probe_mode = flag;
+       eeh_subsystem_flags |= flag;
 }
 
 static inline int eeh_probe_mode_devtree(void)
 {
-       return (eeh_probe_mode == EEH_PROBE_MODE_DEVTREE);
+       return (eeh_subsystem_flags & EEH_PROBE_MODE_DEVTREE);
 }
 
 static inline int eeh_probe_mode_dev(void)
 {
-       return (eeh_probe_mode == EEH_PROBE_MODE_DEV);
+       return (eeh_subsystem_flags & EEH_PROBE_MODE_DEV);
 }
 
 static inline void eeh_serialize_lock(unsigned long *flags)
index a563d9afd179f3790332c453ebae0ee760df6196..a8b52b61043f57112c59822469e9ae648ecd1b1a 100644 (file)
@@ -174,10 +174,10 @@ exc_##label##_book3e:
        mtlr    r16;
 #define TLB_MISS_STATS_D(name)                                             \
        addi    r9,r13,MMSTAT_DSTATS+name;                                  \
-       bl      .tlb_stat_inc;
+       bl      tlb_stat_inc;
 #define TLB_MISS_STATS_I(name)                                             \
        addi    r9,r13,MMSTAT_ISTATS+name;                                  \
-       bl      .tlb_stat_inc;
+       bl      tlb_stat_inc;
 #define TLB_MISS_STATS_X(name)                                             \
        ld      r8,PACA_EXTLB+EX_TLB_ESR(r13);                              \
        cmpdi   cr2,r8,-1;                                                  \
@@ -185,7 +185,7 @@ exc_##label##_book3e:
        addi    r9,r13,MMSTAT_DSTATS+name;                                  \
        b       62f;                                                        \
 61:    addi    r9,r13,MMSTAT_ISTATS+name;                                  \
-62:    bl      .tlb_stat_inc;
+62:    bl      tlb_stat_inc;
 #define TLB_MISS_STATS_SAVE_INFO                                           \
        std     r14,EX_TLB_ESR(r12);    /* save ESR */
 #define TLB_MISS_STATS_SAVE_INFO_BOLTED                                            \
index aeaa56cd9b5465100b00025c7a1da36b3d58e1c5..8f35cd7d59cc6565f07bb46fd1cb392a8794c47e 100644 (file)
@@ -517,7 +517,7 @@ label##_relon_hv:                                                   \
 #define DISABLE_INTS   RECONCILE_IRQ_STATE(r10,r11)
 
 #define ADD_NVGPRS                             \
-       bl      .save_nvgprs
+       bl      save_nvgprs
 
 #define RUNLATCH_ON                            \
 BEGIN_FTR_SECTION                              \
index 169d039ed402080720aef97c33e20952d28dad12..e3661872fbea5b03888aa88c35753bcfc9983403 100644 (file)
@@ -61,6 +61,7 @@ struct dyn_arch_ftrace {
 #endif
 
 #if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) && !defined(__ASSEMBLY__)
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
 #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
 static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
 {
@@ -72,6 +73,7 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name
         */
        return !strcmp(sym + 4, name + 3);
 }
+#endif
 #endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 && !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_FTRACE */
index f51a5580bfd0b2dfbe1abb5edd68e5ab2d3541b7..e20eb95429a8233528fc93508b6bdd0b8ce3bc24 100644 (file)
@@ -20,9 +20,9 @@
  */
 #define TRACE_WITH_FRAME_BUFFER(func)          \
        mflr    r0;                             \
-       stdu    r1, -32(r1);                    \
+       stdu    r1, -STACK_FRAME_OVERHEAD(r1);  \
        std     r0, 16(r1);                     \
-       stdu    r1, -32(r1);                    \
+       stdu    r1, -STACK_FRAME_OVERHEAD(r1);  \
        bl func;                                \
        ld      r1, 0(r1);                      \
        ld      r1, 0(r1);
@@ -36,8 +36,8 @@
  * have to call a C function so call a wrapper that saves all the
  * C-clobbered registers.
  */
-#define TRACE_ENABLE_INTS      TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)
-#define TRACE_DISABLE_INTS     TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)
+#define TRACE_ENABLE_INTS      TRACE_WITH_FRAME_BUFFER(trace_hardirqs_on)
+#define TRACE_DISABLE_INTS     TRACE_WITH_FRAME_BUFFER(trace_hardirqs_off)
 
 /*
  * This is used by assembly code to soft-disable interrupts first and
index 7b6feab6fd26f26cfc3c19456f163845d72db86e..af15d4d8d604c79ab7f09066c1cacfe37d30c7f7 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ptrace.h>
 #include <linux/percpu.h>
 #include <asm/probes.h>
+#include <asm/code-patching.h>
 
 #define  __ARCH_WANT_KPROBES_INSN_SLOT
 
@@ -56,9 +57,9 @@ typedef ppc_opcode_t kprobe_opcode_t;
                if ((colon = strchr(name, ':')) != NULL) {              \
                        colon++;                                        \
                        if (*colon != '\0' && *colon != '.')            \
-                               addr = *(kprobe_opcode_t **)addr;       \
+                               addr = (kprobe_opcode_t *)ppc_function_entry(addr); \
                } else if (name[0] != '.')                              \
-                       addr = *(kprobe_opcode_t **)addr;               \
+                       addr = (kprobe_opcode_t *)ppc_function_entry(addr); \
        } else {                                                        \
                char dot_name[KSYM_NAME_LEN];                           \
                dot_name[0] = '.';                                      \
index b36f650a13fff8d0cd5dacbdee907997d22a6790..e3ad5c72724afd627fb906ba37239a0f8fdf024b 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_POWERPC_LINKAGE_H
 
 #ifdef CONFIG_PPC64
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
 #define cond_syscall(x) \
        asm ("\t.weak " #x "\n\t.set " #x ", sys_ni_syscall\n"          \
             "\t.weak ." #x "\n\t.set ." #x ", .sys_ni_syscall\n")
@@ -9,5 +10,6 @@
        asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n"      \
             "\t.globl ." #alias "\n\t.set ." #alias ", ." #name)
 #endif
+#endif
 
 #endif /* _ASM_POWERPC_LINKAGE_H */
index 5b6c03f1058f21c24a6402d05b8c19d6cd884983..374abc2e41d73131c114e8bfa4d2a9dcadd78614 100644 (file)
@@ -113,6 +113,8 @@ struct machdep_calls {
        /* Optional, may be NULL. */
        void            (*show_cpuinfo)(struct seq_file *m);
        void            (*show_percpuinfo)(struct seq_file *m, int i);
+       /* Returns the current operating frequency of "cpu" in Hz */
+       unsigned long   (*get_proc_freq)(unsigned int cpu);
 
        void            (*init_IRQ)(void);
 
@@ -241,6 +243,9 @@ struct machdep_calls {
        /* Called during PCI resource reassignment */
        resource_size_t (*pcibios_window_alignment)(struct pci_bus *, unsigned long type);
 
+       /* Reset the secondary bus of bridge */
+       void  (*pcibios_reset_secondary_bus)(struct pci_dev *dev);
+
        /* Called to shutdown machine specific hardware not already controlled
         * by other drivers.
         */
index 49fa55bfbac4fba38f26368cbbdcdf1513aa590c..dcfcad139bccc0765e3dc6a5f17cd5566258910b 100644 (file)
@@ -35,6 +35,7 @@ struct mod_arch_specific {
 #ifdef __powerpc64__
        unsigned int stubs_section;     /* Index of stubs section in module */
        unsigned int toc_section;       /* What section is the TOC? */
+       bool toc_fixed;                 /* Have we fixed up .TOC.? */
 #ifdef CONFIG_DYNAMIC_FTRACE
        unsigned long toc;
        unsigned long tramp;
@@ -77,6 +78,9 @@ struct mod_arch_specific {
 #    endif     /* MODULE */
 #endif
 
+bool is_module_trampoline(u32 *insns);
+int module_trampoline_target(struct module *mod, u32 *trampoline,
+                            unsigned long *target);
 
 struct exception_table_entry;
 void sort_ex_table(struct exception_table_entry *start,
index a2efdaa020b0f30b11a08b1352b1f9d7388ad3af..81720ff59a106e599a15f5f535f6b4d08fd4e7fa 100644 (file)
@@ -41,14 +41,14 @@ struct opal_takeover_args {
  * size except the last one in the list to be as well.
  */
 struct opal_sg_entry {
-       void    *data;
-       long    length;
+       __be64 data;
+       __be64 length;
 };
 
-/* sg list */
+/* SG list */
 struct opal_sg_list {
-       unsigned long num_entries;
-       struct opal_sg_list *next;
+       __be64 length;
+       __be64 next;
        struct opal_sg_entry entry[];
 };
 
@@ -858,8 +858,8 @@ int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
                      uint32_t addr, __be32 *data, uint32_t sz);
 
-int64_t opal_read_elog(uint64_t buffer, size_t size, uint64_t log_id);
-int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
+int64_t opal_read_elog(uint64_t buffer, uint64_t size, uint64_t log_id);
+int64_t opal_get_elog_size(__be64 *log_id, __be64 *size, __be64 *elog_type);
 int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
 int64_t opal_send_ack_elog(uint64_t log_id);
 void opal_resend_pending_logs(void);
@@ -868,23 +868,24 @@ int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
 int64_t opal_manage_flash(uint8_t op);
 int64_t opal_update_flash(uint64_t blk_list);
 int64_t opal_dump_init(uint8_t dump_type);
-int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
-int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
+int64_t opal_dump_info(__be32 *dump_id, __be32 *dump_size);
+int64_t opal_dump_info2(__be32 *dump_id, __be32 *dump_size, __be32 *dump_type);
 int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
 int64_t opal_dump_ack(uint32_t dump_id);
 int64_t opal_dump_resend_notification(void);
 
-int64_t opal_get_msg(uint64_t buffer, size_t size);
-int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
+int64_t opal_get_msg(uint64_t buffer, uint64_t size);
+int64_t opal_check_completion(uint64_t buffer, uint64_t size, uint64_t token);
 int64_t opal_sync_host_reboot(void);
 int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
-               size_t length);
+               uint64_t length);
 int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
-               size_t length);
+               uint64_t length);
 int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
 
 /* Internal functions */
-extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
+extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
+                                  int depth, void *data);
 extern int early_init_dt_scan_recoverable_ranges(unsigned long node,
                                 const char *uname, int depth, void *data);
 
@@ -893,10 +894,6 @@ extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
 
 extern void hvc_opal_init_early(void);
 
-/* Internal functions */
-extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
-                                  int depth, void *data);
-
 extern int opal_notifier_register(struct notifier_block *nb);
 extern int opal_notifier_unregister(struct notifier_block *nb);
 
@@ -906,9 +903,6 @@ extern void opal_notifier_enable(void);
 extern void opal_notifier_disable(void);
 extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
 
-extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
-extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
-
 extern int __opal_async_get_token(void);
 extern int opal_async_get_token_interruptible(void);
 extern int __opal_async_release_token(int token);
@@ -916,14 +910,13 @@ extern int opal_async_release_token(int token);
 extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
 extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data);
 
-extern void hvc_opal_init_early(void);
-
 struct rtc_time;
 extern int opal_set_rtc_time(struct rtc_time *tm);
 extern void opal_get_rtc_time(struct rtc_time *tm);
 extern unsigned long opal_get_boot_time(void);
 extern void opal_nvram_init(void);
 extern void opal_flash_init(void);
+extern void opal_flash_term_callback(void);
 extern int opal_elog_init(void);
 extern void opal_platform_dump_init(void);
 extern void opal_sys_param_init(void);
@@ -937,6 +930,10 @@ extern int opal_resync_timebase(void);
 
 extern void opal_lpc_init(void);
 
+struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
+                                            unsigned long vmalloc_size);
+void opal_free_sg_list(struct opal_sg_list *sg);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __OPAL_H */
index ed57fa7920c88dd123fcf139353489fcef4746c0..db1e2b8eff3c4e813d5840b9294128685e8a6b52 100644 (file)
@@ -58,6 +58,7 @@ int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
 int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
 void eeh_pe_state_mark(struct eeh_pe *pe, int state);
 void eeh_pe_state_clear(struct eeh_pe *pe, int state);
+void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode);
 
 void eeh_sysfs_add_device(struct pci_dev *pdev);
 void eeh_sysfs_remove_device(struct pci_dev *pdev);
index 6586a40a46ce161f9f654a57d0222db3bc06d611..6400f1814fe823822f367b379ab5be753a44356e 100644 (file)
@@ -57,7 +57,7 @@ BEGIN_FW_FTR_SECTION;                                                 \
        LDX_BE  r10,0,r10;              /* get log write index */       \
        cmpd    cr1,r11,r10;                                            \
        beq+    cr1,33f;                                                \
-       bl      .accumulate_stolen_time;                                \
+       bl      accumulate_stolen_time;                         \
        ld      r12,_MSR(r1);                                           \
        andi.   r10,r12,MSR_PR;         /* Restore cr0 (coming from user) */ \
 33:                                                                    \
@@ -189,57 +189,53 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
 #define __STK_REG(i)   (112 + ((i)-14)*8)
 #define STK_REG(i)     __STK_REG(__REG_##i)
 
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+#define STK_GOT                24
+#define __STK_PARAM(i) (32 + ((i)-3)*8)
+#else
+#define STK_GOT                40
 #define __STK_PARAM(i) (48 + ((i)-3)*8)
+#endif
 #define STK_PARAM(i)   __STK_PARAM(__REG_##i)
 
-#define XGLUE(a,b) a##b
-#define GLUE(a,b) XGLUE(a,b)
+#if defined(_CALL_ELF) && _CALL_ELF == 2
 
 #define _GLOBAL(name) \
        .section ".text"; \
        .align 2 ; \
+       .type name,@function; \
        .globl name; \
-       .globl GLUE(.,name); \
-       .section ".opd","aw"; \
-name: \
-       .quad GLUE(.,name); \
-       .quad .TOC.@tocbase; \
-       .quad 0; \
-       .previous; \
-       .type GLUE(.,name),@function; \
-GLUE(.,name):
+name:
 
-#define _INIT_GLOBAL(name) \
-       __REF; \
+#define _GLOBAL_TOC(name) \
+       .section ".text"; \
        .align 2 ; \
+       .type name,@function; \
        .globl name; \
-       .globl GLUE(.,name); \
-       .section ".opd","aw"; \
 name: \
-       .quad GLUE(.,name); \
-       .quad .TOC.@tocbase; \
-       .quad 0; \
-       .previous; \
-       .type GLUE(.,name),@function; \
-GLUE(.,name):
+0:     addis r2,r12,(.TOC.-0b)@ha; \
+       addi r2,r2,(.TOC.-0b)@l; \
+       .localentry name,.-name
 
 #define _KPROBE(name) \
        .section ".kprobes.text","a"; \
        .align 2 ; \
+       .type name,@function; \
        .globl name; \
-       .globl GLUE(.,name); \
-       .section ".opd","aw"; \
-name: \
-       .quad GLUE(.,name); \
-       .quad .TOC.@tocbase; \
-       .quad 0; \
-       .previous; \
-       .type GLUE(.,name),@function; \
-GLUE(.,name):
+name:
+
+#define DOTSYM(a)      a
+
+#else
+
+#define XGLUE(a,b) a##b
+#define GLUE(a,b) XGLUE(a,b)
 
-#define _STATIC(name) \
+#define _GLOBAL(name) \
        .section ".text"; \
        .align 2 ; \
+       .globl name; \
+       .globl GLUE(.,name); \
        .section ".opd","aw"; \
 name: \
        .quad GLUE(.,name); \
@@ -249,9 +245,13 @@ name: \
        .type GLUE(.,name),@function; \
 GLUE(.,name):
 
-#define _INIT_STATIC(name) \
-       __REF; \
+#define _GLOBAL_TOC(name) _GLOBAL(name)
+
+#define _KPROBE(name) \
+       .section ".kprobes.text","a"; \
        .align 2 ; \
+       .globl name; \
+       .globl GLUE(.,name); \
        .section ".opd","aw"; \
 name: \
        .quad GLUE(.,name); \
@@ -261,6 +261,10 @@ name: \
        .type GLUE(.,name),@function; \
 GLUE(.,name):
 
+#define DOTSYM(a)      GLUE(.,a)
+
+#endif
+
 #else /* 32-bit */
 
 #define _ENTRY(n)      \
index e5d2e0bc7e032b64890701cdc91d88e18cd665c6..29de0152878fc5934031d930a2d841c02d6e9b50 100644 (file)
 #define SPRN_TEXASR    0x82    /* Transaction EXception & Summary */
 #define   TEXASR_FS    __MASK(63-36)   /* Transaction Failure Summary */
 #define SPRN_TEXASRU   0x83    /* ''      ''      ''    Upper 32  */
+#define   TEXASR_FS     __MASK(63-36) /* TEXASR Failure Summary */
 #define SPRN_TFHAR     0x80    /* Transaction Failure Handler Addr */
 #define SPRN_CTRLF     0x088
 #define SPRN_CTRLT     0x098
index d0e784e0ff484f0053f807e081a4c89fec13dee6..d1bb96d5a298b3f82a068ba0dd9ec9b41095a695 100644 (file)
@@ -39,6 +39,7 @@ static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
                (unsigned long)_stext < end;
 }
 
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
 #undef dereference_function_descriptor
 static inline void *dereference_function_descriptor(void *ptr)
 {
@@ -49,6 +50,7 @@ static inline void *dereference_function_descriptor(void *ptr)
                ptr = p;
        return ptr;
 }
+#endif
 
 #endif
 
index 0dffad6bcc846725a273daff18593c7b03305060..e40010abcaf134f53bbcf639bf6999b856a42a2a 100644 (file)
@@ -10,9 +10,7 @@
 #define __HAVE_ARCH_STRNCMP
 #define __HAVE_ARCH_STRCAT
 #define __HAVE_ARCH_MEMSET
-#ifdef __BIG_ENDIAN__
 #define __HAVE_ARCH_MEMCPY
-#endif
 #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_MEMCMP
 #define __HAVE_ARCH_MEMCHR
@@ -24,9 +22,7 @@ extern int strcmp(const char *,const char *);
 extern int strncmp(const char *, const char *, __kernel_size_t);
 extern char * strcat(char *, const char *);
 extern void * memset(void *,int,__kernel_size_t);
-#ifdef __BIG_ENDIAN__
 extern void * memcpy(void *,const void *,__kernel_size_t);
-#endif
 extern void * memmove(void *,const void *,__kernel_size_t);
 extern int memcmp(const void *,const void *,__kernel_size_t);
 extern void * memchr(const void *,int,__kernel_size_t);
index 3ddf70276706421532066e89261ea3f0d0c8c9ab..ac062f50473605b7bf32459a9c4eeebd38426a8a 100644 (file)
@@ -62,7 +62,7 @@ COMPAT_SYS_SPU(fcntl)
 SYSCALL(ni_syscall)
 SYSCALL_SPU(setpgid)
 SYSCALL(ni_syscall)
-SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
+SYSX(sys_ni_syscall,sys_olduname,sys_olduname)
 SYSCALL_SPU(umask)
 SYSCALL_SPU(chroot)
 COMPAT_SYS(ustat)
@@ -258,7 +258,7 @@ SYSCALL_SPU(tgkill)
 COMPAT_SYS_SPU(utimes)
 COMPAT_SYS_SPU(statfs64)
 COMPAT_SYS_SPU(fstatfs64)
-SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64)
+SYSX(sys_ni_syscall,ppc_fadvise64_64,ppc_fadvise64_64)
 PPC_SYS_SPU(rtas)
 OLDSYS(debug_setcontext)
 SYSCALL(ni_syscall)
@@ -295,7 +295,7 @@ SYSCALL_SPU(mkdirat)
 SYSCALL_SPU(mknodat)
 SYSCALL_SPU(fchownat)
 COMPAT_SYS_SPU(futimesat)
-SYSX_SPU(sys_newfstatat, sys_fstatat64, sys_fstatat64)
+SYSX_SPU(sys_newfstatat,sys_fstatat64,sys_fstatat64)
 SYSCALL_SPU(unlinkat)
 SYSCALL_SPU(renameat)
 SYSCALL_SPU(linkat)
index 7e39c9146a71f63c1701118ec4a2e16a243341b5..59dad113897b0b65f6c616df175a596d901dab77 100644 (file)
@@ -291,9 +291,17 @@ do {                                                                       \
 #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
 #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
 #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16        (sym+add)@dtprel@highesta */
+#define R_PPC64_TLSGD          107
+#define R_PPC64_TLSLD          108
+#define R_PPC64_TOCSAVE                109
+
+#define R_PPC64_REL16          249
+#define R_PPC64_REL16_LO       250
+#define R_PPC64_REL16_HI       251
+#define R_PPC64_REL16_HA       252
 
 /* Keep this the last entry.  */
-#define R_PPC64_NUM            107
+#define R_PPC64_NUM            253
 
 /* There's actually a third entry here, but it's unused */
 struct ppc64_opd_entry
index 552df83f1a49627ddd1d49e1ba982c743a5bfefe..ae3fb68cb28e8df5cb53f078ccc5bcc923c8231c 100644 (file)
@@ -1 +1,6 @@
-#include <asm-generic/setup.h>
+#ifndef _UAPI_ASM_POWERPC_SETUP_H
+#define _UAPI_ASM_POWERPC_SETUP_H
+
+#define COMMAND_LINE_SIZE      2048
+
+#endif /* _UAPI_ASM_POWERPC_SETUP_H */
index cc2d8962e0906b78b4fe9f0c6e18a6991b66b60e..4f1393d200792980c9f7b77c03c92eac9538d70f 100644 (file)
@@ -94,12 +94,12 @@ _GLOBAL(setup_altivec_idle)
 _GLOBAL(__setup_cpu_e6500)
        mflr    r6
 #ifdef CONFIG_PPC64
-       bl      .setup_altivec_ivors
+       bl      setup_altivec_ivors
        /* Touch IVOR42 only if the CPU supports E.HV category */
        mfspr   r10,SPRN_MMUCFG
        rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
        beq     1f
-       bl      .setup_lrat_ivor
+       bl      setup_lrat_ivor
 1:
 #endif
        bl      setup_pw20_idle
@@ -164,15 +164,15 @@ _GLOBAL(__setup_cpu_e5500)
 #ifdef CONFIG_PPC_BOOK3E_64
 _GLOBAL(__restore_cpu_e6500)
        mflr    r5
-       bl      .setup_altivec_ivors
+       bl      setup_altivec_ivors
        /* Touch IVOR42 only if the CPU supports E.HV category */
        mfspr   r10,SPRN_MMUCFG
        rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
        beq     1f
-       bl      .setup_lrat_ivor
+       bl      setup_lrat_ivor
 1:
-       bl      .setup_pw20_idle
-       bl      .setup_altivec_idle
+       bl      setup_pw20_idle
+       bl      setup_altivec_idle
        bl      __restore_cpu_e5500
        mtlr    r5
        blr
@@ -181,9 +181,9 @@ _GLOBAL(__restore_cpu_e5500)
        mflr    r4
        bl      __e500_icache_setup
        bl      __e500_dcache_setup
-       bl      .__setup_base_ivors
-       bl      .setup_perfmon_ivor
-       bl      .setup_doorbell_ivors
+       bl      __setup_base_ivors
+       bl      setup_perfmon_ivor
+       bl      setup_doorbell_ivors
        /*
         * We only want to touch IVOR38-41 if we're running on hardware
         * that supports category E.HV.  The architectural way to determine
@@ -192,7 +192,7 @@ _GLOBAL(__restore_cpu_e5500)
        mfspr   r10,SPRN_MMUCFG
        rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
        beq     1f
-       bl      .setup_ehv_ivors
+       bl      setup_ehv_ivors
 1:
        mtlr    r4
        blr
@@ -201,9 +201,9 @@ _GLOBAL(__setup_cpu_e5500)
        mflr    r5
        bl      __e500_icache_setup
        bl      __e500_dcache_setup
-       bl      .__setup_base_ivors
-       bl      .setup_perfmon_ivor
-       bl      .setup_doorbell_ivors
+       bl      __setup_base_ivors
+       bl      setup_perfmon_ivor
+       bl      setup_doorbell_ivors
        /*
         * We only want to touch IVOR38-41 if we're running on hardware
         * that supports category E.HV.  The architectural way to determine
@@ -212,7 +212,7 @@ _GLOBAL(__setup_cpu_e5500)
        mfspr   r10,SPRN_MMUCFG
        rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
        beq     1f
-       bl      .setup_ehv_ivors
+       bl      setup_ehv_ivors
        b       2f
 1:
        ld      r10,CPU_SPEC_FEATURES(r4)
index e7b76a6bf15083704136459dc1dc69f2c6c9183e..3764fb788d6c56dffcf084475880ad8ee78436d1 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/debugfs.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
 /* Time to wait for a PCI slot to report status, in milliseconds */
 #define PCI_BUS_RESET_WAIT_MSEC (5*60*1000)
 
-/* Platform dependent EEH operations */
-struct eeh_ops *eeh_ops = NULL;
-
-bool eeh_subsystem_enabled = false;
-EXPORT_SYMBOL(eeh_subsystem_enabled);
-
 /*
- * EEH probe mode support. The intention is to support multiple
- * platforms for EEH. Some platforms like pSeries do PCI emunation
- * based on device tree. However, other platforms like powernv probe
- * PCI devices from hardware. The flag is used to distinguish that.
- * In addition, struct eeh_ops::probe would be invoked for particular
- * OF node or PCI device so that the corresponding PE would be created
- * there.
+ * EEH probe mode support, which is part of the flags,
+ * is to support multiple platforms for EEH. Some platforms
+ * like pSeries do PCI emunation based on device tree.
+ * However, other platforms like powernv probe PCI devices
+ * from hardware. The flag is used to distinguish that.
+ * In addition, struct eeh_ops::probe would be invoked for
+ * particular OF node or PCI device so that the corresponding
+ * PE would be created there.
  */
-int eeh_probe_mode;
+int eeh_subsystem_flags;
+EXPORT_SYMBOL(eeh_subsystem_flags);
+
+/* Platform dependent EEH operations */
+struct eeh_ops *eeh_ops = NULL;
 
 /* Lock to avoid races due to multiple reports of an error */
 DEFINE_RAW_SPINLOCK(confirm_error_lock);
@@ -133,6 +133,15 @@ static struct eeh_stats eeh_stats;
 
 #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
 
+static int __init eeh_setup(char *str)
+{
+       if (!strcmp(str, "off"))
+               eeh_subsystem_flags |= EEH_FORCE_DISABLED;
+
+       return 1;
+}
+__setup("eeh=", eeh_setup);
+
 /**
  * eeh_gather_pci_data - Copy assorted PCI config space registers to buff
  * @edev: device to report data for
@@ -145,73 +154,67 @@ static struct eeh_stats eeh_stats;
 static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
 {
        struct device_node *dn = eeh_dev_to_of_node(edev);
-       struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
        u32 cfg;
        int cap, i;
        int n = 0;
 
        n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
-       printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name);
+       pr_warn("EEH: of node=%s\n", dn->full_name);
 
        eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);
        n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
-       printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
+       pr_warn("EEH: PCI device/vendor: %08x\n", cfg);
 
        eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);
        n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
-       printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
-
-       if (!dev) {
-               printk(KERN_WARNING "EEH: no PCI device for this of node\n");
-               return n;
-       }
+       pr_warn("EEH: PCI cmd/status register: %08x\n", cfg);
 
        /* Gather bridge-specific registers */
-       if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
+       if (edev->mode & EEH_DEV_BRIDGE) {
                eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
                n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
-               printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg);
+               pr_warn("EEH: Bridge secondary status: %04x\n", cfg);
 
                eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);
                n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
-               printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);
+               pr_warn("EEH: Bridge control: %04x\n", cfg);
        }
 
        /* Dump out the PCI-X command and status regs */
-       cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+       cap = edev->pcix_cap;
        if (cap) {
                eeh_ops->read_config(dn, cap, 4, &cfg);
                n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
-               printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
+               pr_warn("EEH: PCI-X cmd: %08x\n", cfg);
 
                eeh_ops->read_config(dn, cap+4, 4, &cfg);
                n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
-               printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
+               pr_warn("EEH: PCI-X status: %08x\n", cfg);
        }
 
-       /* If PCI-E capable, dump PCI-E cap 10, and the AER */
-       if (pci_is_pcie(dev)) {
+       /* If PCI-E capable, dump PCI-E cap 10 */
+       cap = edev->pcie_cap;
+       if (cap) {
                n += scnprintf(buf+n, len-n, "pci-e cap10:\n");
-               printk(KERN_WARNING
-                      "EEH: PCI-E capabilities and status follow:\n");
+               pr_warn("EEH: PCI-E capabilities and status follow:\n");
 
                for (i=0; i<=8; i++) {
-                       eeh_ops->read_config(dn, dev->pcie_cap+4*i, 4, &cfg);
+                       eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
                        n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
-                       printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
+                       pr_warn("EEH: PCI-E %02x: %08x\n", i, cfg);
                }
+       }
 
-               cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-               if (cap) {
-                       n += scnprintf(buf+n, len-n, "pci-e AER:\n");
-                       printk(KERN_WARNING
-                              "EEH: PCI-E AER capability register set follows:\n");
-
-                       for (i=0; i<14; i++) {
-                               eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
-                               n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
-                               printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
-                       }
+       /* If AER capable, dump it */
+       cap = edev->aer_cap;
+       if (cap) {
+               n += scnprintf(buf+n, len-n, "pci-e AER:\n");
+               pr_warn("EEH: PCI-E AER capability register set follows:\n");
+
+               for (i=0; i<14; i++) {
+                       eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
+                       n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+                       pr_warn("EEH: PCI-E AER %02x: %08x\n", i, cfg);
                }
        }
 
@@ -232,21 +235,19 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
 {
        size_t loglen = 0;
        struct eeh_dev *edev, *tmp;
-       bool valid_cfg_log = true;
 
        /*
         * When the PHB is fenced or dead, it's pointless to collect
         * the data from PCI config space because it should return
         * 0xFF's. For ER, we still retrieve the data from the PCI
         * config space.
+        *
+        * For pHyp, we have to enable IO for log retrieval. Otherwise,
+        * 0xFF's is always returned from PCI config space.
         */
-       if (eeh_probe_mode_dev() &&
-           (pe->type & EEH_PE_PHB) &&
-           (pe->state & (EEH_PE_ISOLATED | EEH_PE_PHB_DEAD)))
-               valid_cfg_log = false;
-
-       if (valid_cfg_log) {
-               eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
+       if (!(pe->type & EEH_PE_PHB)) {
+               if (eeh_probe_mode_devtree())
+                       eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
                eeh_ops->configure_bridge(pe);
                eeh_pe_restore_bars(pe);
 
@@ -309,7 +310,7 @@ static int eeh_phb_check_failure(struct eeh_pe *pe)
 
        /* If the PHB has been in problematic state */
        eeh_serialize_lock(&flags);
-       if (phb_pe->state & (EEH_PE_ISOLATED | EEH_PE_PHB_DEAD)) {
+       if (phb_pe->state & EEH_PE_ISOLATED) {
                ret = 0;
                goto out;
        }
@@ -515,16 +516,42 @@ EXPORT_SYMBOL(eeh_check_failure);
  */
 int eeh_pci_enable(struct eeh_pe *pe, int function)
 {
-       int rc;
+       int rc, flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
+
+       /*
+        * pHyp doesn't allow to enable IO or DMA on unfrozen PE.
+        * Also, it's pointless to enable them on unfrozen PE. So
+        * we have the check here.
+        */
+       if (function == EEH_OPT_THAW_MMIO ||
+           function == EEH_OPT_THAW_DMA) {
+               rc = eeh_ops->get_state(pe, NULL);
+               if (rc < 0)
+                       return rc;
+
+               /* Needn't to enable or already enabled */
+               if ((rc == EEH_STATE_NOT_SUPPORT) ||
+                   ((rc & flags) == flags))
+                       return 0;
+       }
 
        rc = eeh_ops->set_option(pe, function);
        if (rc)
-               pr_warning("%s: Unexpected state change %d on PHB#%d-PE#%x, err=%d\n",
-                       __func__, function, pe->phb->global_number, pe->addr, rc);
+               pr_warn("%s: Unexpected state change %d on "
+                       "PHB#%d-PE#%x, err=%d\n",
+                       __func__, function, pe->phb->global_number,
+                       pe->addr, rc);
 
        rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
-       if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) &&
-          (function == EEH_OPT_THAW_MMIO))
+       if (rc <= 0)
+               return rc;
+
+       if ((function == EEH_OPT_THAW_MMIO) &&
+           (rc & EEH_STATE_MMIO_ENABLED))
+               return 0;
+
+       if ((function == EEH_OPT_THAW_DMA) &&
+           (rc & EEH_STATE_DMA_ENABLED))
                return 0;
 
        return rc;
@@ -612,26 +639,7 @@ static void eeh_reset_pe_once(struct eeh_pe *pe)
        else
                eeh_ops->reset(pe, EEH_RESET_HOT);
 
-       /* The PCI bus requires that the reset be held high for at least
-        * a 100 milliseconds. We wait a bit longer 'just in case'.
-        */
-#define PCI_BUS_RST_HOLD_TIME_MSEC 250
-       msleep(PCI_BUS_RST_HOLD_TIME_MSEC);
-
-       /* We might get hit with another EEH freeze as soon as the
-        * pci slot reset line is dropped. Make sure we don't miss
-        * these, and clear the flag now.
-        */
-       eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
-
        eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
-
-       /* After a PCI slot has been reset, the PCI Express spec requires
-        * a 1.5 second idle time for the bus to stabilize, before starting
-        * up traffic.
-        */
-#define PCI_BUS_SETTLE_TIME_MSEC 1800
-       msleep(PCI_BUS_SETTLE_TIME_MSEC);
 }
 
 /**
@@ -651,6 +659,10 @@ int eeh_reset_pe(struct eeh_pe *pe)
        for (i=0; i<3; i++) {
                eeh_reset_pe_once(pe);
 
+               /*
+                * EEH_PE_ISOLATED is expected to be removed after
+                * BAR restore.
+                */
                rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
                if ((rc & flags) == flags)
                        return 0;
@@ -826,8 +838,8 @@ int eeh_init(void)
                        &hose_list, list_node)
                        pci_walk_bus(hose->bus, eeh_ops->dev_probe, NULL);
        } else {
-               pr_warning("%s: Invalid probe mode %d\n",
-                          __func__, eeh_probe_mode);
+               pr_warn("%s: Invalid probe mode %x",
+                       __func__, eeh_subsystem_flags);
                return -EINVAL;
        }
 
@@ -1102,10 +1114,45 @@ static const struct file_operations proc_eeh_operations = {
        .release   = single_release,
 };
 
+#ifdef CONFIG_DEBUG_FS
+static int eeh_enable_dbgfs_set(void *data, u64 val)
+{
+       if (val)
+               eeh_subsystem_flags &= ~EEH_FORCE_DISABLED;
+       else
+               eeh_subsystem_flags |= EEH_FORCE_DISABLED;
+
+       /* Notify the backend */
+       if (eeh_ops->post_init)
+               eeh_ops->post_init();
+
+       return 0;
+}
+
+static int eeh_enable_dbgfs_get(void *data, u64 *val)
+{
+       if (eeh_enabled())
+               *val = 0x1ul;
+       else
+               *val = 0x0ul;
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(eeh_enable_dbgfs_ops, eeh_enable_dbgfs_get,
+                       eeh_enable_dbgfs_set, "0x%llx\n");
+#endif
+
 static int __init eeh_init_proc(void)
 {
-       if (machine_is(pseries) || machine_is(powernv))
+       if (machine_is(pseries) || machine_is(powernv)) {
                proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations);
+#ifdef CONFIG_DEBUG_FS
+               debugfs_create_file("eeh_enable", 0600,
+                                    powerpc_debugfs_root, NULL,
+                                    &eeh_enable_dbgfs_ops);
+#endif
+       }
+
        return 0;
 }
 __initcall(eeh_init_proc);
index bb61ca58ca6d8272955d7023852f97cbe180c676..7100a5b96e7059caf572609dec9d7f9393f0106f 100644 (file)
@@ -171,6 +171,15 @@ static void eeh_enable_irq(struct pci_dev *dev)
        }
 }
 
+static bool eeh_dev_removed(struct eeh_dev *edev)
+{
+       /* EEH device removed ? */
+       if (!edev || (edev->mode & EEH_DEV_REMOVED))
+               return true;
+
+       return false;
+}
+
 /**
  * eeh_report_error - Report pci error to each device driver
  * @data: eeh device
@@ -187,10 +196,8 @@ static void *eeh_report_error(void *data, void *userdata)
        enum pci_ers_result rc, *res = userdata;
        struct pci_driver *driver;
 
-       /* We might not have the associated PCI device,
-        * then we should continue for next one.
-        */
-       if (!dev) return NULL;
+       if (!dev || eeh_dev_removed(edev))
+               return NULL;
        dev->error_state = pci_channel_io_frozen;
 
        driver = eeh_pcid_get(dev);
@@ -230,6 +237,9 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata)
        enum pci_ers_result rc, *res = userdata;
        struct pci_driver *driver;
 
+       if (!dev || eeh_dev_removed(edev))
+               return NULL;
+
        driver = eeh_pcid_get(dev);
        if (!driver) return NULL;
 
@@ -267,7 +277,8 @@ static void *eeh_report_reset(void *data, void *userdata)
        enum pci_ers_result rc, *res = userdata;
        struct pci_driver *driver;
 
-       if (!dev) return NULL;
+       if (!dev || eeh_dev_removed(edev))
+               return NULL;
        dev->error_state = pci_channel_io_normal;
 
        driver = eeh_pcid_get(dev);
@@ -307,7 +318,8 @@ static void *eeh_report_resume(void *data, void *userdata)
        struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
        struct pci_driver *driver;
 
-       if (!dev) return NULL;
+       if (!dev || eeh_dev_removed(edev))
+               return NULL;
        dev->error_state = pci_channel_io_normal;
 
        driver = eeh_pcid_get(dev);
@@ -343,7 +355,8 @@ static void *eeh_report_failure(void *data, void *userdata)
        struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
        struct pci_driver *driver;
 
-       if (!dev) return NULL;
+       if (!dev || eeh_dev_removed(edev))
+               return NULL;
        dev->error_state = pci_channel_io_perm_failure;
 
        driver = eeh_pcid_get(dev);
@@ -380,6 +393,16 @@ static void *eeh_rmv_device(void *data, void *userdata)
        if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE))
                return NULL;
 
+       /*
+        * We rely on count-based pcibios_release_device() to
+        * detach permanently offlined PEs. Unfortunately, that's
+        * not reliable enough. We might have the permanently
+        * offlined PEs attached, but we needn't take care of
+        * them and their child devices.
+        */
+       if (eeh_dev_removed(edev))
+               return NULL;
+
        driver = eeh_pcid_get(dev);
        if (driver) {
                eeh_pcid_put(dev);
@@ -417,6 +440,36 @@ static void *eeh_pe_detach_dev(void *data, void *userdata)
        return NULL;
 }
 
+/*
+ * Explicitly clear PE's frozen state for PowerNV where
+ * we have frozen PE until BAR restore is completed. It's
+ * harmless to clear it for pSeries. To be consistent with
+ * PE reset (for 3 times), we try to clear the frozen state
+ * for 3 times as well.
+ */
+static int eeh_clear_pe_frozen_state(struct eeh_pe *pe)
+{
+       int i, rc;
+
+       for (i = 0; i < 3; i++) {
+               rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
+               if (rc)
+                       continue;
+               rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA);
+               if (!rc)
+                       break;
+       }
+
+       /* The PE has been isolated, clear it */
+       if (rc)
+               pr_warn("%s: Can't clear frozen PHB#%x-PE#%x (%d)\n",
+                       __func__, pe->phb->global_number, pe->addr, rc);
+       else
+               eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
+
+       return rc;
+}
+
 /**
  * eeh_reset_device - Perform actual reset of a pci slot
  * @pe: EEH PE
@@ -451,19 +504,33 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
                eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
        }
 
-       /* Reset the pci controller. (Asserts RST#; resets config space).
+       /*
+        * Reset the pci controller. (Asserts RST#; resets config space).
         * Reconfigure bridges and devices. Don't try to bring the system
         * up if the reset failed for some reason.
+        *
+        * During the reset, it's very dangerous to have uncontrolled PCI
+        * config accesses. So we prefer to block them. However, controlled
+        * PCI config accesses initiated from EEH itself are allowed.
         */
+       eeh_pe_state_mark(pe, EEH_PE_RESET);
        rc = eeh_reset_pe(pe);
-       if (rc)
+       if (rc) {
+               eeh_pe_state_clear(pe, EEH_PE_RESET);
                return rc;
+       }
 
        pci_lock_rescan_remove();
 
        /* Restore PE */
        eeh_ops->configure_bridge(pe);
        eeh_pe_restore_bars(pe);
+       eeh_pe_state_clear(pe, EEH_PE_RESET);
+
+       /* Clear frozen state */
+       rc = eeh_clear_pe_frozen_state(pe);
+       if (rc)
+               return rc;
 
        /* Give the system 5 seconds to finish running the user-space
         * hotplug shutdown scripts, e.g. ifdown for ethernet.  Yes,
@@ -573,7 +640,6 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
                        result = PCI_ERS_RESULT_NEED_RESET;
                } else {
                        pr_info("EEH: Notify device drivers to resume I/O\n");
-                       result = PCI_ERS_RESULT_NONE;
                        eeh_pe_dev_traverse(pe, eeh_report_mmio_enabled, &result);
                }
        }
@@ -585,10 +651,17 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
 
                if (rc < 0)
                        goto hard_fail;
-               if (rc)
+               if (rc) {
                        result = PCI_ERS_RESULT_NEED_RESET;
-               else
+               } else {
+                       /*
+                        * We didn't do PE reset for the case. The PE
+                        * is still in frozen state. Clear it before
+                        * resuming the PE.
+                        */
+                       eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
                        result = PCI_ERS_RESULT_RECOVERED;
+               }
        }
 
        /* If any device has a hard failure, then shut off everything. */
@@ -650,8 +723,17 @@ perm_error:
        /* Notify all devices that they're about to go down. */
        eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
 
-       /* Shut down the device drivers for good. */
+       /* Mark the PE to be removed permanently */
+       pe->freeze_count = EEH_MAX_ALLOWED_FREEZES + 1;
+
+       /*
+        * Shut down the device drivers for good. We mark
+        * all removed devices correctly to avoid access
+        * the their PCI config any more.
+        */
        if (frozen_bus) {
+               eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
+
                pci_lock_rescan_remove();
                pcibios_remove_pci_devices(frozen_bus);
                pci_unlock_rescan_remove();
@@ -682,8 +764,7 @@ static void eeh_handle_special_event(void)
                                phb_pe = eeh_phb_pe_get(hose);
                                if (!phb_pe) continue;
 
-                               eeh_pe_state_mark(phb_pe,
-                                       EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+                               eeh_pe_state_mark(phb_pe, EEH_PE_ISOLATED);
                        }
 
                        eeh_serialize_unlock(flags);
@@ -699,8 +780,7 @@ static void eeh_handle_special_event(void)
                        eeh_remove_event(pe);
 
                        if (rc == EEH_NEXT_ERR_DEAD_PHB)
-                               eeh_pe_state_mark(pe,
-                                       EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+                               eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
                        else
                                eeh_pe_state_mark(pe,
                                        EEH_PE_ISOLATED | EEH_PE_RECOVERING);
@@ -724,12 +804,14 @@ static void eeh_handle_special_event(void)
                if (rc == EEH_NEXT_ERR_FROZEN_PE ||
                    rc == EEH_NEXT_ERR_FENCED_PHB) {
                        eeh_handle_normal_event(pe);
+                       eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
                } else {
                        pci_lock_rescan_remove();
                        list_for_each_entry(hose, &hose_list, list_node) {
                                phb_pe = eeh_phb_pe_get(hose);
                                if (!phb_pe ||
-                                   !(phb_pe->state & EEH_PE_PHB_DEAD))
+                                   !(phb_pe->state & EEH_PE_ISOLATED) ||
+                                   (phb_pe->state & EEH_PE_RECOVERING))
                                        continue;
 
                                /* Notify all devices to be down */
index f0c353fa655a3a5a742e2de674851ab3ca88006a..995c2a2846303d3885674d474bcbfd0cae90f9cc 100644 (file)
@@ -503,13 +503,17 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
        struct eeh_dev *edev, *tmp;
        struct pci_dev *pdev;
 
-       /*
-        * Mark the PE with the indicated state. Also,
-        * the associated PCI device will be put into
-        * I/O frozen state to avoid I/O accesses from
-        * the PCI device driver.
-        */
+       /* Keep the state of permanently removed PE intact */
+       if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) &&
+           (state & (EEH_PE_ISOLATED | EEH_PE_RECOVERING)))
+               return NULL;
+
        pe->state |= state;
+
+       /* Offline PCI devices if applicable */
+       if (state != EEH_PE_ISOLATED)
+               return NULL;
+
        eeh_pe_for_each_dev(pe, edev, tmp) {
                pdev = eeh_dev_to_pci_dev(edev);
                if (pdev)
@@ -532,6 +536,27 @@ void eeh_pe_state_mark(struct eeh_pe *pe, int state)
        eeh_pe_traverse(pe, __eeh_pe_state_mark, &state);
 }
 
+static void *__eeh_pe_dev_mode_mark(void *data, void *flag)
+{
+       struct eeh_dev *edev = data;
+       int mode = *((int *)flag);
+
+       edev->mode |= mode;
+
+       return NULL;
+}
+
+/**
+ * eeh_pe_dev_state_mark - Mark state for all device under the PE
+ * @pe: EEH PE
+ *
+ * Mark specific state for all child devices of the PE.
+ */
+void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode)
+{
+       eeh_pe_dev_traverse(pe, __eeh_pe_dev_mode_mark, &mode);
+}
+
 /**
  * __eeh_pe_state_clear - Clear state for the PE
  * @data: EEH PE
@@ -546,8 +571,16 @@ static void *__eeh_pe_state_clear(void *data, void *flag)
        struct eeh_pe *pe = (struct eeh_pe *)data;
        int state = *((int *)flag);
 
+       /* Keep the state of permanently removed PE intact */
+       if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) &&
+           (state & EEH_PE_ISOLATED))
+               return NULL;
+
        pe->state &= ~state;
-       pe->check_count = 0;
+
+       /* Clear check count since last isolation */
+       if (state & EEH_PE_ISOLATED)
+               pe->check_count = 0;
 
        return NULL;
 }
index 662c6dd98072e72beabcb1e894cc05999324da81..9fde8a1bf1e14d617cce4a8093ff210536e271f2 100644 (file)
@@ -39,8 +39,8 @@
  * System calls.
  */
        .section        ".toc","aw"
-.SYS_CALL_TABLE:
-       .tc .sys_call_table[TC],.sys_call_table
+SYS_CALL_TABLE:
+       .tc sys_call_table[TC],sys_call_table
 
 /* This value is used to mark exception frames on the stack. */
 exception_marker:
@@ -106,7 +106,7 @@ BEGIN_FW_FTR_SECTION
        LDX_BE  r10,0,r10               /* get log write index */
        cmpd    cr1,r11,r10
        beq+    cr1,33f
-       bl      .accumulate_stolen_time
+       bl      accumulate_stolen_time
        REST_GPR(0,r1)
        REST_4GPRS(3,r1)
        REST_2GPRS(7,r1)
@@ -143,7 +143,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
        std     r10,SOFTE(r1)
 
 #ifdef SHOW_SYSCALLS
-       bl      .do_show_syscall
+       bl      do_show_syscall
        REST_GPR(0,r1)
        REST_4GPRS(3,r1)
        REST_2GPRS(7,r1)
@@ -162,7 +162,7 @@ system_call:                        /* label this so stack traces look sane */
  * Need to vector to 32 Bit or default sys_call_table here,
  * based on caller's run-mode / personality.
  */
-       ld      r11,.SYS_CALL_TABLE@toc(2)
+       ld      r11,SYS_CALL_TABLE@toc(2)
        andi.   r10,r10,_TIF_32BIT
        beq     15f
        addi    r11,r11,8       /* use 32-bit syscall entries */
@@ -174,14 +174,14 @@ system_call:                      /* label this so stack traces look sane */
        clrldi  r8,r8,32
 15:
        slwi    r0,r0,4
-       ldx     r10,r11,r0      /* Fetch system call handler [ptr] */
-       mtctr   r10
+       ldx     r12,r11,r0      /* Fetch system call handler [ptr] */
+       mtctr   r12
        bctrl                   /* Call handler */
 
 syscall_exit:
        std     r3,RESULT(r1)
 #ifdef SHOW_SYSCALLS
-       bl      .do_show_syscall_exit
+       bl      do_show_syscall_exit
        ld      r3,RESULT(r1)
 #endif
        CURRENT_THREAD_INFO(r12, r1)
@@ -248,9 +248,9 @@ syscall_error:
        
 /* Traced system call support */
 syscall_dotrace:
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_syscall_trace_enter
+       bl      do_syscall_trace_enter
        /*
         * Restore argument registers possibly just changed.
         * We use the return value of do_syscall_trace_enter
@@ -308,7 +308,7 @@ syscall_exit_work:
 4:     /* Anything else left to do? */
        SET_DEFAULT_THREAD_PPR(r3, r10)         /* Set thread.ppr = 3 */
        andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
-       beq     .ret_from_except_lite
+       beq     ret_from_except_lite
 
        /* Re-enable interrupts */
 #ifdef CONFIG_PPC_BOOK3E
@@ -319,10 +319,10 @@ syscall_exit_work:
        mtmsrd  r10,1
 #endif /* CONFIG_PPC_BOOK3E */
 
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_syscall_trace_leave
-       b       .ret_from_except
+       bl      do_syscall_trace_leave
+       b       ret_from_except
 
 /* Save non-volatile GPRs, if not already saved. */
 _GLOBAL(save_nvgprs)
@@ -345,42 +345,44 @@ _GLOBAL(save_nvgprs)
  */
 
 _GLOBAL(ppc_fork)
-       bl      .save_nvgprs
-       bl      .sys_fork
+       bl      save_nvgprs
+       bl      sys_fork
        b       syscall_exit
 
 _GLOBAL(ppc_vfork)
-       bl      .save_nvgprs
-       bl      .sys_vfork
+       bl      save_nvgprs
+       bl      sys_vfork
        b       syscall_exit
 
 _GLOBAL(ppc_clone)
-       bl      .save_nvgprs
-       bl      .sys_clone
+       bl      save_nvgprs
+       bl      sys_clone
        b       syscall_exit
 
 _GLOBAL(ppc32_swapcontext)
-       bl      .save_nvgprs
-       bl      .compat_sys_swapcontext
+       bl      save_nvgprs
+       bl      compat_sys_swapcontext
        b       syscall_exit
 
 _GLOBAL(ppc64_swapcontext)
-       bl      .save_nvgprs
-       bl      .sys_swapcontext
+       bl      save_nvgprs
+       bl      sys_swapcontext
        b       syscall_exit
 
 _GLOBAL(ret_from_fork)
-       bl      .schedule_tail
+       bl      schedule_tail
        REST_NVGPRS(r1)
        li      r3,0
        b       syscall_exit
 
 _GLOBAL(ret_from_kernel_thread)
-       bl      .schedule_tail
+       bl      schedule_tail
        REST_NVGPRS(r1)
-       ld      r14, 0(r14)
        mtlr    r14
        mr      r3,r15
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+       mr      r12,r14
+#endif
        blrl
        li      r3,0
        b       syscall_exit
@@ -611,7 +613,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
 _GLOBAL(ret_from_except)
        ld      r11,_TRAP(r1)
        andi.   r0,r11,1
-       bne     .ret_from_except_lite
+       bne     ret_from_except_lite
        REST_NVGPRS(r1)
 
 _GLOBAL(ret_from_except_lite)
@@ -661,23 +663,23 @@ _GLOBAL(ret_from_except_lite)
 #endif
 1:     andi.   r0,r4,_TIF_NEED_RESCHED
        beq     2f
-       bl      .restore_interrupts
+       bl      restore_interrupts
        SCHEDULE_USER
-       b       .ret_from_except_lite
+       b       ret_from_except_lite
 2:
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        andi.   r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM
        bne     3f              /* only restore TM if nothing else to do */
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .restore_tm_state
+       bl      restore_tm_state
        b       restore
 3:
 #endif
-       bl      .save_nvgprs
-       bl      .restore_interrupts
+       bl      save_nvgprs
+       bl      restore_interrupts
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_notify_resume
-       b       .ret_from_except
+       bl      do_notify_resume
+       b       ret_from_except
 
 resume_kernel:
        /* check current_thread_info, _TIF_EMULATE_STACK_STORE */
@@ -730,7 +732,7 @@ resume_kernel:
         * sure we are soft-disabled first and reconcile irq state.
         */
        RECONCILE_IRQ_STATE(r3,r4)
-1:     bl      .preempt_schedule_irq
+1:     bl      preempt_schedule_irq
 
        /* Re-test flags and eventually loop */
        CURRENT_THREAD_INFO(r9, r1)
@@ -792,7 +794,7 @@ restore_no_replay:
         */
 do_restore:
 #ifdef CONFIG_PPC_BOOK3E
-       b       .exception_return_book3e
+       b       exception_return_book3e
 #else
        /*
         * Clear the reservation. If we know the CPU tracks the address of
@@ -907,7 +909,7 @@ restore_check_irq_replay:
         *
         * Still, this might be useful for things like hash_page
         */
-       bl      .__check_irq_replay
+       bl      __check_irq_replay
        cmpwi   cr0,r3,0
        beq     restore_no_replay
  
@@ -928,13 +930,13 @@ restore_check_irq_replay:
        cmpwi   cr0,r3,0x500
        bne     1f
        addi    r3,r1,STACK_FRAME_OVERHEAD;
-       bl      .do_IRQ
-       b       .ret_from_except
+       bl      do_IRQ
+       b       ret_from_except
 1:     cmpwi   cr0,r3,0x900
        bne     1f
        addi    r3,r1,STACK_FRAME_OVERHEAD;
-       bl      .timer_interrupt
-       b       .ret_from_except
+       bl      timer_interrupt
+       b       ret_from_except
 #ifdef CONFIG_PPC_DOORBELL
 1:
 #ifdef CONFIG_PPC_BOOK3E
@@ -948,14 +950,14 @@ restore_check_irq_replay:
 #endif /* CONFIG_PPC_BOOK3E */
        bne     1f
        addi    r3,r1,STACK_FRAME_OVERHEAD;
-       bl      .doorbell_exception
-       b       .ret_from_except
+       bl      doorbell_exception
+       b       ret_from_except
 #endif /* CONFIG_PPC_DOORBELL */
-1:     b       .ret_from_except /* What else to do here ? */
+1:     b       ret_from_except /* What else to do here ? */
  
 unrecov_restore:
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
+       bl      unrecoverable_exception
        b       unrecov_restore
 
 #ifdef CONFIG_PPC_RTAS
@@ -1021,7 +1023,7 @@ _GLOBAL(enter_rtas)
         std    r6,PACASAVEDMSR(r13)
 
        /* Setup our real return addr */        
-       LOAD_REG_ADDR(r4,.rtas_return_loc)
+       LOAD_REG_ADDR(r4,rtas_return_loc)
        clrldi  r4,r4,2                 /* convert to realmode address */
                mtlr    r4
 
@@ -1045,7 +1047,7 @@ _GLOBAL(enter_rtas)
        rfid
        b       .       /* prevent speculative execution */
 
-_STATIC(rtas_return_loc)
+rtas_return_loc:
        FIXUP_ENDIAN
 
        /* relocation is off at this point */
@@ -1054,7 +1056,7 @@ _STATIC(rtas_return_loc)
 
        bcl     20,31,$+4
 0:     mflr    r3
-       ld      r3,(1f-0b)(r3)          /* get &.rtas_restore_regs */
+       ld      r3,(1f-0b)(r3)          /* get &rtas_restore_regs */
 
        mfmsr   r6
        li      r0,MSR_RI
@@ -1071,9 +1073,9 @@ _STATIC(rtas_return_loc)
        b       .       /* prevent speculative execution */
 
        .align  3
-1:     .llong  .rtas_restore_regs
+1:     .llong  rtas_restore_regs
 
-_STATIC(rtas_restore_regs)
+rtas_restore_regs:
        /* relocation is on at this point */
        REST_GPR(2, r1)                 /* Restore the TOC */
        REST_GPR(13, r1)                /* Restore paca */
@@ -1173,7 +1175,7 @@ _GLOBAL(mcount)
 _GLOBAL(_mcount)
        blr
 
-_GLOBAL(ftrace_caller)
+_GLOBAL_TOC(ftrace_caller)
        /* Taken from output of objdump from lib64/glibc */
        mflr    r3
        ld      r11, 0(r1)
@@ -1197,10 +1199,7 @@ _GLOBAL(ftrace_graph_stub)
 _GLOBAL(ftrace_stub)
        blr
 #else
-_GLOBAL(mcount)
-       blr
-
-_GLOBAL(_mcount)
+_GLOBAL_TOC(_mcount)
        /* Taken from output of objdump from lib64/glibc */
        mflr    r3
        ld      r11, 0(r1)
@@ -1238,7 +1237,7 @@ _GLOBAL(ftrace_graph_caller)
        ld      r11, 112(r1)
        addi    r3, r11, 16
 
-       bl      .prepare_ftrace_return
+       bl      prepare_ftrace_return
        nop
 
        ld      r0, 128(r1)
@@ -1254,7 +1253,7 @@ _GLOBAL(return_to_handler)
        mr      r31, r1
        stdu    r1, -112(r1)
 
-       bl      .ftrace_return_to_handler
+       bl      ftrace_return_to_handler
        nop
 
        /* return value has real return address */
@@ -1284,7 +1283,7 @@ _GLOBAL(mod_return_to_handler)
         */
        ld      r2, PACATOC(r13)
 
-       bl      .ftrace_return_to_handler
+       bl      ftrace_return_to_handler
        nop
 
        /* return value has real return address */
index c1bee3ce9d1fb63530bb886b04e456275279f050..771b4e92e5d9c091fcedfa1dc4982fa6950c1405 100644 (file)
@@ -499,7 +499,7 @@ exc_##n##_bad_stack:                                                            \
        CHECK_NAPPING();                                                \
        addi    r3,r1,STACK_FRAME_OVERHEAD;                             \
        bl      hdlr;                                                   \
-       b       .ret_from_except_lite;
+       b       ret_from_except_lite;
 
 /* This value is used to mark exception frames on the stack. */
        .section        ".toc","aw"
@@ -550,11 +550,11 @@ interrupt_end_book3e:
        CRIT_EXCEPTION_PROLOG(0x100, BOOKE_INTERRUPT_CRITICAL,
                              PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON_CRIT(0x100)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unknown_exception
+       bl      unknown_exception
        b       ret_from_crit_except
 
 /* Machine Check Interrupt */
@@ -562,11 +562,11 @@ interrupt_end_book3e:
        MC_EXCEPTION_PROLOG(0x000, BOOKE_INTERRUPT_MACHINE_CHECK,
                            PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON_MC(0x000)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .machine_check_exception
+       bl      machine_check_exception
        b       ret_from_mc_except
 
 /* Data Storage Interrupt */
@@ -591,7 +591,7 @@ interrupt_end_book3e:
 
 /* External Input Interrupt */
        MASKABLE_EXCEPTION(0x500, BOOKE_INTERRUPT_EXTERNAL,
-                          external_input, .do_IRQ, ACK_NONE)
+                          external_input, do_IRQ, ACK_NONE)
 
 /* Alignment */
        START_EXCEPTION(alignment);
@@ -612,9 +612,9 @@ interrupt_end_book3e:
        std     r14,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r14,PACA_EXGEN+EX_R14(r13)
-       bl      .save_nvgprs
-       bl      .program_check_exception
-       b       .ret_from_except
+       bl      save_nvgprs
+       bl      program_check_exception
+       b       ret_from_except
 
 /* Floating Point Unavailable Interrupt */
        START_EXCEPTION(fp_unavailable);
@@ -625,13 +625,13 @@ interrupt_end_book3e:
        ld      r12,_MSR(r1)
        andi.   r0,r12,MSR_PR;
        beq-    1f
-       bl      .load_up_fpu
+       bl      load_up_fpu
        b       fast_exception_return
 1:     INTS_DISABLE
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .kernel_fp_unavailable_exception
-       b       .ret_from_except
+       bl      kernel_fp_unavailable_exception
+       b       ret_from_except
 
 /* Altivec Unavailable Interrupt */
        START_EXCEPTION(altivec_unavailable);
@@ -644,16 +644,16 @@ BEGIN_FTR_SECTION
        ld      r12,_MSR(r1)
        andi.   r0,r12,MSR_PR;
        beq-    1f
-       bl      .load_up_altivec
+       bl      load_up_altivec
        b       fast_exception_return
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        INTS_DISABLE
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .altivec_unavailable_exception
-       b       .ret_from_except
+       bl      altivec_unavailable_exception
+       b       ret_from_except
 
 /* AltiVec Assist */
        START_EXCEPTION(altivec_assist);
@@ -662,39 +662,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
                                PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON(0x220)
        INTS_DISABLE
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
-       bl      .altivec_assist_exception
+       bl      altivec_assist_exception
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #else
-       bl      .unknown_exception
+       bl      unknown_exception
 #endif
-       b       .ret_from_except
+       b       ret_from_except
 
 
 /* Decrementer Interrupt */
        MASKABLE_EXCEPTION(0x900, BOOKE_INTERRUPT_DECREMENTER,
-                          decrementer, .timer_interrupt, ACK_DEC)
+                          decrementer, timer_interrupt, ACK_DEC)
 
 /* Fixed Interval Timer Interrupt */
        MASKABLE_EXCEPTION(0x980, BOOKE_INTERRUPT_FIT,
-                          fixed_interval, .unknown_exception, ACK_FIT)
+                          fixed_interval, unknown_exception, ACK_FIT)
 
 /* Watchdog Timer Interrupt */
        START_EXCEPTION(watchdog);
        CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG,
                              PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON_CRIT(0x9f0)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
 #ifdef CONFIG_BOOKE_WDT
-       bl      .WatchdogException
+       bl      WatchdogException
 #else
-       bl      .unknown_exception
+       bl      unknown_exception
 #endif
        b       ret_from_crit_except
 
@@ -712,10 +712,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
                                PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON(0xf20)
        INTS_DISABLE
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unknown_exception
-       b       .ret_from_except
+       bl      unknown_exception
+       b       ret_from_except
 
 /* Debug exception as a critical interrupt*/
        START_EXCEPTION(debug_crit);
@@ -774,9 +774,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        mr      r4,r14
        ld      r14,PACA_EXCRIT+EX_R14(r13)
        ld      r15,PACA_EXCRIT+EX_R15(r13)
-       bl      .save_nvgprs
-       bl      .DebugException
-       b       .ret_from_except
+       bl      save_nvgprs
+       bl      DebugException
+       b       ret_from_except
 
 kernel_dbg_exc:
        b       .       /* NYI */
@@ -839,9 +839,9 @@ kernel_dbg_exc:
        mr      r4,r14
        ld      r14,PACA_EXDBG+EX_R14(r13)
        ld      r15,PACA_EXDBG+EX_R15(r13)
-       bl      .save_nvgprs
-       bl      .DebugException
-       b       .ret_from_except
+       bl      save_nvgprs
+       bl      DebugException
+       b       ret_from_except
 
        START_EXCEPTION(perfmon);
        NORMAL_EXCEPTION_PROLOG(0x260, BOOKE_INTERRUPT_PERFORMANCE_MONITOR,
@@ -850,23 +850,23 @@ kernel_dbg_exc:
        INTS_DISABLE
        CHECK_NAPPING()
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .performance_monitor_exception
-       b       .ret_from_except_lite
+       bl      performance_monitor_exception
+       b       ret_from_except_lite
 
 /* Doorbell interrupt */
        MASKABLE_EXCEPTION(0x280, BOOKE_INTERRUPT_DOORBELL,
-                          doorbell, .doorbell_exception, ACK_NONE)
+                          doorbell, doorbell_exception, ACK_NONE)
 
 /* Doorbell critical Interrupt */
        START_EXCEPTION(doorbell_crit);
        CRIT_EXCEPTION_PROLOG(0x2a0, BOOKE_INTERRUPT_DOORBELL_CRITICAL,
                              PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON_CRIT(0x2a0)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unknown_exception
+       bl      unknown_exception
        b       ret_from_crit_except
 
 /*
@@ -878,21 +878,21 @@ kernel_dbg_exc:
                                PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON(0x2c0)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .save_nvgprs
+       bl      save_nvgprs
        INTS_RESTORE_HARD
-       bl      .unknown_exception
-       b       .ret_from_except
+       bl      unknown_exception
+       b       ret_from_except
 
 /* Guest Doorbell critical Interrupt */
        START_EXCEPTION(guest_doorbell_crit);
        CRIT_EXCEPTION_PROLOG(0x2e0, BOOKE_INTERRUPT_GUEST_DBELL_CRIT,
                              PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON_CRIT(0x2e0)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unknown_exception
+       bl      unknown_exception
        b       ret_from_crit_except
 
 /* Hypervisor call */
@@ -901,10 +901,10 @@ kernel_dbg_exc:
                                PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON(0x310)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .save_nvgprs
+       bl      save_nvgprs
        INTS_RESTORE_HARD
-       bl      .unknown_exception
-       b       .ret_from_except
+       bl      unknown_exception
+       b       ret_from_except
 
 /* Embedded Hypervisor priviledged  */
        START_EXCEPTION(ehpriv);
@@ -912,10 +912,10 @@ kernel_dbg_exc:
                                PROLOG_ADDITION_NONE)
        EXCEPTION_COMMON(0x320)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .save_nvgprs
+       bl      save_nvgprs
        INTS_RESTORE_HARD
-       bl      .unknown_exception
-       b       .ret_from_except
+       bl      unknown_exception
+       b       ret_from_except
 
 /* LRAT Error interrupt */
        START_EXCEPTION(lrat_error);
@@ -1014,16 +1014,16 @@ storage_fault_common:
        mr      r5,r15
        ld      r14,PACA_EXGEN+EX_R14(r13)
        ld      r15,PACA_EXGEN+EX_R15(r13)
-       bl      .do_page_fault
+       bl      do_page_fault
        cmpdi   r3,0
        bne-    1f
-       b       .ret_from_except_lite
-1:     bl      .save_nvgprs
+       b       ret_from_except_lite
+1:     bl      save_nvgprs
        mr      r5,r3
        addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r4,_DAR(r1)
-       bl      .bad_page_fault
-       b       .ret_from_except
+       bl      bad_page_fault
+       b       ret_from_except
 
 /*
  * Alignment exception doesn't fit entirely in the 0x100 bytes so it
@@ -1035,10 +1035,10 @@ alignment_more:
        addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r14,PACA_EXGEN+EX_R14(r13)
        ld      r15,PACA_EXGEN+EX_R15(r13)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        INTS_RESTORE_HARD
-       bl      .alignment_exception
-       b       .ret_from_except
+       bl      alignment_exception
+       b       ret_from_except
 
 /*
  * We branch here from entry_64.S for the last stage of the exception
@@ -1172,7 +1172,7 @@ bad_stack_book3e:
        std     r12,0(r11)
        ld      r2,PACATOC(r13)
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .kernel_bad_stack
+       bl      kernel_bad_stack
        b       1b
 
 /*
@@ -1521,13 +1521,13 @@ _GLOBAL(start_initialization_book3e)
         * and always use AS 0, so we just set it up to match our link
         * address and never use 0 based addresses.
         */
-       bl      .initial_tlb_book3e
+       bl      initial_tlb_book3e
 
        /* Init global core bits */
-       bl      .init_core_book3e
+       bl      init_core_book3e
 
        /* Init per-thread bits */
-       bl      .init_thread_book3e
+       bl      init_thread_book3e
 
        /* Return to common init code */
        tovirt(r28,r28)
@@ -1548,7 +1548,7 @@ _GLOBAL(start_initialization_book3e)
  */
 _GLOBAL(book3e_secondary_core_init_tlb_set)
        li      r4,1
-       b       .generic_secondary_smp_init
+       b       generic_secondary_smp_init
 
 _GLOBAL(book3e_secondary_core_init)
        mflr    r28
@@ -1558,18 +1558,18 @@ _GLOBAL(book3e_secondary_core_init)
        bne     2f
 
        /* Setup TLB for this core */
-       bl      .initial_tlb_book3e
+       bl      initial_tlb_book3e
 
        /* We can return from the above running at a different
         * address, so recalculate r2 (TOC)
         */
-       bl      .relative_toc
+       bl      relative_toc
 
        /* Init global core bits */
-2:     bl      .init_core_book3e
+2:     bl      init_core_book3e
 
        /* Init per-thread bits */
-3:     bl      .init_thread_book3e
+3:     bl      init_thread_book3e
 
        /* Return to common init code at proper virtual address.
         *
@@ -1596,14 +1596,14 @@ _GLOBAL(book3e_secondary_thread_init)
        mflr    r28
        b       3b
 
-_STATIC(init_core_book3e)
+init_core_book3e:
        /* Establish the interrupt vector base */
        LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e)
        mtspr   SPRN_IVPR,r3
        sync
        blr
 
-_STATIC(init_thread_book3e)
+init_thread_book3e:
        lis     r3,(SPRN_EPCR_ICM | SPRN_EPCR_GICM)@h
        mtspr   SPRN_EPCR,r3
 
index 3afd3915921a267496eb63c329570cee1906bf14..20f11eb4dff7ee4e308565ec0910f57b5bd189e6 100644 (file)
@@ -132,12 +132,12 @@ BEGIN_FTR_SECTION
 #endif
 
        beq     cr1,2f
-       b       .power7_wakeup_noloss
-2:     b       .power7_wakeup_loss
+       b       power7_wakeup_noloss
+2:     b       power7_wakeup_loss
 
        /* Fast Sleep wakeup on PowerNV */
 8:     GET_PACA(r13)
-       b       .power7_wakeup_tb_loss
+       b       power7_wakeup_tb_loss
 
 9:
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
@@ -211,16 +211,16 @@ data_access_slb_pSeries:
 #endif /* __DISABLED__ */
        mfspr   r12,SPRN_SRR1
 #ifndef CONFIG_RELOCATABLE
-       b       .slb_miss_realmode
+       b       slb_miss_realmode
 #else
        /*
-        * We can't just use a direct branch to .slb_miss_realmode
+        * We can't just use a direct branch to slb_miss_realmode
         * because the distance from here to there depends on where
         * the kernel ends up being put.
         */
        mfctr   r11
        ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, .slb_miss_realmode)
+       LOAD_HANDLER(r10, slb_miss_realmode)
        mtctr   r10
        bctr
 #endif
@@ -243,11 +243,11 @@ instruction_access_slb_pSeries:
 #endif /* __DISABLED__ */
        mfspr   r12,SPRN_SRR1
 #ifndef CONFIG_RELOCATABLE
-       b       .slb_miss_realmode
+       b       slb_miss_realmode
 #else
        mfctr   r11
        ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, .slb_miss_realmode)
+       LOAD_HANDLER(r10, slb_miss_realmode)
        mtctr   r10
        bctr
 #endif
@@ -524,7 +524,7 @@ do_stab_bolted_pSeries:
        std     r12,PACA_EXSLB+EX_R12(r13)
        GET_SCRATCH0(r10)
        std     r10,PACA_EXSLB+EX_R13(r13)
-       EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
+       EXCEPTION_PROLOG_PSERIES_1(do_stab_bolted, EXC_STD)
 
        KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
        KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
@@ -769,38 +769,38 @@ kvmppc_skip_Hinterrupt:
 
 /*** Common interrupt handlers ***/
 
-       STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception)
+       STD_EXCEPTION_COMMON(0x100, system_reset, system_reset_exception)
 
        STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
-       STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt)
-       STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt)
+       STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, timer_interrupt)
+       STD_EXCEPTION_COMMON(0x980, hdecrementer, hdec_interrupt)
 #ifdef CONFIG_PPC_DOORBELL
-       STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, .doorbell_exception)
+       STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, doorbell_exception)
 #else
-       STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, .unknown_exception)
+       STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, unknown_exception)
 #endif
-       STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
-       STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
-       STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
-       STD_EXCEPTION_COMMON(0xe40, emulation_assist, .emulation_assist_interrupt)
-       STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
+       STD_EXCEPTION_COMMON(0xb00, trap_0b, unknown_exception)
+       STD_EXCEPTION_COMMON(0xd00, single_step, single_step_exception)
+       STD_EXCEPTION_COMMON(0xe00, trap_0e, unknown_exception)
+       STD_EXCEPTION_COMMON(0xe40, emulation_assist, emulation_assist_interrupt)
+       STD_EXCEPTION_COMMON(0xe60, hmi_exception, unknown_exception)
 #ifdef CONFIG_PPC_DOORBELL
-       STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, .doorbell_exception)
+       STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception)
 #else
-       STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, .unknown_exception)
+       STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, unknown_exception)
 #endif
-       STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception)
-       STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
-       STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception)
+       STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, performance_monitor_exception)
+       STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, instruction_breakpoint_exception)
+       STD_EXCEPTION_COMMON(0x1502, denorm, unknown_exception)
 #ifdef CONFIG_ALTIVEC
-       STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception)
+       STD_EXCEPTION_COMMON(0x1700, altivec_assist, altivec_assist_exception)
 #else
-       STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception)
+       STD_EXCEPTION_COMMON(0x1700, altivec_assist, unknown_exception)
 #endif
 #ifdef CONFIG_CBE_RAS
-       STD_EXCEPTION_COMMON(0x1200, cbe_system_error, .cbe_system_error_exception)
-       STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, .cbe_maintenance_exception)
-       STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)
+       STD_EXCEPTION_COMMON(0x1200, cbe_system_error, cbe_system_error_exception)
+       STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, cbe_maintenance_exception)
+       STD_EXCEPTION_COMMON(0x1800, cbe_thermal, cbe_thermal_exception)
 #endif /* CONFIG_CBE_RAS */
 
        /*
@@ -829,16 +829,16 @@ data_access_slb_relon_pSeries:
        mfspr   r3,SPRN_DAR
        mfspr   r12,SPRN_SRR1
 #ifndef CONFIG_RELOCATABLE
-       b       .slb_miss_realmode
+       b       slb_miss_realmode
 #else
        /*
-        * We can't just use a direct branch to .slb_miss_realmode
+        * We can't just use a direct branch to slb_miss_realmode
         * because the distance from here to there depends on where
         * the kernel ends up being put.
         */
        mfctr   r11
        ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, .slb_miss_realmode)
+       LOAD_HANDLER(r10, slb_miss_realmode)
        mtctr   r10
        bctr
 #endif
@@ -854,11 +854,11 @@ instruction_access_slb_relon_pSeries:
        mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
        mfspr   r12,SPRN_SRR1
 #ifndef CONFIG_RELOCATABLE
-       b       .slb_miss_realmode
+       b       slb_miss_realmode
 #else
        mfctr   r11
        ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, .slb_miss_realmode)
+       LOAD_HANDLER(r10, slb_miss_realmode)
        mtctr   r10
        bctr
 #endif
@@ -966,7 +966,7 @@ system_call_entry:
        b       system_call_common
 
 ppc64_runlatch_on_trampoline:
-       b       .__ppc64_runlatch_on
+       b       __ppc64_runlatch_on
 
 /*
  * Here we have detected that the kernel stack pointer is bad.
@@ -1025,7 +1025,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
        std     r12,RESULT(r1)
        std     r11,STACK_FRAME_OVERHEAD-16(r1)
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .kernel_bad_stack
+       bl      kernel_bad_stack
        b       1b
 
 /*
@@ -1046,7 +1046,7 @@ data_access_common:
        ld      r3,PACA_EXGEN+EX_DAR(r13)
        lwz     r4,PACA_EXGEN+EX_DSISR(r13)
        li      r5,0x300
-       b       .do_hash_page           /* Try to handle as hpte fault */
+       b       do_hash_page            /* Try to handle as hpte fault */
 
        .align  7
        .globl  h_data_storage_common
@@ -1056,11 +1056,11 @@ h_data_storage_common:
        mfspr   r10,SPRN_HDSISR
        stw     r10,PACA_EXGEN+EX_DSISR(r13)
        EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unknown_exception
-       b       .ret_from_except
+       bl      unknown_exception
+       b       ret_from_except
 
        .align  7
        .globl instruction_access_common
@@ -1071,9 +1071,9 @@ instruction_access_common:
        ld      r3,_NIP(r1)
        andis.  r4,r12,0x5820
        li      r5,0x400
-       b       .do_hash_page           /* Try to handle as hpte fault */
+       b       do_hash_page            /* Try to handle as hpte fault */
 
-       STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception)
+       STD_EXCEPTION_COMMON(0xe20, h_instr_storage, unknown_exception)
 
 /*
  * Here is the common SLB miss user that is used when going to virtual
@@ -1088,7 +1088,7 @@ slb_miss_user_common:
        stw     r9,PACA_EXGEN+EX_CCR(r13)
        std     r10,PACA_EXGEN+EX_LR(r13)
        std     r11,PACA_EXGEN+EX_SRR0(r13)
-       bl      .slb_allocate_user
+       bl      slb_allocate_user
 
        ld      r10,PACA_EXGEN+EX_LR(r13)
        ld      r3,PACA_EXGEN+EX_R3(r13)
@@ -1131,9 +1131,9 @@ slb_miss_fault:
 unrecov_user_slb:
        EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN)
        DISABLE_INTS
-       bl      .save_nvgprs
+       bl      save_nvgprs
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
+       bl      unrecoverable_exception
        b       1b
 
 #endif /* __DISABLED__ */
@@ -1158,10 +1158,10 @@ machine_check_common:
        lwz     r4,PACA_EXGEN+EX_DSISR(r13)
        std     r3,_DAR(r1)
        std     r4,_DSISR(r1)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .machine_check_exception
-       b       .ret_from_except
+       bl      machine_check_exception
+       b       ret_from_except
 
        .align  7
        .globl alignment_common
@@ -1175,31 +1175,31 @@ alignment_common:
        lwz     r4,PACA_EXGEN+EX_DSISR(r13)
        std     r3,_DAR(r1)
        std     r4,_DSISR(r1)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .alignment_exception
-       b       .ret_from_except
+       bl      alignment_exception
+       b       ret_from_except
 
        .align  7
        .globl program_check_common
 program_check_common:
        EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .program_check_exception
-       b       .ret_from_except
+       bl      program_check_exception
+       b       ret_from_except
 
        .align  7
        .globl fp_unavailable_common
 fp_unavailable_common:
        EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
        bne     1f                      /* if from user, just load it up */
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .kernel_fp_unavailable_exception
+       bl      kernel_fp_unavailable_exception
        BUG_OPCODE
 1:
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
@@ -1211,15 +1211,15 @@ BEGIN_FTR_SECTION
        bne-    2f
 END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
-       bl      .load_up_fpu
+       bl      load_up_fpu
        b       fast_exception_return
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 2:     /* User process was in a transaction */
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .fp_unavailable_tm
-       b       .ret_from_except
+       bl      fp_unavailable_tm
+       b       ret_from_except
 #endif
        .align  7
        .globl altivec_unavailable_common
@@ -1237,24 +1237,24 @@ BEGIN_FTR_SECTION
        bne-    2f
   END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
 #endif
-       bl      .load_up_altivec
+       bl      load_up_altivec
        b       fast_exception_return
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 2:     /* User process was in a transaction */
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .altivec_unavailable_tm
-       b       .ret_from_except
+       bl      altivec_unavailable_tm
+       b       ret_from_except
 #endif
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .altivec_unavailable_exception
-       b       .ret_from_except
+       bl      altivec_unavailable_exception
+       b       ret_from_except
 
        .align  7
        .globl vsx_unavailable_common
@@ -1272,26 +1272,26 @@ BEGIN_FTR_SECTION
        bne-    2f
   END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
 #endif
-       b       .load_up_vsx
+       b       load_up_vsx
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 2:     /* User process was in a transaction */
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .vsx_unavailable_tm
-       b       .ret_from_except
+       bl      vsx_unavailable_tm
+       b       ret_from_except
 #endif
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif
-       bl      .save_nvgprs
+       bl      save_nvgprs
        DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .vsx_unavailable_exception
-       b       .ret_from_except
+       bl      vsx_unavailable_exception
+       b       ret_from_except
 
-       STD_EXCEPTION_COMMON(0xf60, facility_unavailable, .facility_unavailable_exception)
-       STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, .facility_unavailable_exception)
+       STD_EXCEPTION_COMMON(0xf60, facility_unavailable, facility_unavailable_exception)
+       STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, facility_unavailable_exception)
 
        .align  7
        .globl  __end_handlers
@@ -1386,9 +1386,9 @@ _GLOBAL(opal_mc_secondary_handler)
 machine_check_handle_early:
        std     r0,GPR0(r1)     /* Save r0 */
        EXCEPTION_PROLOG_COMMON_3(0x200)
-       bl      .save_nvgprs
+       bl      save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .machine_check_early
+       bl      machine_check_early
        ld      r12,_MSR(r1)
 #ifdef CONFIG_PPC_P7_NAP
        /*
@@ -1408,11 +1408,11 @@ machine_check_handle_early:
        /* Supervisor state loss */
        li      r0,1
        stb     r0,PACA_NAPSTATELOST(r13)
-3:     bl      .machine_check_queue_event
+3:     bl      machine_check_queue_event
        MACHINE_CHECK_HANDLER_WINDUP
        GET_PACA(r13)
        ld      r1,PACAR1(r13)
-       b       .power7_enter_nap_mode
+       b       power7_enter_nap_mode
 4:
 #endif
        /*
@@ -1444,7 +1444,7 @@ machine_check_handle_early:
        andi.   r11,r12,MSR_RI
        bne     2f
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
+       bl      unrecoverable_exception
        b       1b
 2:
        /*
@@ -1452,7 +1452,7 @@ machine_check_handle_early:
         * Queue up the MCE event so that we can log it later, while
         * returning from kernel or opal call.
         */
-       bl      .machine_check_queue_event
+       bl      machine_check_queue_event
        MACHINE_CHECK_HANDLER_WINDUP
        rfid
 9:
@@ -1468,7 +1468,7 @@ machine_check_handle_early:
  * r3 is saved in paca->slb_r3
  * We assume we aren't going to take any exceptions during this procedure.
  */
-_GLOBAL(slb_miss_realmode)
+slb_miss_realmode:
        mflr    r10
 #ifdef CONFIG_RELOCATABLE
        mtctr   r11
@@ -1477,7 +1477,7 @@ _GLOBAL(slb_miss_realmode)
        stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
        std     r10,PACA_EXSLB+EX_LR(r13)       /* save LR */
 
-       bl      .slb_allocate_realmode
+       bl      slb_allocate_realmode
 
        /* All done -- return from exception. */
 
@@ -1517,9 +1517,9 @@ _GLOBAL(slb_miss_realmode)
 unrecov_slb:
        EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
        DISABLE_INTS
-       bl      .save_nvgprs
+       bl      save_nvgprs
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
+       bl      unrecoverable_exception
        b       1b
 
 
@@ -1536,7 +1536,7 @@ power4_fixup_nap:
  * Hash table stuff
  */
        .align  7
-_STATIC(do_hash_page)
+do_hash_page:
        std     r3,_DAR(r1)
        std     r4,_DSISR(r1)
 
@@ -1573,7 +1573,7 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
         *
         * at return r3 = 0 for success, 1 for page fault, negative for error
         */
-       bl      .hash_page              /* build HPTE if possible */
+       bl      hash_page               /* build HPTE if possible */
        cmpdi   r3,0                    /* see if hash_page succeeded */
 
        /* Success */
@@ -1587,35 +1587,35 @@ handle_page_fault:
 11:    ld      r4,_DAR(r1)
        ld      r5,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_page_fault
+       bl      do_page_fault
        cmpdi   r3,0
        beq+    12f
-       bl      .save_nvgprs
+       bl      save_nvgprs
        mr      r5,r3
        addi    r3,r1,STACK_FRAME_OVERHEAD
        lwz     r4,_DAR(r1)
-       bl      .bad_page_fault
-       b       .ret_from_except
+       bl      bad_page_fault
+       b       ret_from_except
 
 /* We have a data breakpoint exception - handle it */
 handle_dabr_fault:
-       bl      .save_nvgprs
+       bl      save_nvgprs
        ld      r4,_DAR(r1)
        ld      r5,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_break
-12:    b       .ret_from_except_lite
+       bl      do_break
+12:    b       ret_from_except_lite
 
 
 /* We have a page fault that hash_page could handle but HV refused
  * the PTE insertion
  */
-13:    bl      .save_nvgprs
+13:    bl      save_nvgprs
        mr      r5,r3
        addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r4,_DAR(r1)
-       bl      .low_hash_fault
-       b       .ret_from_except
+       bl      low_hash_fault
+       b       ret_from_except
 
 /*
  * We come here as a result of a DSI at a point where we don't want
@@ -1624,16 +1624,16 @@ handle_dabr_fault:
  * were soft-disabled.  We want to invoke the exception handler for
  * the access, or panic if there isn't a handler.
  */
-77:    bl      .save_nvgprs
+77:    bl      save_nvgprs
        mr      r4,r3
        addi    r3,r1,STACK_FRAME_OVERHEAD
        li      r5,SIGSEGV
-       bl      .bad_page_fault
-       b       .ret_from_except
+       bl      bad_page_fault
+       b       ret_from_except
 
        /* here we have a segment miss */
 do_ste_alloc:
-       bl      .ste_allocate           /* try to insert stab entry */
+       bl      ste_allocate            /* try to insert stab entry */
        cmpdi   r3,0
        bne-    handle_page_fault
        b       fast_exception_return
@@ -1646,7 +1646,7 @@ do_ste_alloc:
  * We assume (DAR >> 60) == 0xc.
  */
        .align  7
-_GLOBAL(do_stab_bolted)
+do_stab_bolted:
        stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
        std     r11,PACA_EXSLB+EX_SRR0(r13)     /* save SRR0 in exc. frame */
        mfspr   r11,SPRN_DAR                    /* ea */
index 2230fd0ca3e4fc089931f25a61c20cb66aa99a6a..02667744fbb55c4ddbbd9eb22a208136fd2c1c29 100644 (file)
@@ -69,7 +69,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node,
         */
        token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
        if (!token)
-               return 0;
+               return 1;
 
        fw_dump.fadump_supported = 1;
        fw_dump.ibm_configure_kernel_dump = *token;
@@ -92,7 +92,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node,
                                        &size);
 
        if (!sections)
-               return 0;
+               return 1;
 
        num_sections = size / (3 * sizeof(u32));
 
@@ -110,6 +110,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node,
                        break;
                }
        }
+
        return 1;
 }
 
index 6a014c763cc71da4a9a5fd523649f105bf5fdc10..f202d0731b065466ba8151df98b11cd6a3cd720c 100644 (file)
@@ -105,11 +105,9 @@ __ftrace_make_nop(struct module *mod,
                  struct dyn_ftrace *rec, unsigned long addr)
 {
        unsigned int op;
-       unsigned int jmp[5];
        unsigned long ptr;
        unsigned long ip = rec->ip;
-       unsigned long tramp;
-       int offset;
+       void *tramp;
 
        /* read where this goes */
        if (probe_kernel_read(&op, (void *)ip, sizeof(int)))
@@ -122,96 +120,41 @@ __ftrace_make_nop(struct module *mod,
        }
 
        /* lets find where the pointer goes */
-       tramp = find_bl_target(ip, op);
-
-       /*
-        * On PPC64 the trampoline looks like:
-        * 0x3d, 0x82, 0x00, 0x00,    addis   r12,r2, <high>
-        * 0x39, 0x8c, 0x00, 0x00,    addi    r12,r12, <low>
-        *   Where the bytes 2,3,6 and 7 make up the 32bit offset
-        *   to the TOC that holds the pointer.
-        *   to jump to.
-        * 0xf8, 0x41, 0x00, 0x28,    std     r2,40(r1)
-        * 0xe9, 0x6c, 0x00, 0x20,    ld      r11,32(r12)
-        *   The actually address is 32 bytes from the offset
-        *   into the TOC.
-        * 0xe8, 0x4c, 0x00, 0x28,    ld      r2,40(r12)
-        */
-
-       pr_devel("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
-
-       /* Find where the trampoline jumps to */
-       if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
-               printk(KERN_ERR "Failed to read %lx\n", tramp);
-               return -EFAULT;
-       }
+       tramp = (void *)find_bl_target(ip, op);
 
-       pr_devel(" %08x %08x", jmp[0], jmp[1]);
+       pr_devel("ip:%lx jumps to %p", ip, tramp);
 
-       /* verify that this is what we expect it to be */
-       if (((jmp[0] & 0xffff0000) != 0x3d820000) ||
-           ((jmp[1] & 0xffff0000) != 0x398c0000) ||
-           (jmp[2] != 0xf8410028) ||
-           (jmp[3] != 0xe96c0020) ||
-           (jmp[4] != 0xe84c0028)) {
+       if (!is_module_trampoline(tramp)) {
                printk(KERN_ERR "Not a trampoline\n");
                return -EINVAL;
        }
 
-       /* The bottom half is signed extended */
-       offset = ((unsigned)((unsigned short)jmp[0]) << 16) +
-               (int)((short)jmp[1]);
-
-       pr_devel(" %x ", offset);
-
-       /* get the address this jumps too */
-       tramp = mod->arch.toc + offset + 32;
-       pr_devel("toc: %lx", tramp);
-
-       if (probe_kernel_read(jmp, (void *)tramp, 8)) {
-               printk(KERN_ERR "Failed to read %lx\n", tramp);
+       if (module_trampoline_target(mod, tramp, &ptr)) {
+               printk(KERN_ERR "Failed to get trampoline target\n");
                return -EFAULT;
        }
 
-       pr_devel(" %08x %08x\n", jmp[0], jmp[1]);
-
-#ifdef __LITTLE_ENDIAN__
-       ptr = ((unsigned long)jmp[1] << 32) + jmp[0];
-#else
-       ptr = ((unsigned long)jmp[0] << 32) + jmp[1];
-#endif
+       pr_devel("trampoline target %lx", ptr);
 
        /* This should match what was called */
        if (ptr != ppc_function_entry((void *)addr)) {
-               printk(KERN_ERR "addr does not match %lx\n", ptr);
+               printk(KERN_ERR "addr %lx does not match expected %lx\n",
+                       ptr, ppc_function_entry((void *)addr));
                return -EINVAL;
        }
 
        /*
-        * We want to nop the line, but the next line is
-        *  0xe8, 0x41, 0x00, 0x28   ld r2,40(r1)
-        * This needs to be turned to a nop too.
-        */
-       if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE))
-               return -EFAULT;
-
-       if (op != 0xe8410028) {
-               printk(KERN_ERR "Next line is not ld! (%08x)\n", op);
-               return -EINVAL;
-       }
-
-       /*
-        * Milton Miller pointed out that we can not blindly do nops.
-        * If a task was preempted when calling a trace function,
-        * the nops will remove the way to restore the TOC in r2
-        * and the r2 TOC will get corrupted.
-        */
-
-       /*
-        * Replace:
-        *   bl <tramp>  <==== will be replaced with "b 1f"
-        *   ld r2,40(r1)
-        *  1:
+        * Our original call site looks like:
+        *
+        * bl <tramp>
+        * ld r2,XX(r1)
+        *
+        * Milton Miller pointed out that we can not simply nop the branch.
+        * If a task was preempted when calling a trace function, the nops
+        * will remove the way to restore the TOC in r2 and the r2 TOC will
+        * get corrupted.
+        *
+        * Use a b +8 to jump over the load.
         */
        op = 0x48000008;        /* b +8 */
 
@@ -349,19 +292,24 @@ static int
 __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
        unsigned int op[2];
-       unsigned long ip = rec->ip;
+       void *ip = (void *)rec->ip;
 
        /* read where this goes */
-       if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
+       if (probe_kernel_read(op, ip, sizeof(op)))
                return -EFAULT;
 
        /*
-        * It should be pointing to two nops or
-        *  b +8; ld r2,40(r1)
+        * We expect to see:
+        *
+        * b +8
+        * ld r2,XX(r1)
+        *
+        * The load offset is different depending on the ABI. For simplicity
+        * just mask it out when doing the compare.
         */
-       if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) &&
-           ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) {
-               printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]);
+       if ((op[0] != 0x48000008) || ((op[1] & 0xffff00000) != 0xe8410000)) {
+               printk(KERN_ERR "Unexpected call sequence: %x %x\n",
+                       op[0], op[1]);
                return -EINVAL;
        }
 
@@ -371,23 +319,16 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                return -EINVAL;
        }
 
-       /* create the branch to the trampoline */
-       op[0] = create_branch((unsigned int *)ip,
-                             rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
-       if (!op[0]) {
-               printk(KERN_ERR "REL24 out of range!\n");
+       /* Ensure branch is within 24 bits */
+       if (create_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
+               printk(KERN_ERR "Branch out of range");
                return -EINVAL;
        }
 
-       /* ld r2,40(r1) */
-       op[1] = 0xe8410028;
-
-       pr_devel("write to %lx\n", rec->ip);
-
-       if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
-               return -EPERM;
-
-       flush_icache_range(ip, ip + 8);
+       if (patch_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
+               printk(KERN_ERR "REL24 out of range!\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
index b7363bd42452848169e3fa5bc58721c1aeb3b08a..a95145d7f61bffa1736a183efc78c1596e32bb4c 100644 (file)
@@ -70,16 +70,15 @@ _GLOBAL(__start)
        /* NOP this out unconditionally */
 BEGIN_FTR_SECTION
        FIXUP_ENDIAN
-       b       .__start_initialization_multiplatform
+       b       __start_initialization_multiplatform
 END_FTR_SECTION(0, 1)
 
        /* Catch branch to 0 in real mode */
        trap
 
-       /* Secondary processors spin on this value until it becomes nonzero.
-        * When it does it contains the real address of the descriptor
-        * of the function that the cpu should jump to to continue
-        * initialization.
+       /* Secondary processors spin on this value until it becomes non-zero.
+        * When non-zero, it contains the real address of the function the cpu
+        * should jump to.
         */
        .balign 8
        .globl  __secondary_hold_spinloop
@@ -140,16 +139,15 @@ __secondary_hold:
        tovirt(r26,r26)
 #endif
        /* All secondary cpus wait here until told to start. */
-100:   ld      r4,__secondary_hold_spinloop-_stext(r26)
-       cmpdi   0,r4,0
+100:   ld      r12,__secondary_hold_spinloop-_stext(r26)
+       cmpdi   0,r12,0
        beq     100b
 
 #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
 #ifdef CONFIG_PPC_BOOK3E
-       tovirt(r4,r4)
+       tovirt(r12,r12)
 #endif
-       ld      r4,0(r4)                /* deref function descriptor */
-       mtctr   r4
+       mtctr   r12
        mr      r3,r24
        /*
         * it may be the case that other platforms have r4 right to
@@ -186,16 +184,16 @@ _GLOBAL(generic_secondary_thread_init)
        mr      r24,r3
 
        /* turn on 64-bit mode */
-       bl      .enable_64b_mode
+       bl      enable_64b_mode
 
        /* get a valid TOC pointer, wherever we're mapped at */
-       bl      .relative_toc
+       bl      relative_toc
        tovirt(r2,r2)
 
 #ifdef CONFIG_PPC_BOOK3E
        /* Book3E initialization */
        mr      r3,r24
-       bl      .book3e_secondary_thread_init
+       bl      book3e_secondary_thread_init
 #endif
        b       generic_secondary_common_init
 
@@ -214,17 +212,17 @@ _GLOBAL(generic_secondary_smp_init)
        mr      r25,r4
 
        /* turn on 64-bit mode */
-       bl      .enable_64b_mode
+       bl      enable_64b_mode
 
        /* get a valid TOC pointer, wherever we're mapped at */
-       bl      .relative_toc
+       bl      relative_toc
        tovirt(r2,r2)
 
 #ifdef CONFIG_PPC_BOOK3E
        /* Book3E initialization */
        mr      r3,r24
        mr      r4,r25
-       bl      .book3e_secondary_core_init
+       bl      book3e_secondary_core_init
 #endif
 
 generic_secondary_common_init:
@@ -236,7 +234,7 @@ generic_secondary_common_init:
        ld      r13,0(r13)              /* Get base vaddr of paca array  */
 #ifndef CONFIG_SMP
        addi    r13,r13,PACA_SIZE       /* know r13 if used accidentally */
-       b       .kexec_wait             /* wait for next kernel if !SMP  */
+       b       kexec_wait              /* wait for next kernel if !SMP  */
 #else
        LOAD_REG_ADDR(r7, nr_cpu_ids)   /* Load nr_cpu_ids address       */
        lwz     r7,0(r7)                /* also the max paca allocated   */
@@ -250,7 +248,7 @@ generic_secondary_common_init:
        blt     1b
 
        mr      r3,r24                  /* not found, copy phys to r3    */
-       b       .kexec_wait             /* next kernel might do better   */
+       b       kexec_wait              /* next kernel might do better   */
 
 2:     SET_PACA(r13)
 #ifdef CONFIG_PPC_BOOK3E
@@ -264,11 +262,13 @@ generic_secondary_common_init:
        /* See if we need to call a cpu state restore handler */
        LOAD_REG_ADDR(r23, cur_cpu_spec)
        ld      r23,0(r23)
-       ld      r23,CPU_SPEC_RESTORE(r23)
-       cmpdi   0,r23,0
+       ld      r12,CPU_SPEC_RESTORE(r23)
+       cmpdi   0,r12,0
        beq     3f
-       ld      r23,0(r23)
-       mtctr   r23
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
+       ld      r12,0(r12)
+#endif
+       mtctr   r12
        bctrl
 
 3:     LOAD_REG_ADDR(r3, spinning_secondaries) /* Decrement spinning_secondaries */
@@ -299,7 +299,7 @@ generic_secondary_common_init:
  * Assumes we're mapped EA == RA if the MMU is on.
  */
 #ifdef CONFIG_PPC_BOOK3S
-_STATIC(__mmu_off)
+__mmu_off:
        mfmsr   r3
        andi.   r0,r3,MSR_IR|MSR_DR
        beqlr
@@ -324,12 +324,12 @@ _STATIC(__mmu_off)
  *                 DT block, r4 is a physical pointer to the kernel itself
  *
  */
-_GLOBAL(__start_initialization_multiplatform)
+__start_initialization_multiplatform:
        /* Make sure we are running in 64 bits mode */
-       bl      .enable_64b_mode
+       bl      enable_64b_mode
 
        /* Get TOC pointer (current runtime address) */
-       bl      .relative_toc
+       bl      relative_toc
 
        /* find out where we are now */
        bcl     20,31,$+4
@@ -342,7 +342,7 @@ _GLOBAL(__start_initialization_multiplatform)
         */
        cmpldi  cr0,r5,0
        beq     1f
-       b       .__boot_from_prom               /* yes -> prom */
+       b       __boot_from_prom                /* yes -> prom */
 1:
        /* Save parameters */
        mr      r31,r3
@@ -354,8 +354,8 @@ _GLOBAL(__start_initialization_multiplatform)
 #endif
 
 #ifdef CONFIG_PPC_BOOK3E
-       bl      .start_initialization_book3e
-       b       .__after_prom_start
+       bl      start_initialization_book3e
+       b       __after_prom_start
 #else
        /* Setup some critical 970 SPRs before switching MMU off */
        mfspr   r0,SPRN_PVR
@@ -368,15 +368,15 @@ _GLOBAL(__start_initialization_multiplatform)
        beq     1f
        cmpwi   r0,0x45         /* 970GX */
        bne     2f
-1:     bl      .__cpu_preinit_ppc970
+1:     bl      __cpu_preinit_ppc970
 2:
 
        /* Switch off MMU if not already off */
-       bl      .__mmu_off
-       b       .__after_prom_start
+       bl      __mmu_off
+       b       __after_prom_start
 #endif /* CONFIG_PPC_BOOK3E */
 
-_INIT_STATIC(__boot_from_prom)
+__boot_from_prom:
 #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
        /* Save parameters */
        mr      r31,r3
@@ -395,7 +395,7 @@ _INIT_STATIC(__boot_from_prom)
 #ifdef CONFIG_RELOCATABLE
        /* Relocate code for where we are now */
        mr      r3,r26
-       bl      .relocate
+       bl      relocate
 #endif
 
        /* Restore parameters */
@@ -407,14 +407,14 @@ _INIT_STATIC(__boot_from_prom)
 
        /* Do all of the interaction with OF client interface */
        mr      r8,r26
-       bl      .prom_init
+       bl      prom_init
 #endif /* #CONFIG_PPC_OF_BOOT_TRAMPOLINE */
 
        /* We never return. We also hit that trap if trying to boot
         * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
        trap
 
-_STATIC(__after_prom_start)
+__after_prom_start:
 #ifdef CONFIG_RELOCATABLE
        /* process relocations for the final address of the kernel */
        lis     r25,PAGE_OFFSET@highest /* compute virtual base of kernel */
@@ -424,7 +424,7 @@ _STATIC(__after_prom_start)
        bne     1f
        add     r25,r25,r26
 1:     mr      r3,r25
-       bl      .relocate
+       bl      relocate
 #endif
 
 /*
@@ -464,12 +464,12 @@ _STATIC(__after_prom_start)
        lis     r5,(copy_to_here - _stext)@ha
        addi    r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */
 
-       bl      .copy_and_flush         /* copy the first n bytes        */
+       bl      copy_and_flush          /* copy the first n bytes        */
                                        /* this includes the code being  */
                                        /* executed here.                */
        addis   r8,r3,(4f - _stext)@ha  /* Jump to the copy of this code */
-       addi    r8,r8,(4f - _stext)@l   /* that we just made */
-       mtctr   r8
+       addi    r12,r8,(4f - _stext)@l  /* that we just made */
+       mtctr   r12
        bctr
 
 .balign 8
@@ -478,9 +478,9 @@ p_end:      .llong  _end - _stext
 4:     /* Now copy the rest of the kernel up to _end */
        addis   r5,r26,(p_end - _stext)@ha
        ld      r5,(p_end - _stext)@l(r5)       /* get _end */
-5:     bl      .copy_and_flush         /* copy the rest */
+5:     bl      copy_and_flush          /* copy the rest */
 
-9:     b       .start_here_multiplatform
+9:     b       start_here_multiplatform
 
 /*
  * Copy routine used to copy the kernel to start at physical address 0
@@ -544,7 +544,7 @@ __secondary_start_pmac_0:
        
 _GLOBAL(pmac_secondary_start)
        /* turn on 64-bit mode */
-       bl      .enable_64b_mode
+       bl      enable_64b_mode
 
        li      r0,0
        mfspr   r3,SPRN_HID4
@@ -556,11 +556,11 @@ _GLOBAL(pmac_secondary_start)
        slbia
 
        /* get TOC pointer (real address) */
-       bl      .relative_toc
+       bl      relative_toc
        tovirt(r2,r2)
 
        /* Copy some CPU settings from CPU 0 */
-       bl      .__restore_cpu_ppc970
+       bl      __restore_cpu_ppc970
 
        /* pSeries do that early though I don't think we really need it */
        mfmsr   r3
@@ -619,7 +619,7 @@ __secondary_start:
        std     r14,PACAKSAVE(r13)
 
        /* Do early setup for that CPU (stab, slb, hash table pointer) */
-       bl      .early_setup_secondary
+       bl      early_setup_secondary
 
        /*
         * setup the new stack pointer, but *don't* use this until
@@ -639,7 +639,7 @@ __secondary_start:
        stb     r0,PACAIRQHAPPENED(r13)
 
        /* enable MMU and jump to start_secondary */
-       LOAD_REG_ADDR(r3, .start_secondary_prolog)
+       LOAD_REG_ADDR(r3, start_secondary_prolog)
        LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
 
        mtspr   SPRN_SRR0,r3
@@ -652,11 +652,11 @@ __secondary_start:
  * zero the stack back-chain pointer and get the TOC virtual address
  * before going into C code.
  */
-_GLOBAL(start_secondary_prolog)
+start_secondary_prolog:
        ld      r2,PACATOC(r13)
        li      r3,0
        std     r3,0(r1)                /* Zero the stack frame pointer */
-       bl      .start_secondary
+       bl      start_secondary
        b       .
 /*
  * Reset stack pointer and call start_secondary
@@ -667,14 +667,14 @@ _GLOBAL(start_secondary_resume)
        ld      r1,PACAKSAVE(r13)       /* Reload kernel stack pointer */
        li      r3,0
        std     r3,0(r1)                /* Zero the stack frame pointer */
-       bl      .start_secondary
+       bl      start_secondary
        b       .
 #endif
 
 /*
  * This subroutine clobbers r11 and r12
  */
-_GLOBAL(enable_64b_mode)
+enable_64b_mode:
        mfmsr   r11                     /* grab the current MSR */
 #ifdef CONFIG_PPC_BOOK3E
        oris    r11,r11,0x8000          /* CM bit set, we'll set ICM later */
@@ -715,9 +715,9 @@ p_toc:      .llong  __toc_start + 0x8000 - 0b
 /*
  * This is where the main kernel code starts.
  */
-_INIT_STATIC(start_here_multiplatform)
+start_here_multiplatform:
        /* set up the TOC */
-       bl      .relative_toc
+       bl      relative_toc
        tovirt(r2,r2)
 
        /* Clear out the BSS. It may have been done in prom_init,
@@ -776,9 +776,9 @@ _INIT_STATIC(start_here_multiplatform)
 
        /* Restore parameters passed from prom_init/kexec */
        mr      r3,r31
-       bl      .early_setup            /* also sets r13 and SPRG_PACA */
+       bl      early_setup             /* also sets r13 and SPRG_PACA */
 
-       LOAD_REG_ADDR(r3, .start_here_common)
+       LOAD_REG_ADDR(r3, start_here_common)
        ld      r4,PACAKMSR(r13)
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
@@ -786,7 +786,8 @@ _INIT_STATIC(start_here_multiplatform)
        b       .       /* prevent speculative execution */
        
        /* This is where all platforms converge execution */
-_INIT_GLOBAL(start_here_common)
+
+start_here_common:
        /* relocation is on at this point */
        std     r1,PACAKSAVE(r13)
 
@@ -794,7 +795,7 @@ _INIT_GLOBAL(start_here_common)
        ld      r2,PACATOC(r13)
 
        /* Do more system initializations in virtual mode */
-       bl      .setup_system
+       bl      setup_system
 
        /* Mark interrupts soft and hard disabled (they might be enabled
         * in the PACA when doing hotplug)
@@ -805,7 +806,7 @@ _INIT_GLOBAL(start_here_common)
        stb     r0,PACAIRQHAPPENED(r13)
 
        /* Generic kernel entry */
-       bl      .start_kernel
+       bl      start_kernel
 
        /* Not reached */
        BUG_OPCODE
index bfb73cc209ceb3885f60a2ba873fb271940f414d..48c21acef915883aa08205e2d9388cef67f91b99 100644 (file)
@@ -43,7 +43,7 @@ _GLOBAL(\name)
         */
 #ifdef CONFIG_TRACE_IRQFLAGS
        stdu    r1,-128(r1)
-       bl      .trace_hardirqs_on
+       bl      trace_hardirqs_on
        addi    r1,r1,128
 #endif
        li      r0,1
index e3edaa189911b8232d2c0682b52dedd982f88ae0..f57a19348bddb4ec7f7bbf0f2bb2ff50aa292c97 100644 (file)
@@ -46,7 +46,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
        mflr    r0
        std     r0,16(r1)
        stdu    r1,-128(r1)
-       bl      .trace_hardirqs_on
+       bl      trace_hardirqs_on
        addi    r1,r1,128
        ld      r0,16(r1)
        mtlr    r0
index c3ab86975614a4a9d4af842962fa66f32c5c8e47..dca6e16c2436d79c588e417ca5e012b145c76cfe 100644 (file)
@@ -58,7 +58,7 @@ _GLOBAL(power7_powersave_common)
        /* Make sure FPU, VSX etc... are flushed as we may lose
         * state when going to nap mode
         */
-       bl      .discard_lazy_cpu_state
+       bl      discard_lazy_cpu_state
 #endif /* CONFIG_SMP */
 
        /* Hard disable interrupts */
@@ -168,7 +168,7 @@ _GLOBAL(power7_wakeup_loss)
 _GLOBAL(power7_wakeup_noloss)
        lbz     r0,PACA_NAPSTATELOST(r13)
        cmpwi   r0,0
-       bne     .power7_wakeup_loss
+       bne     power7_wakeup_loss
        ld      r1,PACAR1(r13)
        ld      r4,_MSR(r1)
        ld      r5,_NIP(r1)
index 40bd7bd4e19a88ee9b573c37deea8bc8694375b9..85fb16e64cef3e21e67869d31e8c950512726ddb 100644 (file)
@@ -71,8 +71,9 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
                                  phys_addr_t taddr, unsigned long irq,
                                  upf_t flags, int irq_check_parent)
 {
-       const __be32 *clk, *spd;
+       const __be32 *clk, *spd, *rs;
        u32 clock = BASE_BAUD * 16;
+       u32 shift = 0;
        int index;
 
        /* get clock freq. if present */
@@ -83,6 +84,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        /* get default speed if present */
        spd = of_get_property(np, "current-speed", NULL);
 
+       /* get register shift if present */
+       rs = of_get_property(np, "reg-shift", NULL);
+       if (rs && *rs)
+               shift = be32_to_cpup(rs);
+
        /* If we have a location index, then try to use it */
        if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
                index = want_index;
@@ -126,6 +132,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        legacy_serial_ports[index].uartclk = clock;
        legacy_serial_ports[index].irq = irq;
        legacy_serial_ports[index].flags = flags;
+       legacy_serial_ports[index].regshift = shift;
        legacy_serial_infos[index].taddr = taddr;
        legacy_serial_infos[index].np = of_node_get(np);
        legacy_serial_infos[index].clock = clock;
@@ -163,9 +170,8 @@ static int __init add_legacy_soc_port(struct device_node *np,
        if (of_get_property(np, "clock-frequency", NULL) == NULL)
                return -1;
 
-       /* if reg-shift or offset, don't try to use it */
-       if ((of_get_property(np, "reg-shift", NULL) != NULL) ||
-               (of_get_property(np, "reg-offset", NULL) != NULL))
+       /* if reg-offset don't try to use it */
+       if ((of_get_property(np, "reg-offset", NULL) != NULL))
                return -1;
 
        /* if rtas uses this device, don't try to use it as well */
@@ -315,17 +321,20 @@ static void __init setup_legacy_serial_console(int console)
        struct legacy_serial_info *info = &legacy_serial_infos[console];
        struct plat_serial8250_port *port = &legacy_serial_ports[console];
        void __iomem *addr;
+       unsigned int stride;
+
+       stride = 1 << port->regshift;
 
        /* Check if a translated MMIO address has been found */
        if (info->taddr) {
                addr = ioremap(info->taddr, 0x1000);
                if (addr == NULL)
                        return;
-               udbg_uart_init_mmio(addr, 1);
+               udbg_uart_init_mmio(addr, stride);
        } else {
                /* Check if it's PIO and we support untranslated PIO */
                if (port->iotype == UPIO_PORT && isa_io_special)
-                       udbg_uart_init_pio(port->iobase, 1);
+                       udbg_uart_init_pio(port->iobase, stride);
                else
                        return;
        }
index 3d0249599d524af2a8883cacc4df5d44716273b8..4e314b90c75d699edda82589c8a5a983bcc5dc6e 100644 (file)
@@ -34,7 +34,7 @@ _GLOBAL(call_do_softirq)
        std     r0,16(r1)
        stdu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
        mr      r1,r3
-       bl      .__do_softirq
+       bl      __do_softirq
        ld      r1,0(r1)
        ld      r0,16(r1)
        mtlr    r0
@@ -45,7 +45,7 @@ _GLOBAL(call_do_irq)
        std     r0,16(r1)
        stdu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
        mr      r1,r4
-       bl      .__do_irq
+       bl      __do_irq
        ld      r1,0(r1)
        ld      r0,16(r1)
        mtlr    r0
@@ -506,7 +506,7 @@ _GLOBAL(kexec_smp_wait)
        stb     r4,PACAKEXECSTATE(r13)
        SYNC
 
-       b       .kexec_wait
+       b       kexec_wait
 
 /*
  * switch to real mode (turn mmu off)
@@ -576,7 +576,7 @@ _GLOBAL(kexec_sequence)
 
        /* copy dest pages, flush whole dest image */
        mr      r3,r29
-       bl      .kexec_copy_flush       /* (image) */
+       bl      kexec_copy_flush        /* (image) */
 
        /* turn off mmu */
        bl      real_mode
@@ -586,7 +586,7 @@ _GLOBAL(kexec_sequence)
        mr      r4,r30          /* start, aka phys mem offset */
        li      r5,0x100
        li      r6,0
-       bl      .copy_and_flush /* (dest, src, copy limit, start offset) */
+       bl      copy_and_flush  /* (dest, src, copy limit, start offset) */
 1:     /* assume normal blr return */
 
        /* release other cpus to the new kernel secondary start at 0x60 */
@@ -595,8 +595,12 @@ _GLOBAL(kexec_sequence)
        stw     r6,kexec_flag-1b(5)
 
        /* clear out hardware hash page table and tlb */
-       ld      r5,0(r27)               /* deref function descriptor */
-       mtctr   r5
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
+       ld      r12,0(r27)              /* deref function descriptor */
+#else
+       mr      r12,r27
+#endif
+       mtctr   r12
        bctrl                           /* ppc_md.hpte_clear_all(void); */
 
 /*
@@ -630,3 +634,31 @@ _GLOBAL(kexec_sequence)
        li      r5,0
        blr     /* image->start(physid, image->start, 0); */
 #endif /* CONFIG_KEXEC */
+
+#ifdef CONFIG_MODULES
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+
+#ifdef CONFIG_MODVERSIONS
+.weak __crc_TOC.
+.section "___kcrctab+TOC.","a"
+.globl __kcrctab_TOC.
+__kcrctab_TOC.:
+       .llong  __crc_TOC.
+#endif
+
+/*
+ * Export a fake .TOC. since both modpost and depmod will complain otherwise.
+ * Both modpost and depmod strip the leading . so we do the same here.
+ */
+.section "__ksymtab_strings","a"
+__kstrtab_TOC.:
+       .asciz "TOC."
+
+.section "___ksymtab+TOC.","a"
+/* This symbol name is important: it's used by modpost to find exported syms */
+.globl __ksymtab_TOC.
+__ksymtab_TOC.:
+       .llong 0 /* .value */
+       .llong __kstrtab_TOC.
+#endif /* ELFv2 */
+#endif /* MODULES */
index 12664c130d73dd2d62fac4300f033de1a5242b7c..ef349d077129718eba1bb16eb65be1d96193a76f 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/vmalloc.h>
 #include <linux/ftrace.h>
 #include <linux/bug.h>
+#include <linux/uaccess.h>
 #include <asm/module.h>
 #include <asm/firmware.h>
 #include <asm/code-patching.h>
 #define DEBUGP(fmt , ...)
 #endif
 
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+#define R2_STACK_OFFSET 24
+
+/* An address is simply the address of the function. */
+typedef unsigned long func_desc_t;
+
+static func_desc_t func_desc(unsigned long addr)
+{
+       return addr;
+}
+static unsigned long func_addr(unsigned long addr)
+{
+       return addr;
+}
+static unsigned long stub_func_addr(func_desc_t func)
+{
+       return func;
+}
+
+/* PowerPC64 specific values for the Elf64_Sym st_other field.  */
+#define STO_PPC64_LOCAL_BIT    5
+#define STO_PPC64_LOCAL_MASK   (7 << STO_PPC64_LOCAL_BIT)
+#define PPC64_LOCAL_ENTRY_OFFSET(other)                                        \
+ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
+
+static unsigned int local_entry_offset(const Elf64_Sym *sym)
+{
+       /* sym->st_other indicates offset to local entry point
+        * (otherwise it will assume r12 is the address of the start
+        * of function and try to derive r2 from it). */
+       return PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
+}
+#else
+#define R2_STACK_OFFSET 40
+
+/* An address is address of the OPD entry, which contains address of fn. */
+typedef struct ppc64_opd_entry func_desc_t;
+
+static func_desc_t func_desc(unsigned long addr)
+{
+       return *(struct ppc64_opd_entry *)addr;
+}
+static unsigned long func_addr(unsigned long addr)
+{
+       return func_desc(addr).funcaddr;
+}
+static unsigned long stub_func_addr(func_desc_t func)
+{
+       return func.funcaddr;
+}
+static unsigned int local_entry_offset(const Elf64_Sym *sym)
+{
+       return 0;
+}
+#endif
+
 /* Like PPC32, we need little trampolines to do > 24-bit jumps (into
    the kernel itself).  But on PPC64, these need to be used for every
    jump, actually, to reset r2 (TOC+0x8000). */
 struct ppc64_stub_entry
 {
-       /* 28 byte jump instruction sequence (7 instructions) */
-       unsigned char jump[28];
-       unsigned char unused[4];
+       /* 28 byte jump instruction sequence (7 instructions). We only
+        * need 6 instructions on ABIv2 but we always allocate 7 so
+        * so we don't have to modify the trampoline load instruction. */
+       u32 jump[7];
+       u32 unused;
        /* Data for the above code */
-       struct ppc64_opd_entry opd;
+       func_desc_t funcdata;
 };
 
-/* We use a stub to fix up r2 (TOC ptr) and to jump to the (external)
-   function which may be more than 24-bits away.  We could simply
-   patch the new r2 value and function pointer into the stub, but it's
-   significantly shorter to put these values at the end of the stub
-   code, and patch the stub address (32-bits relative to the TOC ptr,
-   r2) into the stub. */
-static struct ppc64_stub_entry ppc64_stub =
-{ .jump = {
-#ifdef __LITTLE_ENDIAN__
-       0x00, 0x00, 0x82, 0x3d, /* addis   r12,r2, <high> */
-       0x00, 0x00, 0x8c, 0x39, /* addi    r12,r12, <low> */
-       /* Save current r2 value in magic place on the stack. */
-       0x28, 0x00, 0x41, 0xf8, /* std     r2,40(r1) */
-       0x20, 0x00, 0x6c, 0xe9, /* ld      r11,32(r12) */
-       0x28, 0x00, 0x4c, 0xe8, /* ld      r2,40(r12) */
-       0xa6, 0x03, 0x69, 0x7d, /* mtctr   r11 */
-       0x20, 0x04, 0x80, 0x4e  /* bctr */
-#else
-       0x3d, 0x82, 0x00, 0x00, /* addis   r12,r2, <high> */
-       0x39, 0x8c, 0x00, 0x00, /* addi    r12,r12, <low> */
+/*
+ * PPC64 uses 24 bit jumps, but we need to jump into other modules or
+ * the kernel which may be further.  So we jump to a stub.
+ *
+ * For ELFv1 we need to use this to set up the new r2 value (aka TOC
+ * pointer).  For ELFv2 it's the callee's responsibility to set up the
+ * new r2, but for both we need to save the old r2.
+ *
+ * We could simply patch the new r2 value and function pointer into
+ * the stub, but it's significantly shorter to put these values at the
+ * end of the stub code, and patch the stub address (32-bits relative
+ * to the TOC ptr, r2) into the stub.
+ */
+
+static u32 ppc64_stub_insns[] = {
+       0x3d620000,                     /* addis   r11,r2, <high> */
+       0x396b0000,                     /* addi    r11,r11, <low> */
        /* Save current r2 value in magic place on the stack. */
-       0xf8, 0x41, 0x00, 0x28, /* std     r2,40(r1) */
-       0xe9, 0x6c, 0x00, 0x20, /* ld      r11,32(r12) */
-       0xe8, 0x4c, 0x00, 0x28, /* ld      r2,40(r12) */
-       0x7d, 0x69, 0x03, 0xa6, /* mtctr   r11 */
-       0x4e, 0x80, 0x04, 0x20  /* bctr */
+       0xf8410000|R2_STACK_OFFSET,     /* std     r2,R2_STACK_OFFSET(r1) */
+       0xe98b0020,                     /* ld      r12,32(r11) */
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
+       /* Set up new r2 from function descriptor */
+       0xe84b0026,                     /* ld      r2,40(r11) */
+#endif
+       0x7d8903a6,                     /* mtctr   r12 */
+       0x4e800420                      /* bctr */
+};
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+static u32 ppc64_stub_mask[] = {
+       0xffff0000,
+       0xffff0000,
+       0xffffffff,
+       0xffffffff,
+#if !defined(_CALL_ELF) || _CALL_ELF != 2
+       0xffffffff,
+#endif
+       0xffffffff,
+       0xffffffff
+};
+
+bool is_module_trampoline(u32 *p)
+{
+       unsigned int i;
+       u32 insns[ARRAY_SIZE(ppc64_stub_insns)];
+
+       BUILD_BUG_ON(sizeof(ppc64_stub_insns) != sizeof(ppc64_stub_mask));
+
+       if (probe_kernel_read(insns, p, sizeof(insns)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(ppc64_stub_insns); i++) {
+               u32 insna = insns[i];
+               u32 insnb = ppc64_stub_insns[i];
+               u32 mask = ppc64_stub_mask[i];
+
+               if ((insna & mask) != (insnb & mask))
+                       return false;
+       }
+
+       return true;
+}
+
+int module_trampoline_target(struct module *mod, u32 *trampoline,
+                            unsigned long *target)
+{
+       u32 buf[2];
+       u16 upper, lower;
+       long offset;
+       void *toc_entry;
+
+       if (probe_kernel_read(buf, trampoline, sizeof(buf)))
+               return -EFAULT;
+
+       upper = buf[0] & 0xffff;
+       lower = buf[1] & 0xffff;
+
+       /* perform the addis/addi, both signed */
+       offset = ((short)upper << 16) + (short)lower;
+
+       /*
+        * Now get the address this trampoline jumps to. This
+        * is always 32 bytes into our trampoline stub.
+        */
+       toc_entry = (void *)mod->arch.toc + offset + 32;
+
+       if (probe_kernel_read(target, toc_entry, sizeof(*target)))
+               return -EFAULT;
+
+       return 0;
+}
+
 #endif
-} };
 
 /* Count how many different 24-bit relocations (different symbol,
    different addend) */
@@ -183,6 +308,7 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
        return relocs * sizeof(struct ppc64_stub_entry);
 }
 
+/* Still needed for ELFv2, for .TOC. */
 static void dedotify_versions(struct modversion_info *vers,
                              unsigned long size)
 {
@@ -193,7 +319,7 @@ static void dedotify_versions(struct modversion_info *vers,
                        memmove(vers->name, vers->name+1, strlen(vers->name));
 }
 
-/* Undefined symbols which refer to .funcname, hack to funcname */
+/* Undefined symbols which refer to .funcname, hack to funcname (or .TOC.) */
 static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
 {
        unsigned int i;
@@ -207,6 +333,24 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
        }
 }
 
+static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs,
+                              const char *strtab,
+                              unsigned int symindex)
+{
+       unsigned int i, numsyms;
+       Elf64_Sym *syms;
+
+       syms = (Elf64_Sym *)sechdrs[symindex].sh_addr;
+       numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym);
+
+       for (i = 1; i < numsyms; i++) {
+               if (syms[i].st_shndx == SHN_UNDEF
+                   && strcmp(strtab + syms[i].st_name, "TOC.") == 0)
+                       return &syms[i];
+       }
+       return NULL;
+}
+
 int module_frob_arch_sections(Elf64_Ehdr *hdr,
                              Elf64_Shdr *sechdrs,
                              char *secstrings,
@@ -271,21 +415,12 @@ static inline unsigned long my_r2(Elf64_Shdr *sechdrs, struct module *me)
 /* Patch stub to reference function and correct r2 value. */
 static inline int create_stub(Elf64_Shdr *sechdrs,
                              struct ppc64_stub_entry *entry,
-                             struct ppc64_opd_entry *opd,
+                             unsigned long addr,
                              struct module *me)
 {
-       Elf64_Half *loc1, *loc2;
        long reladdr;
 
-       *entry = ppc64_stub;
-
-#ifdef __LITTLE_ENDIAN__
-       loc1 = (Elf64_Half *)&entry->jump[0];
-       loc2 = (Elf64_Half *)&entry->jump[4];
-#else
-       loc1 = (Elf64_Half *)&entry->jump[2];
-       loc2 = (Elf64_Half *)&entry->jump[6];
-#endif
+       memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
 
        /* Stub uses address relative to r2. */
        reladdr = (unsigned long)entry - my_r2(sechdrs, me);
@@ -296,35 +431,33 @@ static inline int create_stub(Elf64_Shdr *sechdrs,
        }
        DEBUGP("Stub %p get data from reladdr %li\n", entry, reladdr);
 
-       *loc1 = PPC_HA(reladdr);
-       *loc2 = PPC_LO(reladdr);
-       entry->opd.funcaddr = opd->funcaddr;
-       entry->opd.r2 = opd->r2;
+       entry->jump[0] |= PPC_HA(reladdr);
+       entry->jump[1] |= PPC_LO(reladdr);
+       entry->funcdata = func_desc(addr);
        return 1;
 }
 
-/* Create stub to jump to function described in this OPD: we need the
+/* Create stub to jump to function described in this OPD/ptr: we need the
    stub to set up the TOC ptr (r2) for the function. */
 static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
-                                  unsigned long opdaddr,
+                                  unsigned long addr,
                                   struct module *me)
 {
        struct ppc64_stub_entry *stubs;
-       struct ppc64_opd_entry *opd = (void *)opdaddr;
        unsigned int i, num_stubs;
 
        num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stubs);
 
        /* Find this stub, or if that fails, the next avail. entry */
        stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr;
-       for (i = 0; stubs[i].opd.funcaddr; i++) {
+       for (i = 0; stub_func_addr(stubs[i].funcdata); i++) {
                BUG_ON(i >= num_stubs);
 
-               if (stubs[i].opd.funcaddr == opd->funcaddr)
+               if (stub_func_addr(stubs[i].funcdata) == func_addr(addr))
                        return (unsigned long)&stubs[i];
        }
 
-       if (!create_stub(sechdrs, &stubs[i], opd, me))
+       if (!create_stub(sechdrs, &stubs[i], addr, me))
                return 0;
 
        return (unsigned long)&stubs[i];
@@ -339,7 +472,8 @@ static int restore_r2(u32 *instruction, struct module *me)
                       me->name, *instruction);
                return 0;
        }
-       *instruction = 0xe8410028;      /* ld r2,40(r1) */
+       /* ld r2,R2_STACK_OFFSET(r1) */
+       *instruction = 0xe8410000 | R2_STACK_OFFSET;
        return 1;
 }
 
@@ -357,6 +491,17 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 
        DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
               sechdrs[relsec].sh_info);
+
+       /* First time we're called, we can fix up .TOC. */
+       if (!me->arch.toc_fixed) {
+               sym = find_dot_toc(sechdrs, strtab, symindex);
+               /* It's theoretically possible that a module doesn't want a
+                * .TOC. so don't fail it just for that. */
+               if (sym)
+                       sym->st_value = my_r2(sechdrs, me);
+               me->arch.toc_fixed = true;
+       }
+
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
                /* This is where to make the change */
                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -453,7 +598,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                                        return -ENOENT;
                                if (!restore_r2((u32 *)location + 1, me))
                                        return -ENOEXEC;
-                       }
+                       } else
+                               value += local_entry_offset(sym);
 
                        /* Convert value to relative */
                        value -= (unsigned long)location;
@@ -474,6 +620,31 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        *location = value - (unsigned long)location;
                        break;
 
+               case R_PPC64_TOCSAVE:
+                       /*
+                        * Marker reloc indicates we don't have to save r2.
+                        * That would only save us one instruction, so ignore
+                        * it.
+                        */
+                       break;
+
+               case R_PPC64_REL16_HA:
+                       /* Subtract location pointer */
+                       value -= (unsigned long)location;
+                       value = ((value + 0x8000) >> 16);
+                       *((uint16_t *) location)
+                               = (*((uint16_t *) location) & ~0xffff)
+                               | (value & 0xffff);
+                       break;
+
+               case R_PPC64_REL16_LO:
+                       /* Subtract location pointer */
+                       value -= (unsigned long)location;
+                       *((uint16_t *) location)
+                               = (*((uint16_t *) location) & ~0xffff)
+                               | (value & 0xffff);
+                       break;
+
                default:
                        printk("%s: Unknown ADD relocation: %lu\n",
                               me->name,
index d9476c1fc9596132d27bc68d5795e2b6a3ee8a6a..add166aa806a13e124933e49b35ccfdde305aa36 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -120,6 +121,25 @@ resource_size_t pcibios_window_alignment(struct pci_bus *bus,
        return 1;
 }
 
+void pcibios_reset_secondary_bus(struct pci_dev *dev)
+{
+       u16 ctrl;
+
+       if (ppc_md.pcibios_reset_secondary_bus) {
+               ppc_md.pcibios_reset_secondary_bus(dev);
+               return;
+       }
+
+       pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+       ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+       msleep(2);
+
+       ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+       ssleep(1);
+}
+
 static resource_size_t pcibios_io_size(const struct pci_controller *hose)
 {
 #ifdef CONFIG_PPC64
@@ -666,60 +686,36 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
 void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                  struct device_node *dev, int primary)
 {
-       const __be32 *ranges;
-       int rlen;
-       int pna = of_n_addr_cells(dev);
-       int np = pna + 5;
        int memno = 0;
-       u32 pci_space;
-       unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
        struct resource *res;
+       struct of_pci_range range;
+       struct of_pci_range_parser parser;
 
        printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
               dev->full_name, primary ? "(primary)" : "");
 
-       /* Get ranges property */
-       ranges = of_get_property(dev, "ranges", &rlen);
-       if (ranges == NULL)
+       /* Check for ranges property */
+       if (of_pci_range_parser_init(&parser, dev))
                return;
 
        /* Parse it */
-       while ((rlen -= np * 4) >= 0) {
-               /* Read next ranges element */
-               pci_space = of_read_number(ranges, 1);
-               pci_addr = of_read_number(ranges + 1, 2);
-               cpu_addr = of_translate_address(dev, ranges + 3);
-               size = of_read_number(ranges + pna + 3, 2);
-               ranges += np;
-
+       for_each_of_pci_range(&parser, &range) {
                /* If we failed translation or got a zero-sized region
                 * (some FW try to feed us with non sensical zero sized regions
                 * such as power3 which look like some kind of attempt at exposing
                 * the VGA memory hole)
                 */
-               if (cpu_addr == OF_BAD_ADDR || size == 0)
+               if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
                        continue;
 
-               /* Now consume following elements while they are contiguous */
-               for (; rlen >= np * sizeof(u32);
-                    ranges += np, rlen -= np * 4) {
-                       if (of_read_number(ranges, 1) != pci_space)
-                               break;
-                       pci_next = of_read_number(ranges + 1, 2);
-                       cpu_next = of_translate_address(dev, ranges + 3);
-                       if (pci_next != pci_addr + size ||
-                           cpu_next != cpu_addr + size)
-                               break;
-                       size += of_read_number(ranges + pna + 3, 2);
-               }
-
                /* Act based on address space type */
                res = NULL;
-               switch ((pci_space >> 24) & 0x3) {
-               case 1:         /* PCI IO space */
+               switch (range.flags & IORESOURCE_TYPE_BITS) {
+               case IORESOURCE_IO:
                        printk(KERN_INFO
                               "  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
-                              cpu_addr, cpu_addr + size - 1, pci_addr);
+                              range.cpu_addr, range.cpu_addr + range.size - 1,
+                              range.pci_addr);
 
                        /* We support only one IO range */
                        if (hose->pci_io_size) {
@@ -729,11 +725,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        }
 #ifdef CONFIG_PPC32
                        /* On 32 bits, limit I/O space to 16MB */
-                       if (size > 0x01000000)
-                               size = 0x01000000;
+                       if (range.size > 0x01000000)
+                               range.size = 0x01000000;
 
                        /* 32 bits needs to map IOs here */
-                       hose->io_base_virt = ioremap(cpu_addr, size);
+                       hose->io_base_virt = ioremap(range.cpu_addr,
+                                               range.size);
 
                        /* Expect trouble if pci_addr is not 0 */
                        if (primary)
@@ -743,20 +740,20 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        /* pci_io_size and io_base_phys always represent IO
                         * space starting at 0 so we factor in pci_addr
                         */
-                       hose->pci_io_size = pci_addr + size;
-                       hose->io_base_phys = cpu_addr - pci_addr;
+                       hose->pci_io_size = range.pci_addr + range.size;
+                       hose->io_base_phys = range.cpu_addr - range.pci_addr;
 
                        /* Build resource */
                        res = &hose->io_resource;
-                       res->flags = IORESOURCE_IO;
-                       res->start = pci_addr;
+                       range.cpu_addr = range.pci_addr;
                        break;
-               case 2:         /* PCI Memory space */
-               case 3:         /* PCI 64 bits Memory space */
+               case IORESOURCE_MEM:
                        printk(KERN_INFO
                               " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
-                              cpu_addr, cpu_addr + size - 1, pci_addr,
-                              (pci_space & 0x40000000) ? "Prefetch" : "");
+                              range.cpu_addr, range.cpu_addr + range.size - 1,
+                              range.pci_addr,
+                              (range.pci_space & 0x40000000) ?
+                              "Prefetch" : "");
 
                        /* We support only 3 memory ranges */
                        if (memno >= 3) {
@@ -765,28 +762,21 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                continue;
                        }
                        /* Handles ISA memory hole space here */
-                       if (pci_addr == 0) {
+                       if (range.pci_addr == 0) {
                                if (primary || isa_mem_base == 0)
-                                       isa_mem_base = cpu_addr;
-                               hose->isa_mem_phys = cpu_addr;
-                               hose->isa_mem_size = size;
+                                       isa_mem_base = range.cpu_addr;
+                               hose->isa_mem_phys = range.cpu_addr;
+                               hose->isa_mem_size = range.size;
                        }
 
                        /* Build resource */
-                       hose->mem_offset[memno] = cpu_addr - pci_addr;
+                       hose->mem_offset[memno] = range.cpu_addr -
+                                                       range.pci_addr;
                        res = &hose->mem_resources[memno++];
-                       res->flags = IORESOURCE_MEM;
-                       if (pci_space & 0x40000000)
-                               res->flags |= IORESOURCE_PREFETCH;
-                       res->start = cpu_addr;
                        break;
                }
                if (res != NULL) {
-                       res->name = dev->full_name;
-                       res->end = res->start + size - 1;
-                       res->parent = NULL;
-                       res->sibling = NULL;
-                       res->child = NULL;
+                       of_pci_range_to_resource(&range, dev, res);
                }
        }
 }
index 83c26d829991e8b8c118d6fa8d8d5bb7ffc68fda..ea6470c21f4e4e86152093c6126990a73544bf62 100644 (file)
@@ -304,6 +304,9 @@ static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus,
        struct pci_dev *dev = NULL;
        const __be32 *reg;
        int reglen, devfn;
+#ifdef CONFIG_EEH
+       struct eeh_dev *edev = of_node_to_eeh_dev(dn);
+#endif
 
        pr_debug("  * %s\n", dn->full_name);
        if (!of_device_is_available(dn))
@@ -321,6 +324,12 @@ static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus,
                return dev;
        }
 
+       /* Device removed permanently ? */
+#ifdef CONFIG_EEH
+       if (edev && (edev->mode & EEH_DEV_REMOVED))
+               return NULL;
+#endif
+
        /* create a new pci_dev for this device */
        dev = of_create_pci_dev(dn, bus, devfn);
        if (!dev)
index 3bd77edd7610ce20267a880069972624eafed62e..48d17d6fca5b6e43ab1c77759f04a87f90c5aa2c 100644 (file)
@@ -120,6 +120,7 @@ EXPORT_SYMBOL(giveup_spe);
 EXPORT_SYMBOL(flush_instruction_cache);
 #endif
 EXPORT_SYMBOL(flush_dcache_range);
+EXPORT_SYMBOL(flush_icache_range);
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PPC32
@@ -154,9 +155,7 @@ EXPORT_SYMBOL(__cmpdi2);
 #endif
 long long __bswapdi2(long long);
 EXPORT_SYMBOL(__bswapdi2);
-#ifdef __BIG_ENDIAN__
 EXPORT_SYMBOL(memcpy);
-#endif
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memcmp);
index 31d021506d210e6b7cf1fa4136b1067f8163dc05..2ae1b99166c63895784539f1c87a7488278ddf05 100644 (file)
@@ -54,6 +54,7 @@
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #endif
+#include <asm/code-patching.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 
@@ -1108,7 +1109,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                struct thread_info *ti = (void *)task_stack_page(p);
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->gpr[1] = sp + sizeof(struct pt_regs);
-               childregs->gpr[14] = usp;       /* function */
+               /* function */
+               if (usp)
+                       childregs->gpr[14] = ppc_function_entry((void *)usp);
 #ifdef CONFIG_PPC64
                clear_tsk_thread_flag(p, TIF_32BIT);
                childregs->softe = 1;
@@ -1187,17 +1190,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        if (cpu_has_feature(CPU_FTR_HAS_PPR))
                p->thread.ppr = INIT_PPR;
 #endif
-       /*
-        * The PPC64 ABI makes use of a TOC to contain function 
-        * pointers.  The function (ret_from_except) is actually a pointer
-        * to the TOC entry.  The first entry is a pointer to the actual
-        * function.
-        */
-#ifdef CONFIG_PPC64
-       kregs->nip = *((unsigned long *)f);
-#else
-       kregs->nip = (unsigned long)f;
-#endif
+       kregs->nip = ppc_function_entry(f);
        return 0;
 }
 
index b0c263da219a2b4a0bcfc7ed09b69c26cb12432c..77aa1e95e9046d39908048d8a711c44c83841415 100644 (file)
@@ -23,7 +23,7 @@ strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224
 reloc_got2 kernstart_addr memstart_addr linux_banner _stext
 opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry
 boot_command_line __prom_init_toc_start __prom_init_toc_end
-btext_setup_display"
+btext_setup_display TOC."
 
 NM="$1"
 OBJ="$2"
index 2f3cdb01506de3d7791712ecd6ffeaf1fcd36352..658e89d2025b0b2dd65bb812d2c89d65867c1015 100644 (file)
@@ -705,7 +705,7 @@ static int __init rtas_flash_init(void)
        if (rtas_token("ibm,update-flash-64-and-reboot") ==
                       RTAS_UNKNOWN_SERVICE) {
                pr_info("rtas_flash: no firmware flash support\n");
-               return 1;
+               return -EINVAL;
        }
 
        rtas_validate_flash_data.buf = kzalloc(VALIDATE_BUF_SIZE, GFP_KERNEL);
index 7d4c7172f38ed43d85873c23f5b1e63e733ea093..c168337aef9dd3ccc48c70a00a41d19f4bc3f92d 100644 (file)
@@ -80,10 +80,6 @@ int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val)
        if (ret)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       if (returnval == EEH_IO_ERROR_VALUE(size) &&
-           eeh_dev_check_failure(of_node_to_eeh_dev(pdn->node)))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
        return PCIBIOS_SUCCESSFUL;
 }
 
@@ -92,18 +88,39 @@ static int rtas_pci_read_config(struct pci_bus *bus,
                                int where, int size, u32 *val)
 {
        struct device_node *busdn, *dn;
-
-       busdn = pci_bus_to_OF_node(bus);
+       struct pci_dn *pdn;
+       bool found = false;
+#ifdef CONFIG_EEH
+       struct eeh_dev *edev;
+#endif
+       int ret;
 
        /* Search only direct children of the bus */
+       *val = 0xFFFFFFFF;
+       busdn = pci_bus_to_OF_node(bus);
        for (dn = busdn->child; dn; dn = dn->sibling) {
-               struct pci_dn *pdn = PCI_DN(dn);
+               pdn = PCI_DN(dn);
                if (pdn && pdn->devfn == devfn
-                   && of_device_is_available(dn))
-                       return rtas_read_config(pdn, where, size, val);
+                   && of_device_is_available(dn)) {
+                       found = true;
+                       break;
+               }
        }
 
-       return PCIBIOS_DEVICE_NOT_FOUND;
+       if (!found)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+#ifdef CONFIG_EEH
+       edev = of_node_to_eeh_dev(dn);
+       if (edev && edev->pe && edev->pe->state & EEH_PE_RESET)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+#endif
+
+       ret = rtas_read_config(pdn, where, size, val);
+       if (*val == EEH_IO_ERROR_VALUE(size) &&
+           eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return ret;
 }
 
 int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val)
@@ -136,17 +153,34 @@ static int rtas_pci_write_config(struct pci_bus *bus,
                                 int where, int size, u32 val)
 {
        struct device_node *busdn, *dn;
-
-       busdn = pci_bus_to_OF_node(bus);
+       struct pci_dn *pdn;
+       bool found = false;
+#ifdef CONFIG_EEH
+       struct eeh_dev *edev;
+#endif
+       int ret;
 
        /* Search only direct children of the bus */
+       busdn = pci_bus_to_OF_node(bus);
        for (dn = busdn->child; dn; dn = dn->sibling) {
-               struct pci_dn *pdn = PCI_DN(dn);
+               pdn = PCI_DN(dn);
                if (pdn && pdn->devfn == devfn
-                   && of_device_is_available(dn))
-                       return rtas_write_config(pdn, where, size, val);
+                   && of_device_is_available(dn)) {
+                       found = true;
+                       break;
+               }
        }
-       return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (!found)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+#ifdef CONFIG_EEH
+       edev = of_node_to_eeh_dev(dn);
+       if (edev && edev->pe && (edev->pe->state & EEH_PE_RESET))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+#endif
+       ret = rtas_write_config(pdn, where, size, val);
+
+       return ret;
 }
 
 static struct pci_ops rtas_pci_ops = {
index 79b7612ac6fa34f7e1d77c1db95f399f7be3bcc1..3cf25c89469dbbf1d1dbc8902313172d910e2754 100644 (file)
@@ -212,6 +212,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 {
        unsigned long cpu_id = (unsigned long)v - 1;
        unsigned int pvr;
+       unsigned long proc_freq;
        unsigned short maj;
        unsigned short min;
 
@@ -263,12 +264,19 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 #endif /* CONFIG_TAU */
 
        /*
-        * Assume here that all clock rates are the same in a
-        * smp system.  -- Cort
+        * Platforms that have variable clock rates, should implement
+        * the method ppc_md.get_proc_freq() that reports the clock
+        * rate of a given cpu. The rest can use ppc_proc_freq to
+        * report the clock rate that is same across all cpus.
         */
-       if (ppc_proc_freq)
+       if (ppc_md.get_proc_freq)
+               proc_freq = ppc_md.get_proc_freq(cpu_id);
+       else
+               proc_freq = ppc_proc_freq;
+
+       if (proc_freq)
                seq_printf(m, "clock\t\t: %lu.%06luMHz\n",
-                          ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
+                          proc_freq / 1000000, proc_freq % 1000000);
 
        if (ppc_md.show_percpuinfo != NULL)
                ppc_md.show_percpuinfo(m, cpu_id);
index fbe24377eda3e4f268d6074e0803dd0891c8c416..90b532ace0d5802b860e2344333f3ec32de91ea8 100644 (file)
@@ -341,7 +341,7 @@ void smp_release_cpus(void)
 
        ptr  = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
                        - PHYSICAL_START);
-       *ptr = __pa(generic_secondary_smp_init);
+       *ptr = ppc_function_entry(generic_secondary_smp_init);
 
        /* And wait a bit for them to catch up */
        for (i = 0; i < 100000; i++) {
index 93219c34af327b3e113a344485310b8f2923a879..895c50ca943c9527656609956119160ae53a5230 100644 (file)
 #include <asm/ppc_asm.h>
 
 #ifdef CONFIG_PPC64
-#define SYSCALL(func)          .llong  .sys_##func,.sys_##func
-#define COMPAT_SYS(func)       .llong  .sys_##func,.compat_sys_##func
-#define PPC_SYS(func)          .llong  .ppc_##func,.ppc_##func
-#define OLDSYS(func)           .llong  .sys_ni_syscall,.sys_ni_syscall
-#define SYS32ONLY(func)                .llong  .sys_ni_syscall,.compat_sys_##func
-#define SYSX(f, f3264, f32)    .llong  .f,.f3264
+#define SYSCALL(func)          .llong  DOTSYM(sys_##func),DOTSYM(sys_##func)
+#define COMPAT_SYS(func)       .llong  DOTSYM(sys_##func),DOTSYM(compat_sys_##func)
+#define PPC_SYS(func)          .llong  DOTSYM(ppc_##func),DOTSYM(ppc_##func)
+#define OLDSYS(func)           .llong  DOTSYM(sys_ni_syscall),DOTSYM(sys_ni_syscall)
+#define SYS32ONLY(func)                .llong  DOTSYM(sys_ni_syscall),DOTSYM(compat_sys_##func)
+#define SYSX(f, f3264, f32)    .llong  DOTSYM(f),DOTSYM(f3264)
 #else
 #define SYSCALL(func)          .long   sys_##func
 #define COMPAT_SYS(func)       .long   sys_##func
@@ -36,6 +36,8 @@
 #define PPC_SYS_SPU(func)      PPC_SYS(func)
 #define SYSX_SPU(f, f3264, f32)        SYSX(f, f3264, f32)
 
+.section .rodata,"a"
+
 #ifdef CONFIG_PPC64
 #define sys_sigpending sys_ni_syscall
 #define sys_old_getrlimit sys_ni_syscall
@@ -43,5 +45,7 @@
        .p2align        3
 #endif
 
-_GLOBAL(sys_call_table)
+.globl sys_call_table
+sys_call_table:
+
 #include <asm/systbl.h>
index 03567c05950a3cf5ee465ef0d3a8e540ad5594a8..ee061c3715deb0b66247247938a60a46d34e5131 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/ppc-opcode.h>
 #include <asm/ptrace.h>
 #include <asm/reg.h>
+#include <asm/bug.h>
 
 #ifdef CONFIG_VSX
 /* See fpu.S, this is borrowed from there */
@@ -41,7 +42,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX);           \
 /* Stack frame offsets for local variables. */
 #define TM_FRAME_L0    TM_FRAME_SIZE-16
 #define TM_FRAME_L1    TM_FRAME_SIZE-8
-#define STACK_PARAM(x) (48+((x)*8))
 
 
 /* In order to access the TM SPRs, TM must be enabled.  So, do so: */
@@ -108,12 +108,12 @@ _GLOBAL(tm_reclaim)
        mflr    r0
        stw     r6, 8(r1)
        std     r0, 16(r1)
-       std     r2, 40(r1)
+       std     r2, STK_GOT(r1)
        stdu    r1, -TM_FRAME_SIZE(r1)
 
        /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. */
 
-       std     r3, STACK_PARAM(0)(r1)
+       std     r3, STK_PARAM(R3)(r1)
        SAVE_NVGPRS(r1)
 
        /* We need to setup MSR for VSX register save instructions.  Here we
@@ -175,6 +175,13 @@ dont_backup_vec:
        stfd    fr0,FPSTATE_FPSCR(r7)
 
 dont_backup_fp:
+       /* Do sanity check on MSR to make sure we are suspended */
+       li      r7, (MSR_TS_S)@higher
+       srdi    r6, r14, 32
+       and     r6, r6, r7
+1:     tdeqi   r6, 0
+       EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0
+
        /* The moment we treclaim, ALL of our GPRs will switch
         * to user register state.  (FPRs, CCR etc. also!)
         * Use an sprg and a tm_scratch in the PACA to shuffle.
@@ -202,7 +209,7 @@ dont_backup_fp:
        /* 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 * */
+       ld      r12, STK_PARAM(R3)(r1)          /* Param 0, thread_struct * */
 
        std     r11, THREAD_TM_PPR(r12)         /* Store PPR and free r11 */
 
@@ -289,7 +296,7 @@ dont_backup_fp:
        ld      r0, 16(r1)
        mtcr    r4
        mtlr    r0
-       ld      r2, 40(r1)
+       ld      r2, STK_GOT(r1)
 
        /* Load system default DSCR */
        ld      r4, DSCR_DEFAULT@toc(r2)
@@ -312,7 +319,7 @@ _GLOBAL(__tm_recheckpoint)
        mflr    r0
        stw     r5, 8(r1)
        std     r0, 16(r1)
-       std     r2, 40(r1)
+       std     r2, STK_GOT(r1)
        stdu    r1, -TM_FRAME_SIZE(r1)
 
        /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD].
@@ -320,8 +327,6 @@ _GLOBAL(__tm_recheckpoint)
         */
        SAVE_NVGPRS(r1)
 
-       std     r1, PACAR1(r13)
-
        /* Load complete register state from ts_ckpt* registers */
 
        addi    r7, r3, PT_CKPT_REGS            /* Thread's ckpt_regs */
@@ -385,12 +390,10 @@ restore_gprs:
        /* ******************** CR,LR,CCR,MSR ********** */
        ld      r4, _CTR(r7)
        ld      r5, _LINK(r7)
-       ld      r6, _CCR(r7)
        ld      r8, _XER(r7)
 
        mtctr   r4
        mtlr    r5
-       mtcr    r6
        mtxer   r8
 
        /* ******************** TAR ******************** */
@@ -406,7 +409,8 @@ restore_gprs:
        li      r4, 0
        mtmsrd  r4, 1
 
-       REST_4GPRS(0, r7)                       /* GPR0-3 */
+       REST_GPR(0, r7)                         /* GPR0 */
+       REST_2GPRS(2, r7)                       /* GPR2-3 */
        REST_GPR(4, r7)                         /* GPR4 */
        REST_4GPRS(8, r7)                       /* GPR8-11 */
        REST_2GPRS(12, r7)                      /* GPR12-13 */
@@ -418,6 +422,31 @@ restore_gprs:
        mtspr   SPRN_DSCR, r5
        mtspr   SPRN_PPR, r6
 
+       /* Do final sanity check on TEXASR to make sure FS is set.  Do this
+        * here before we load up the userspace r1 so any bugs we hit will get
+        * a call chain */
+       mfspr   r5, SPRN_TEXASR
+       srdi    r5, r5, 16
+       li      r6, (TEXASR_FS)@h
+       and     r6, r6, r5
+1:     tdeqi   r6, 0
+       EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0
+
+       /* Do final sanity check on MSR to make sure we are not transactional
+        * or suspended
+        */
+       mfmsr   r6
+       li      r5, (MSR_TS_MASK)@higher
+       srdi    r6, r6, 32
+       and     r6, r6, r5
+1:     tdnei   r6, 0
+       EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0
+
+       /* Restore CR */
+       ld      r6, _CCR(r7)
+       mtcr    r6
+
+       REST_GPR(1, r7)                         /* GPR1 */
        REST_GPR(5, r7)                         /* GPR5-7 */
        REST_GPR(6, r7)
        ld      r7, GPR7(r7)
@@ -448,7 +477,7 @@ restore_gprs:
        ld      r0, 16(r1)
        mtcr    r4
        mtlr    r0
-       ld      r2, 40(r1)
+       ld      r2, STK_GOT(r1)
 
        /* Load system default DSCR */
        ld      r4, DSCR_DEFAULT@toc(r2)
index e18e3cfc32debeb21248301c078c229ab59c5e8e..8c86422a1e37a706627dac1ac49ea19ed89a0ee7 100644 (file)
@@ -171,7 +171,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
 #endif /* CONFIG_SMP */
 
        /* Jump to partition switch code */
-       bl      .kvmppc_hv_entry_trampoline
+       bl      kvmppc_hv_entry_trampoline
        nop
 
 /*
index ffbb871c2bd803827fa5a78658f29d2fa8a1dbd6..9f0ad718e4766bd2b114d4314def16a46b304ebe 100644 (file)
@@ -242,6 +242,12 @@ kvm_novcpu_exit:
  */
        .globl  kvm_start_guest
 kvm_start_guest:
+
+       /* Set runlatch bit the minute you wake up from nap */
+       mfspr   r1, SPRN_CTRLF
+       ori     r1, r1, 1
+       mtspr   SPRN_CTRLT, r1
+
        ld      r2,PACATOC(r13)
 
        li      r0,KVM_HWTHREAD_IN_KVM
@@ -309,6 +315,11 @@ kvm_no_guest:
        li      r0, KVM_HWTHREAD_IN_NAP
        stb     r0, HSTATE_HWTHREAD_STATE(r13)
 kvm_do_nap:
+       /* Clear the runlatch bit before napping */
+       mfspr   r2, SPRN_CTRLF
+       clrrdi  r2, r2, 1
+       mtspr   SPRN_CTRLT, r2
+
        li      r3, LPCR_PECE0
        mfspr   r4, SPRN_LPCR
        rlwimi  r4, r3, 0, LPCR_PECE0 | LPCR_PECE1
@@ -1647,7 +1658,7 @@ kvmppc_hdsi:
        /* Search the hash table. */
        mr      r3, r9                  /* vcpu pointer */
        li      r7, 1                   /* data fault */
-       bl      .kvmppc_hpte_hv_fault
+       bl      kvmppc_hpte_hv_fault
        ld      r9, HSTATE_KVM_VCPU(r13)
        ld      r10, VCPU_PC(r9)
        ld      r11, VCPU_MSR(r9)
@@ -1721,7 +1732,7 @@ kvmppc_hisi:
        mr      r4, r10
        mr      r6, r11
        li      r7, 0                   /* instruction fault */
-       bl      .kvmppc_hpte_hv_fault
+       bl      kvmppc_hpte_hv_fault
        ld      r9, HSTATE_KVM_VCPU(r13)
        ld      r10, VCPU_PC(r9)
        ld      r11, VCPU_MSR(r9)
@@ -1795,16 +1806,16 @@ hcall_real_fallback:
        .globl  hcall_real_table
 hcall_real_table:
        .long   0               /* 0 - unused */
-       .long   .kvmppc_h_remove - hcall_real_table
-       .long   .kvmppc_h_enter - hcall_real_table
-       .long   .kvmppc_h_read - hcall_real_table
+       .long   DOTSYM(kvmppc_h_remove) - hcall_real_table
+       .long   DOTSYM(kvmppc_h_enter) - hcall_real_table
+       .long   DOTSYM(kvmppc_h_read) - hcall_real_table
        .long   0               /* 0x10 - H_CLEAR_MOD */
        .long   0               /* 0x14 - H_CLEAR_REF */
-       .long   .kvmppc_h_protect - hcall_real_table
-       .long   .kvmppc_h_get_tce - hcall_real_table
-       .long   .kvmppc_h_put_tce - hcall_real_table
+       .long   DOTSYM(kvmppc_h_protect) - hcall_real_table
+       .long   DOTSYM(kvmppc_h_get_tce) - hcall_real_table
+       .long   DOTSYM(kvmppc_h_put_tce) - hcall_real_table
        .long   0               /* 0x24 - H_SET_SPRG0 */
-       .long   .kvmppc_h_set_dabr - hcall_real_table
+       .long   DOTSYM(kvmppc_h_set_dabr) - hcall_real_table
        .long   0               /* 0x2c */
        .long   0               /* 0x30 */
        .long   0               /* 0x34 */
@@ -1820,11 +1831,11 @@ hcall_real_table:
        .long   0               /* 0x5c */
        .long   0               /* 0x60 */
 #ifdef CONFIG_KVM_XICS
-       .long   .kvmppc_rm_h_eoi - hcall_real_table
-       .long   .kvmppc_rm_h_cppr - hcall_real_table
-       .long   .kvmppc_rm_h_ipi - hcall_real_table
+       .long   DOTSYM(kvmppc_rm_h_eoi) - hcall_real_table
+       .long   DOTSYM(kvmppc_rm_h_cppr) - hcall_real_table
+       .long   DOTSYM(kvmppc_rm_h_ipi) - hcall_real_table
        .long   0               /* 0x70 - H_IPOLL */
-       .long   .kvmppc_rm_h_xirr - hcall_real_table
+       .long   DOTSYM(kvmppc_rm_h_xirr) - hcall_real_table
 #else
        .long   0               /* 0x64 - H_EOI */
        .long   0               /* 0x68 - H_CPPR */
@@ -1858,7 +1869,7 @@ hcall_real_table:
        .long   0               /* 0xd4 */
        .long   0               /* 0xd8 */
        .long   0               /* 0xdc */
-       .long   .kvmppc_h_cede - hcall_real_table
+       .long   DOTSYM(kvmppc_h_cede) - hcall_real_table
        .long   0               /* 0xe4 */
        .long   0               /* 0xe8 */
        .long   0               /* 0xec */
@@ -1875,11 +1886,11 @@ hcall_real_table:
        .long   0               /* 0x118 */
        .long   0               /* 0x11c */
        .long   0               /* 0x120 */
-       .long   .kvmppc_h_bulk_remove - hcall_real_table
+       .long   DOTSYM(kvmppc_h_bulk_remove) - hcall_real_table
        .long   0               /* 0x128 */
        .long   0               /* 0x12c */
        .long   0               /* 0x130 */
-       .long   .kvmppc_h_set_xdabr - hcall_real_table
+       .long   DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table
 hcall_real_table_end:
 
 ignore_hdec:
@@ -1999,8 +2010,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
 
        /*
         * Take a nap until a decrementer or external or doobell interrupt
-        * occurs, with PECE1, PECE0 and PECEDP set in LPCR
+        * occurs, with PECE1, PECE0 and PECEDP set in LPCR. Also clear the
+        * runlatch bit before napping.
         */
+       mfspr   r2, SPRN_CTRLF
+       clrrdi  r2, r2, 1
+       mtspr   SPRN_CTRLT, r2
+
        li      r0,1
        stb     r0,HSTATE_HWTHREAD_REQ(r13)
        mfspr   r5,SPRN_LPCR
@@ -2099,7 +2115,7 @@ kvm_cede_exit:
        /* Try to handle a machine check in real mode */
 machine_check_realmode:
        mr      r3, r9          /* get vcpu pointer */
-       bl      .kvmppc_realmode_machine_check
+       bl      kvmppc_realmode_machine_check
        nop
        cmpdi   r3, 0           /* continue exiting from guest? */
        ld      r9, HSTATE_KVM_VCPU(r13)
index 95a20e17dbff2c79557a18dba8f553a0f3a323d2..59fa2de9546d7fb0ba8ca05729ad78e75e0a9e88 100644 (file)
@@ -23,9 +23,7 @@ obj-y                 += checksum_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC64)    += checksum_wrappers_64.o
 endif
 
-ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),)
 obj-$(CONFIG_PPC64)            += memcpy_power7.o memcpy_64.o 
-endif
 
 obj-$(CONFIG_PPC_EMULATE_SSTEP)        += sstep.o ldstfp.o
 
index 9f9434a8526443c482b715b74824f99c99d86f0c..e59c9c2ebe98dd4468054a1808dbd7b7fd65a7f6 100644 (file)
@@ -20,7 +20,7 @@ _GLOBAL(copy_page)
 BEGIN_FTR_SECTION
        lis     r5,PAGE_SIZE@h
 FTR_SECTION_ELSE
-       b       .copypage_power7
+       b       copypage_power7
 ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY)
        ori     r5,r5,PAGE_SIZE@l
 BEGIN_FTR_SECTION
index 395c594722a223e339944905ddeb675670c9085e..d7dafb3777acc6badda7b391ebc48580f37710a8 100644 (file)
@@ -56,15 +56,15 @@ _GLOBAL(copypage_power7)
 
 #ifdef CONFIG_ALTIVEC
        mflr    r0
-       std     r3,48(r1)
-       std     r4,56(r1)
+       std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
+       std     r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
        std     r0,16(r1)
        stdu    r1,-STACKFRAMESIZE(r1)
-       bl      .enter_vmx_copy
+       bl      enter_vmx_copy
        cmpwi   r3,0
        ld      r0,STACKFRAMESIZE+16(r1)
-       ld      r3,STACKFRAMESIZE+48(r1)
-       ld      r4,STACKFRAMESIZE+56(r1)
+       ld      r3,STK_REG(R31)(r1)
+       ld      r4,STK_REG(R30)(r1)
        mtlr    r0
 
        li      r0,(PAGE_SIZE/128)
@@ -103,7 +103,7 @@ _GLOBAL(copypage_power7)
        addi    r3,r3,128
        bdnz    1b
 
-       b       .exit_vmx_copy          /* tail call optimise */
+       b       exit_vmx_copy           /* tail call optimise */
 
 #else
        li      r0,(PAGE_SIZE/128)
index 596a285c07554d65dfd561367a52ffed47aba55d..0860ee46013c93a4952cd8147c76aa600f66506f 100644 (file)
@@ -18,7 +18,7 @@
 #endif
 
        .align  7
-_GLOBAL(__copy_tofrom_user)
+_GLOBAL_TOC(__copy_tofrom_user)
 BEGIN_FTR_SECTION
        nop
 FTR_SECTION_ELSE
index e8e9c36dc7844455c4b24356cdff5f9ed9e70aff..c46c876ac96af693445e91da8204ade16169ece6 100644 (file)
@@ -66,7 +66,7 @@
        ld      r15,STK_REG(R15)(r1)
        ld      r14,STK_REG(R14)(r1)
 .Ldo_err3:
-       bl      .exit_vmx_usercopy
+       bl      exit_vmx_usercopy
        ld      r0,STACKFRAMESIZE+16(r1)
        mtlr    r0
        b       .Lexit
@@ -85,9 +85,9 @@
 .Lexit:
        addi    r1,r1,STACKFRAMESIZE
 .Ldo_err1:
-       ld      r3,48(r1)
-       ld      r4,56(r1)
-       ld      r5,64(r1)
+       ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
+       ld      r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
+       ld      r5,-STACKFRAMESIZE+STK_REG(R29)(r1)
        b       __copy_tofrom_user_base
 
 
@@ -96,18 +96,18 @@ _GLOBAL(__copy_tofrom_user_power7)
        cmpldi  r5,16
        cmpldi  cr1,r5,4096
 
-       std     r3,48(r1)
-       std     r4,56(r1)
-       std     r5,64(r1)
+       std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
+       std     r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
+       std     r5,-STACKFRAMESIZE+STK_REG(R29)(r1)
 
        blt     .Lshort_copy
        bgt     cr1,.Lvmx_copy
 #else
        cmpldi  r5,16
 
-       std     r3,48(r1)
-       std     r4,56(r1)
-       std     r5,64(r1)
+       std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
+       std     r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
+       std     r5,-STACKFRAMESIZE+STK_REG(R29)(r1)
 
        blt     .Lshort_copy
 #endif
@@ -295,12 +295,12 @@ err1;     stb     r0,0(r3)
        mflr    r0
        std     r0,16(r1)
        stdu    r1,-STACKFRAMESIZE(r1)
-       bl      .enter_vmx_usercopy
+       bl      enter_vmx_usercopy
        cmpwi   cr1,r3,0
        ld      r0,STACKFRAMESIZE+16(r1)
-       ld      r3,STACKFRAMESIZE+48(r1)
-       ld      r4,STACKFRAMESIZE+56(r1)
-       ld      r5,STACKFRAMESIZE+64(r1)
+       ld      r3,STK_REG(R31)(r1)
+       ld      r4,STK_REG(R30)(r1)
+       ld      r5,STK_REG(R29)(r1)
        mtlr    r0
 
        /*
@@ -514,7 +514,7 @@ err3;       lbz     r0,0(r4)
 err3;  stb     r0,0(r3)
 
 15:    addi    r1,r1,STACKFRAMESIZE
-       b       .exit_vmx_usercopy      /* tail call optimise */
+       b       exit_vmx_usercopy       /* tail call optimise */
 
 .Lvmx_unaligned_copy:
        /* Get the destination 16B aligned */
@@ -717,5 +717,5 @@ err3;       lbz     r0,0(r4)
 err3;  stb     r0,0(r3)
 
 15:    addi    r1,r1,STACKFRAMESIZE
-       b       .exit_vmx_usercopy      /* tail call optimise */
+       b       exit_vmx_usercopy       /* tail call optimise */
 #endif /* CONFiG_ALTIVEC */
index 9b96ff2ecd4dadb0aae350e80fde94fb93afb20b..19e66001a4f9d5ab6b1c1e7cc6f15c9b50b83b55 100644 (file)
@@ -24,7 +24,7 @@
 
 _GLOBAL(__arch_hweight8)
 BEGIN_FTR_SECTION
-       b .__sw_hweight8
+       b __sw_hweight8
        nop
        nop
 FTR_SECTION_ELSE
@@ -35,7 +35,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB)
 
 _GLOBAL(__arch_hweight16)
 BEGIN_FTR_SECTION
-       b .__sw_hweight16
+       b __sw_hweight16
        nop
        nop
        nop
@@ -57,7 +57,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB)
 
 _GLOBAL(__arch_hweight32)
 BEGIN_FTR_SECTION
-       b .__sw_hweight32
+       b __sw_hweight32
        nop
        nop
        nop
@@ -82,7 +82,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB)
 
 _GLOBAL(__arch_hweight64)
 BEGIN_FTR_SECTION
-       b .__sw_hweight64
+       b __sw_hweight64
        nop
        nop
        nop
index f4fcb0bc65639225b2fca58ace18025870bc471b..0738f96befbff76829e1119a5feefc915be39da8 100644 (file)
@@ -79,8 +79,8 @@ _GLOBAL(memset)
 
 _GLOBAL(memmove)
        cmplw   0,r3,r4
-       bgt     .backwards_memcpy
-       b       .memcpy
+       bgt     backwards_memcpy
+       b       memcpy
 
 _GLOBAL(backwards_memcpy)
        rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
index 72ad055168a333ed31ebd5c0c014ff00f6c7436a..32a06ec395d2108202762c6d164b3994ca6a7644 100644 (file)
 #include <asm/ppc_asm.h>
 
        .align  7
-_GLOBAL(memcpy)
+_GLOBAL_TOC(memcpy)
 BEGIN_FTR_SECTION
-       std     r3,48(r1)       /* save destination pointer for return value */
+#ifdef __LITTLE_ENDIAN__
+       cmpdi   cr7,r5,0
+#else
+       std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)     /* save destination pointer for return value */
+#endif
 FTR_SECTION_ELSE
 #ifndef SELFTEST
        b       memcpy_power7
 #endif
 ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY)
+#ifdef __LITTLE_ENDIAN__
+       /* dumb little-endian memcpy that will get replaced at runtime */
+       addi r9,r3,-1
+       addi r4,r4,-1
+       beqlr cr7
+       mtctr r5
+1:     lbzu r10,1(r4)
+       stbu r10,1(r9)
+       bdnz 1b
+       blr
+#else
        PPC_MTOCRF(0x01,r5)
        cmpldi  cr1,r5,16
        neg     r6,r3           # LS 3 bits = # bytes to 8-byte dest bdry
@@ -73,7 +88,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 2:     bf      cr7*4+3,3f
        lbz     r9,8(r4)
        stb     r9,0(r3)
-3:     ld      r3,48(r1)       /* return dest pointer */
+3:     ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)     /* return dest pointer */
        blr
 
 .Lsrc_unaligned:
@@ -156,7 +171,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 2:     bf      cr7*4+3,3f
        rotldi  r9,r9,8
        stb     r9,0(r3)
-3:     ld      r3,48(r1)       /* return dest pointer */
+3:     ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)     /* return dest pointer */
        blr
 
 .Ldst_unaligned:
@@ -201,5 +216,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 3:     bf      cr7*4+3,4f
        lbz     r0,0(r4)
        stb     r0,0(r3)
-4:     ld      r3,48(r1)       /* return dest pointer */
+4:     ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)     /* return dest pointer */
        blr
+#endif
index e4177dbea6bd6a9e59e1cfc548195b1223b8eb0d..2ff5c142f87ba061257f1f00fcc948bc4cb04780 100644 (file)
@@ -33,14 +33,14 @@ _GLOBAL(memcpy_power7)
        cmpldi  r5,16
        cmpldi  cr1,r5,4096
 
-       std     r3,48(r1)
+       std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
 
        blt     .Lshort_copy
        bgt     cr1,.Lvmx_copy
 #else
        cmpldi  r5,16
 
-       std     r3,48(r1)
+       std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
 
        blt     .Lshort_copy
 #endif
@@ -216,7 +216,7 @@ _GLOBAL(memcpy_power7)
        lbz     r0,0(r4)
        stb     r0,0(r3)
 
-15:    ld      r3,48(r1)
+15:    ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
        blr
 
 .Lunwind_stack_nonvmx_copy:
@@ -226,16 +226,16 @@ _GLOBAL(memcpy_power7)
 #ifdef CONFIG_ALTIVEC
 .Lvmx_copy:
        mflr    r0
-       std     r4,56(r1)
-       std     r5,64(r1)
+       std     r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
+       std     r5,-STACKFRAMESIZE+STK_REG(R29)(r1)
        std     r0,16(r1)
        stdu    r1,-STACKFRAMESIZE(r1)
-       bl      .enter_vmx_copy
+       bl      enter_vmx_copy
        cmpwi   cr1,r3,0
        ld      r0,STACKFRAMESIZE+16(r1)
-       ld      r3,STACKFRAMESIZE+48(r1)
-       ld      r4,STACKFRAMESIZE+56(r1)
-       ld      r5,STACKFRAMESIZE+64(r1)
+       ld      r3,STK_REG(R31)(r1)
+       ld      r4,STK_REG(R30)(r1)
+       ld      r5,STK_REG(R29)(r1)
        mtlr    r0
 
        /*
@@ -447,8 +447,8 @@ _GLOBAL(memcpy_power7)
        stb     r0,0(r3)
 
 15:    addi    r1,r1,STACKFRAMESIZE
-       ld      r3,48(r1)
-       b       .exit_vmx_copy          /* tail call optimise */
+       ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
+       b       exit_vmx_copy           /* tail call optimise */
 
 .Lvmx_unaligned_copy:
        /* Get the destination 16B aligned */
@@ -651,6 +651,6 @@ _GLOBAL(memcpy_power7)
        stb     r0,0(r3)
 
 15:    addi    r1,r1,STACKFRAMESIZE
-       ld      r3,48(r1)
-       b       .exit_vmx_copy          /* tail call optimise */
+       ld      r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
+       b       exit_vmx_copy           /* tail call optimise */
 #endif /* CONFiG_ALTIVEC */
index 1136d26a95ae02ac075914e13f54720864b71fea..057cbbb4c576d3377ca6f21b46d4b574114ef2be 100644 (file)
@@ -159,7 +159,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
 BEGIN_FTR_SECTION
        mr      r4,r30
        mr      r5,r7
-       bl      .hash_page_do_lazy_icache
+       bl      hash_page_do_lazy_icache
 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 
        /* At this point, r3 contains new PP bits, save them in
@@ -201,7 +201,8 @@ htab_insert_pte:
        li      r8,MMU_PAGE_4K          /* page size */
        li      r9,MMU_PAGE_4K          /* actual page size */
        ld      r10,STK_PARAM(R9)(r1)   /* segment size */
-_GLOBAL(htab_call_hpte_insert1)
+.globl htab_call_hpte_insert1
+htab_call_hpte_insert1:
        bl      .                       /* Patched by htab_finish_init() */
        cmpdi   0,r3,0
        bge     htab_pte_insert_ok      /* Insertion successful */
@@ -225,7 +226,8 @@ _GLOBAL(htab_call_hpte_insert1)
        li      r8,MMU_PAGE_4K          /* page size */
        li      r9,MMU_PAGE_4K          /* actual page size */
        ld      r10,STK_PARAM(R9)(r1)   /* segment size */
-_GLOBAL(htab_call_hpte_insert2)
+.globl htab_call_hpte_insert2
+htab_call_hpte_insert2:
        bl      .                       /* Patched by htab_finish_init() */
        cmpdi   0,r3,0
        bge+    htab_pte_insert_ok      /* Insertion successful */
@@ -242,7 +244,8 @@ _GLOBAL(htab_call_hpte_insert2)
 2:     and     r0,r5,r27
        rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */   
        /* Call ppc_md.hpte_remove */
-_GLOBAL(htab_call_hpte_remove)
+.globl htab_call_hpte_remove
+htab_call_hpte_remove:
        bl      .                       /* Patched by htab_finish_init() */
 
        /* Try all again */
@@ -296,7 +299,8 @@ htab_modify_pte:
        li      r7,MMU_PAGE_4K          /* actual page size */
        ld      r8,STK_PARAM(R9)(r1)    /* segment size */
        ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
-_GLOBAL(htab_call_hpte_updatepp)
+.globl htab_call_hpte_updatepp
+htab_call_hpte_updatepp:
        bl      .                       /* Patched by htab_finish_init() */
 
        /* if we failed because typically the HPTE wasn't really here
@@ -471,7 +475,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
 BEGIN_FTR_SECTION
        mr      r4,r30
        mr      r5,r7
-       bl      .hash_page_do_lazy_icache
+       bl      hash_page_do_lazy_icache
 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 
        /* At this point, r3 contains new PP bits, save them in
@@ -526,7 +530,8 @@ htab_special_pfn:
        li      r8,MMU_PAGE_4K          /* page size */
        li      r9,MMU_PAGE_4K          /* actual page size */
        ld      r10,STK_PARAM(R9)(r1)   /* segment size */
-_GLOBAL(htab_call_hpte_insert1)
+.globl htab_call_hpte_insert1
+htab_call_hpte_insert1:
        bl      .                       /* patched by htab_finish_init() */
        cmpdi   0,r3,0
        bge     htab_pte_insert_ok      /* Insertion successful */
@@ -554,7 +559,8 @@ _GLOBAL(htab_call_hpte_insert1)
        li      r8,MMU_PAGE_4K          /* page size */
        li      r9,MMU_PAGE_4K          /* actual page size */
        ld      r10,STK_PARAM(R9)(r1)   /* segment size */
-_GLOBAL(htab_call_hpte_insert2)
+.globl htab_call_hpte_insert2
+htab_call_hpte_insert2:
        bl      .                       /* patched by htab_finish_init() */
        cmpdi   0,r3,0
        bge+    htab_pte_insert_ok      /* Insertion successful */
@@ -571,7 +577,8 @@ _GLOBAL(htab_call_hpte_insert2)
 2:     and     r0,r5,r27
        rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
        /* Call ppc_md.hpte_remove */
-_GLOBAL(htab_call_hpte_remove)
+.globl htab_call_hpte_remove
+htab_call_hpte_remove:
        bl      .                       /* patched by htab_finish_init() */
 
        /* Try all again */
@@ -588,7 +595,7 @@ htab_inval_old_hpte:
        li      r6,MMU_PAGE_64K         /* psize */
        ld      r7,STK_PARAM(R9)(r1)    /* ssize */
        ld      r8,STK_PARAM(R8)(r1)    /* local */
-       bl      .flush_hash_page
+       bl      flush_hash_page
        /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */
        lis     r0,_PAGE_HPTE_SUB@h
        ori     r0,r0,_PAGE_HPTE_SUB@l
@@ -660,7 +667,8 @@ htab_modify_pte:
        li      r7,MMU_PAGE_4K          /* actual page size */
        ld      r8,STK_PARAM(R9)(r1)    /* segment size */
        ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
-_GLOBAL(htab_call_hpte_updatepp)
+.globl htab_call_hpte_updatepp
+htab_call_hpte_updatepp:
        bl      .                       /* patched by htab_finish_init() */
 
        /* if we failed because typically the HPTE wasn't really here
@@ -812,7 +820,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
 BEGIN_FTR_SECTION
        mr      r4,r30
        mr      r5,r7
-       bl      .hash_page_do_lazy_icache
+       bl      hash_page_do_lazy_icache
 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 
        /* At this point, r3 contains new PP bits, save them in
@@ -857,7 +865,8 @@ ht64_insert_pte:
        li      r8,MMU_PAGE_64K
        li      r9,MMU_PAGE_64K         /* actual page size */
        ld      r10,STK_PARAM(R9)(r1)   /* segment size */
-_GLOBAL(ht64_call_hpte_insert1)
+.globl ht64_call_hpte_insert1
+ht64_call_hpte_insert1:
        bl      .                       /* patched by htab_finish_init() */
        cmpdi   0,r3,0
        bge     ht64_pte_insert_ok      /* Insertion successful */
@@ -881,7 +890,8 @@ _GLOBAL(ht64_call_hpte_insert1)
        li      r8,MMU_PAGE_64K
        li      r9,MMU_PAGE_64K         /* actual page size */
        ld      r10,STK_PARAM(R9)(r1)   /* segment size */
-_GLOBAL(ht64_call_hpte_insert2)
+.globl ht64_call_hpte_insert2
+ht64_call_hpte_insert2:
        bl      .                       /* patched by htab_finish_init() */
        cmpdi   0,r3,0
        bge+    ht64_pte_insert_ok      /* Insertion successful */
@@ -898,7 +908,8 @@ _GLOBAL(ht64_call_hpte_insert2)
 2:     and     r0,r5,r27
        rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
        /* Call ppc_md.hpte_remove */
-_GLOBAL(ht64_call_hpte_remove)
+.globl ht64_call_hpte_remove
+ht64_call_hpte_remove:
        bl      .                       /* patched by htab_finish_init() */
 
        /* Try all again */
@@ -952,7 +963,8 @@ ht64_modify_pte:
        li      r7,MMU_PAGE_64K         /* actual page size */
        ld      r8,STK_PARAM(R9)(r1)    /* segment size */
        ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
-_GLOBAL(ht64_call_hpte_updatepp)
+.globl ht64_call_hpte_updatepp
+ht64_call_hpte_updatepp:
        bl      .                       /* patched by htab_finish_init() */
 
        /* if we failed because typically the HPTE wasn't really here
index 3ea26c25590be1dabe4a057882f35b77f5dfe7c1..cf1d325eae8be814953650cf6b94fd349c0fdd12 100644 (file)
@@ -82,17 +82,14 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
                va &= ~((1ul << mmu_psize_defs[apsize].shift) - 1);
                va |= penc << 12;
                va |= ssize << 8;
-               /* Add AVAL part */
-               if (psize != apsize) {
-                       /*
-                        * MPSS, 64K base page size and 16MB parge page size
-                        * We don't need all the bits, but rest of the bits
-                        * must be ignored by the processor.
-                        * vpn cover upto 65 bits of va. (0...65) and we need
-                        * 58..64 bits of va.
-                        */
-                       va |= (vpn & 0xfe);
-               }
+               /*
+                * AVAL bits:
+                * We don't need all the bits, but rest of the bits
+                * must be ignored by the processor.
+                * vpn cover upto 65 bits of va. (0...65) and we need
+                * 58..64 bits of va.
+                */
+               va |= (vpn & 0xfe); /* AVAL */
                va |= 1; /* L */
                asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2)
                             : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206)
@@ -133,17 +130,14 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
                va &= ~((1ul << mmu_psize_defs[apsize].shift) - 1);
                va |= penc << 12;
                va |= ssize << 8;
-               /* Add AVAL part */
-               if (psize != apsize) {
-                       /*
-                        * MPSS, 64K base page size and 16MB parge page size
-                        * We don't need all the bits, but rest of the bits
-                        * must be ignored by the processor.
-                        * vpn cover upto 65 bits of va. (0...65) and we need
-                        * 58..64 bits of va.
-                        */
-                       va |= (vpn & 0xfe);
-               }
+               /*
+                * AVAL bits:
+                * We don't need all the bits, but rest of the bits
+                * must be ignored by the processor.
+                * vpn cover upto 65 bits of va. (0...65) and we need
+                * 58..64 bits of va.
+                */
+               va |= (vpn & 0xfe);
                va |= 1; /* L */
                asm volatile(".long 0x7c000224 | (%0 << 11) | (1 << 21)"
                             : : "r"(va) : "memory");
index d766d6ee33fe6889e5a96b3898f8c47b0050fc14..91666f07e60aecf403f1e130015dd3c0fe0cdb74 100644 (file)
@@ -445,6 +445,24 @@ static void mmu_psize_set_default_penc(void)
                        mmu_psize_defs[bpsize].penc[apsize] = -1;
 }
 
+#ifdef CONFIG_PPC_64K_PAGES
+
+static bool might_have_hea(void)
+{
+       /*
+        * The HEA ethernet adapter requires awareness of the
+        * GX bus. Without that awareness we can easily assume
+        * we will never see an HEA ethernet device.
+        */
+#ifdef CONFIG_IBMEBUS
+       return !cpu_has_feature(CPU_FTR_ARCH_207S);
+#else
+       return false;
+#endif
+}
+
+#endif /* #ifdef CONFIG_PPC_64K_PAGES */
+
 static void __init htab_init_page_sizes(void)
 {
        int rc;
@@ -499,10 +517,11 @@ static void __init htab_init_page_sizes(void)
                        mmu_linear_psize = MMU_PAGE_64K;
                if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) {
                        /*
-                        * Don't use 64k pages for ioremap on pSeries, since
-                        * that would stop us accessing the HEA ethernet.
+                        * When running on pSeries using 64k pages for ioremap
+                        * would stop us accessing the HEA ethernet. So if we
+                        * have the chance of ever seeing one, stay at 4k.
                         */
-                       if (!machine_is(pseries))
+                       if (!might_have_hea() || !machine_is(pseries))
                                mmu_io_psize = MMU_PAGE_64K;
                } else
                        mmu_ci_restrictions = 1;
@@ -603,47 +622,43 @@ int remove_section_mapping(unsigned long start, unsigned long end)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-#define FUNCTION_TEXT(A)       ((*(unsigned long *)(A)))
+extern u32 htab_call_hpte_insert1[];
+extern u32 htab_call_hpte_insert2[];
+extern u32 htab_call_hpte_remove[];
+extern u32 htab_call_hpte_updatepp[];
+extern u32 ht64_call_hpte_insert1[];
+extern u32 ht64_call_hpte_insert2[];
+extern u32 ht64_call_hpte_remove[];
+extern u32 ht64_call_hpte_updatepp[];
 
 static void __init htab_finish_init(void)
 {
-       extern unsigned int *htab_call_hpte_insert1;
-       extern unsigned int *htab_call_hpte_insert2;
-       extern unsigned int *htab_call_hpte_remove;
-       extern unsigned int *htab_call_hpte_updatepp;
-
 #ifdef CONFIG_PPC_HAS_HASH_64K
-       extern unsigned int *ht64_call_hpte_insert1;
-       extern unsigned int *ht64_call_hpte_insert2;
-       extern unsigned int *ht64_call_hpte_remove;
-       extern unsigned int *ht64_call_hpte_updatepp;
-
        patch_branch(ht64_call_hpte_insert1,
-               FUNCTION_TEXT(ppc_md.hpte_insert),
+               ppc_function_entry(ppc_md.hpte_insert),
                BRANCH_SET_LINK);
        patch_branch(ht64_call_hpte_insert2,
-               FUNCTION_TEXT(ppc_md.hpte_insert),
+               ppc_function_entry(ppc_md.hpte_insert),
                BRANCH_SET_LINK);
        patch_branch(ht64_call_hpte_remove,
-               FUNCTION_TEXT(ppc_md.hpte_remove),
+               ppc_function_entry(ppc_md.hpte_remove),
                BRANCH_SET_LINK);
        patch_branch(ht64_call_hpte_updatepp,
-               FUNCTION_TEXT(ppc_md.hpte_updatepp),
+               ppc_function_entry(ppc_md.hpte_updatepp),
                BRANCH_SET_LINK);
-
 #endif /* CONFIG_PPC_HAS_HASH_64K */
 
        patch_branch(htab_call_hpte_insert1,
-               FUNCTION_TEXT(ppc_md.hpte_insert),
+               ppc_function_entry(ppc_md.hpte_insert),
                BRANCH_SET_LINK);
        patch_branch(htab_call_hpte_insert2,
-               FUNCTION_TEXT(ppc_md.hpte_insert),
+               ppc_function_entry(ppc_md.hpte_insert),
                BRANCH_SET_LINK);
        patch_branch(htab_call_hpte_remove,
-               FUNCTION_TEXT(ppc_md.hpte_remove),
+               ppc_function_entry(ppc_md.hpte_remove),
                BRANCH_SET_LINK);
        patch_branch(htab_call_hpte_updatepp,
-               FUNCTION_TEXT(ppc_md.hpte_updatepp),
+               ppc_function_entry(ppc_md.hpte_updatepp),
                BRANCH_SET_LINK);
 }
 
index 9d1d33cd2be528598eb9a3e0c436a0c041094656..4623366f82e93cb311c377dae87330678fae031f 100644 (file)
@@ -256,10 +256,14 @@ static inline void patch_slb_encoding(unsigned int *insn_addr,
        patch_instruction(insn_addr, insn);
 }
 
+extern u32 slb_compare_rr_to_size[];
+extern u32 slb_miss_kernel_load_linear[];
+extern u32 slb_miss_kernel_load_io[];
+extern u32 slb_compare_rr_to_size[];
+extern u32 slb_miss_kernel_load_vmemmap[];
+
 void slb_set_size(u16 size)
 {
-       extern unsigned int *slb_compare_rr_to_size;
-
        if (mmu_slb_size == size)
                return;
 
@@ -272,11 +276,7 @@ void slb_initialize(void)
        unsigned long linear_llp, vmalloc_llp, io_llp;
        unsigned long lflags, vflags;
        static int slb_encoding_inited;
-       extern unsigned int *slb_miss_kernel_load_linear;
-       extern unsigned int *slb_miss_kernel_load_io;
-       extern unsigned int *slb_compare_rr_to_size;
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-       extern unsigned int *slb_miss_kernel_load_vmemmap;
        unsigned long vmemmap_llp;
 #endif
 
index 17aa6dfceb3498cbb0a09302485bdf1ab8049cbf..736d18b3cefd3bd16e2d9ab7c34b56bb7f5e8a61 100644 (file)
@@ -35,7 +35,7 @@ _GLOBAL(slb_allocate_realmode)
         * check for bad kernel/user address
         * (ea & ~REGION_MASK) >= PGTABLE_RANGE
         */
-       rldicr. r9,r3,4,(63 - 46 - 4)
+       rldicr. r9,r3,4,(63 - PGTABLE_EADDR_SIZE - 4)
        bne-    8f
 
        srdi    r9,r3,60                /* get region */
@@ -59,7 +59,8 @@ _GLOBAL(slb_allocate_realmode)
        /* Linear mapping encoding bits, the "li" instruction below will
         * be patched by the kernel at boot
         */
-_GLOBAL(slb_miss_kernel_load_linear)
+.globl slb_miss_kernel_load_linear
+slb_miss_kernel_load_linear:
        li      r11,0
        /*
         * context = (MAX_USER_CONTEXT) + ((ea >> 60) - 0xc) + 1
@@ -79,7 +80,8 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
        /* Check virtual memmap region. To be patches at kernel boot */
        cmpldi  cr0,r9,0xf
        bne     1f
-_GLOBAL(slb_miss_kernel_load_vmemmap)
+.globl slb_miss_kernel_load_vmemmap
+slb_miss_kernel_load_vmemmap:
        li      r11,0
        b       6f
 1:
@@ -95,7 +97,8 @@ _GLOBAL(slb_miss_kernel_load_vmemmap)
        b       6f
 5:
        /* IO mapping */
-       _GLOBAL(slb_miss_kernel_load_io)
+.globl slb_miss_kernel_load_io
+slb_miss_kernel_load_io:
        li      r11,0
 6:
        /*
@@ -250,7 +253,8 @@ slb_finish_load:
 7:     ld      r10,PACASTABRR(r13)
        addi    r10,r10,1
        /* This gets soft patched on boot. */
-_GLOBAL(slb_compare_rr_to_size)
+.globl slb_compare_rr_to_size
+slb_compare_rr_to_size:
        cmpldi  r10,0
 
        blt+    4f
index 297c9105141365e81316a888176fe80611b5b08a..e0766b82e1656721ff9e93586b47552414936973 100644 (file)
@@ -155,16 +155,28 @@ static ssize_t read_offset_data(void *dest, size_t dest_len,
        return copy_len;
 }
 
-static unsigned long h_get_24x7_catalog_page(char page[static 4096],
-                                            u32 version, u32 index)
+static unsigned long h_get_24x7_catalog_page_(unsigned long phys_4096,
+                                             unsigned long version,
+                                             unsigned long index)
 {
-       WARN_ON(!IS_ALIGNED((unsigned long)page, 4096));
+       pr_devel("h_get_24x7_catalog_page(0x%lx, %lu, %lu)",
+                       phys_4096,
+                       version,
+                       index);
+       WARN_ON(!IS_ALIGNED(phys_4096, 4096));
        return plpar_hcall_norets(H_GET_24X7_CATALOG_PAGE,
-                       virt_to_phys(page),
+                       phys_4096,
                        version,
                        index);
 }
 
+static unsigned long h_get_24x7_catalog_page(char page[],
+                                            u64 version, u32 index)
+{
+       return h_get_24x7_catalog_page_(virt_to_phys(page),
+                                       version, index);
+}
+
 static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
                            struct bin_attribute *bin_attr, char *buf,
                            loff_t offset, size_t count)
@@ -173,7 +185,7 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
        ssize_t ret = 0;
        size_t catalog_len = 0, catalog_page_len = 0, page_count = 0;
        loff_t page_offset = 0;
-       uint32_t catalog_version_num = 0;
+       uint64_t catalog_version_num = 0;
        void *page = kmem_cache_alloc(hv_page_cache, GFP_USER);
        struct hv_24x7_catalog_page_0 *page_0 = page;
        if (!page)
@@ -185,7 +197,7 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
                goto e_free;
        }
 
-       catalog_version_num = be32_to_cpu(page_0->version);
+       catalog_version_num = be64_to_cpu(page_0->version);
        catalog_page_len = be32_to_cpu(page_0->length);
        catalog_len = catalog_page_len * 4096;
 
@@ -208,8 +220,9 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
                                page, 4096, page_offset * 4096);
 e_free:
        if (hret)
-               pr_err("h_get_24x7_catalog_page(ver=%d, page=%lld) failed: rc=%ld\n",
-                               catalog_version_num, page_offset, hret);
+               pr_err("h_get_24x7_catalog_page(ver=%lld, page=%lld) failed:"
+                      " rc=%ld\n",
+                      catalog_version_num, page_offset, hret);
        kfree(page);
 
        pr_devel("catalog_read: offset=%lld(%lld) count=%zu(%zu) catalog_len=%zu(%zu) => %zd\n",
@@ -243,7 +256,7 @@ e_free:                                                             \
 static DEVICE_ATTR_RO(_name)
 
 PAGE_0_ATTR(catalog_version, "%lld\n",
-               (unsigned long long)be32_to_cpu(page_0->version));
+               (unsigned long long)be64_to_cpu(page_0->version));
 PAGE_0_ATTR(catalog_len, "%lld\n",
                (unsigned long long)be32_to_cpu(page_0->length) * 4096);
 static BIN_ATTR_RO(catalog, 0/* real length varies */);
@@ -485,13 +498,13 @@ static int hv_24x7_init(void)
        struct hv_perf_caps caps;
 
        if (!firmware_has_feature(FW_FEATURE_LPAR)) {
-               pr_info("not a virtualized system, not enabling\n");
+               pr_debug("not a virtualized system, not enabling\n");
                return -ENODEV;
        }
 
        hret = hv_perf_caps_get(&caps);
        if (hret) {
-               pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+               pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
                                hret);
                return -ENODEV;
        }
index 278ba7b9c2b525287f930445e71e04bd538e3236..c9d399a2df82e6727fa78b4de69fb867cc85552f 100644 (file)
@@ -78,7 +78,7 @@ static ssize_t kernel_version_show(struct device *dev,
        return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
 }
 
-DEVICE_ATTR_RO(kernel_version);
+static DEVICE_ATTR_RO(kernel_version);
 HV_CAPS_ATTR(version, "0x%x\n");
 HV_CAPS_ATTR(ga, "%d\n");
 HV_CAPS_ATTR(expanded, "%d\n");
@@ -273,13 +273,13 @@ static int hv_gpci_init(void)
        struct hv_perf_caps caps;
 
        if (!firmware_has_feature(FW_FEATURE_LPAR)) {
-               pr_info("not a virtualized system, not enabling\n");
+               pr_debug("not a virtualized system, not enabling\n");
                return -ENODEV;
        }
 
        hret = hv_perf_caps_get(&caps);
        if (hret) {
-               pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+               pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
                                hret);
                return -ENODEV;
        }
index dc1a264ec6e6da888eb45955c8360e2f816a3a90..4d88f6a19058cc253dcd885eec86e077f7441295 100644 (file)
@@ -199,6 +199,34 @@ config CURRITUCK
        help
          This option enables support for the IBM Currituck (476fpe) evaluation board
 
+config AKEBONO
+       bool "IBM Akebono (476gtr) Support"
+       depends on PPC_47x
+       default n
+       select SWIOTLB
+       select 476FPE
+       select PPC4xx_PCI_EXPRESS
+       select PCI_MSI
+       select PPC4xx_HSTA_MSI
+       select I2C
+       select I2C_IBM_IIC
+       select NETDEVICES
+       select ETHERNET
+       select NET_VENDOR_IBM
+       select IBM_EMAC_EMAC4
+       select IBM_EMAC_RGMII_WOL
+       select USB
+       select USB_OHCI_HCD_PLATFORM
+       select USB_EHCI_HCD_PLATFORM
+       select MMC_SDHCI
+       select MMC_SDHCI_PLTFM
+       select MMC_SDHCI_OF_476GTR
+       select ATA
+       select SATA_AHCI_PLATFORM
+       help
+         This option enables support for the IBM Akebono (476gtr) evaluation board
+
+
 config ICON
        bool "Icon"
        depends on 44x
@@ -323,6 +351,20 @@ config APM821xx
        select IBM_EMAC_EMAC4
        select IBM_EMAC_TAH
 
+config 476FPE_ERR46
+       depends on 476FPE
+       bool "Enable linker work around for PPC476FPE errata #46"
+       help
+         This option enables a work around for an icache bug on 476
+         that can cause execution of stale instructions when falling
+         through pages (IBM errata #46). It requires a recent version
+         of binutils which supports the --ppc476-workaround option.
+
+         The work around enables the appropriate linker options and
+         ensures that all module output sections are aligned to 4K
+         page boundaries. The work around is only required when
+         building modules.
+
 # 44x errata/workaround config symbols, selected by the CPU models above
 config IBM440EP_ERR42
        bool
index d03833abec092938ea15ea398e6e6536623f376c..26d35b5941f7988c91507a3c1e944d1840f0a436 100644 (file)
@@ -10,4 +10,5 @@ obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
 obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o
 obj-$(CONFIG_ISS4xx)   += iss4xx.o
 obj-$(CONFIG_CANYONLANDS)+= canyonlands.o
-obj-$(CONFIG_CURRITUCK)        += currituck.o
+obj-$(CONFIG_CURRITUCK)        += ppc476.o
+obj-$(CONFIG_AKEBONO)  += ppc476.o
similarity index 72%
rename from arch/powerpc/platforms/44x/currituck.c
rename to arch/powerpc/platforms/44x/ppc476.c
index 7f1b71a01c6a4e936da38573b72654e6e6ef6163..33986c1a05da2eaa6e1722dac53de62a2586f304 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Currituck board specific routines
+ * PowerPC 476FPE board specific routines
  *
- * Copyright Â© 2011 Tony Breeds IBM Corporation
+ * Copyright Â© 2013 Tony Breeds IBM Corporation
+ * Copyright Â© 2013 Alistair Popple IBM Corporation
  *
  * Based on earlier code:
  *    Matt Porter <mporter@kernel.crashing.org>
@@ -35,8 +36,9 @@
 #include <asm/mmu.h>
 
 #include <linux/pci.h>
+#include <linux/i2c.h>
 
-static __initdata struct of_device_id ppc47x_of_bus[] = {
+static struct of_device_id ppc47x_of_bus[] __initdata = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,plb6", },
        { .compatible = "ibm,opb", },
@@ -55,15 +57,69 @@ static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);
 
+/* Akebono has an AVR microcontroller attached to the I2C bus
+ * which is used to power off/reset the system. */
+
+/* AVR I2C Commands */
+#define AVR_PWRCTL_CMD (0x26)
+
+/* Flags for the power control I2C commands */
+#define AVR_PWRCTL_PWROFF (0x01)
+#define AVR_PWRCTL_RESET (0x02)
+
+static struct i2c_client *avr_i2c_client;
+static void avr_halt_system(int pwrctl_flags)
+{
+       /* Request the AVR to reset the system */
+       i2c_smbus_write_byte_data(avr_i2c_client,
+                                 AVR_PWRCTL_CMD, pwrctl_flags);
+
+       /* Wait for system to be reset */
+       while (1)
+               ;
+}
+
+static void avr_power_off_system(void)
+{
+       avr_halt_system(AVR_PWRCTL_PWROFF);
+}
+
+static void avr_reset_system(char *cmd)
+{
+       avr_halt_system(AVR_PWRCTL_RESET);
+}
+
+static int avr_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       avr_i2c_client = client;
+       ppc_md.restart = avr_reset_system;
+       ppc_md.power_off = avr_power_off_system;
+       return 0;
+}
+
+static const struct i2c_device_id avr_id[] = {
+       { "akebono-avr", 0 },
+       { }
+};
+
+static struct i2c_driver avr_driver = {
+       .driver = {
+               .name = "akebono-avr",
+       },
+       .probe = avr_probe,
+       .id_table = avr_id,
+};
+
 static int __init ppc47x_device_probe(void)
 {
+       i2c_add_driver(&avr_driver);
        of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);
 
        return 0;
 }
 machine_device_initcall(ppc47x, ppc47x_device_probe);
 
-/* We can have either UICs or MPICs */
 static void __init ppc47x_init_irq(void)
 {
        struct device_node *np;
@@ -157,43 +213,36 @@ static void __init ppc47x_setup_arch(void)
 {
 
        /* No need to check the DMA config as we /know/ our windows are all of
-        * RAM.  Lets hope that doesn't change */
+        * RAM.  Lets hope that doesn't change */
        swiotlb_detect_4g();
 
        ppc47x_smp_init();
 }
 
-/*
- * Called very early, MMU is off, device-tree isn't unflattened
- */
-static int __init ppc47x_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "ibm,currituck"))
-               return 0;
-
-       return 1;
-}
-
 static int board_rev = -1;
 static int __init ppc47x_get_board_rev(void)
 {
-       u8 fpga_reg0;
-       void *fpga;
-       struct device_node *np;
+       int reg;
+       u8 *fpga;
+       struct device_node *np = NULL;
+
+       if (of_machine_is_compatible("ibm,currituck")) {
+               np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
+               reg = 0;
+       } else if (of_machine_is_compatible("ibm,akebono")) {
+               np = of_find_compatible_node(NULL, NULL, "ibm,akebono-fpga");
+               reg = 2;
+       }
 
-       np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
        if (!np)
                goto fail;
 
-       fpga = of_iomap(np, 0);
+       fpga = (u8 *) of_iomap(np, 0);
        of_node_put(np);
        if (!fpga)
                goto fail;
 
-       fpga_reg0 = ioread8(fpga);
-       board_rev = fpga_reg0 & 0x03;
+       board_rev = ioread8(fpga + reg) & 0x03;
        pr_info("%s: Found board revision %d\n", __func__, board_rev);
        iounmap(fpga);
        return 0;
@@ -208,7 +257,7 @@ machine_arch_initcall(ppc47x, ppc47x_get_board_rev);
 static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
 {
        if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
-                                     dev->device == 0x00e0)) {
+                                     dev->device == 0x00e0)) {
                if (board_rev == 0) {
                        dev->irq = irq_create_mapping(NULL, 47);
                        pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
@@ -221,13 +270,30 @@ static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
        }
 }
 
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init ppc47x_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "ibm,akebono"))
+               return 1;
+
+       if (of_flat_dt_is_compatible(root, "ibm,currituck")) {
+               ppc_md.pci_irq_fixup = ppc47x_pci_irq_fixup;
+               return 1;
+       }
+
+       return 0;
+}
+
 define_machine(ppc47x) {
        .name                   = "PowerPC 47x",
        .probe                  = ppc47x_probe,
        .progress               = udbg_progress,
        .init_IRQ               = ppc47x_init_irq,
        .setup_arch             = ppc47x_setup_arch,
-       .pci_irq_fixup          = ppc47x_pci_irq_fixup,
        .restart                = ppc4xx_reset_system,
        .calibrate_decr         = generic_calibrate_decr,
 };
diff --git a/arch/powerpc/platforms/44x/ppc476_modules.lds b/arch/powerpc/platforms/44x/ppc476_modules.lds
new file mode 100644 (file)
index 0000000..9fec5d3
--- /dev/null
@@ -0,0 +1,15 @@
+SECTIONS
+{
+       .text : ALIGN(4096)
+       {
+               *(.text .text.* .fixup)
+       }
+       .init.text : ALIGN(4096)
+       {
+               *(.init.text .init.text.*)
+       }
+       .exit.text : ALIGN(4096)
+       {
+               *(.exit.text .exit.text.*)
+       }
+}
index 6382098d6f8d884aeea1fbbef387df8572f0b5b9..ba093f55367894bd79129e412e96550d02cae428 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/cacheflush.h>
 #include <asm/dbell.h>
 #include <asm/fsl_guts.h>
+#include <asm/code-patching.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/mpic.h>
@@ -267,7 +268,7 @@ out:
        flush_spin_table(spin_table);
        out_be32(&spin_table->pir, hw_cpu);
        out_be64((u64 *)(&spin_table->addr_h),
-         __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
+               __pa(ppc_function_entry(generic_secondary_smp_init)));
        flush_spin_table(spin_table);
 #endif
 
index d9e2b19b7c8deb16b344670c50174032d494176d..43b65ad1970a1a8635e7c517b7cfb95d211bcf84 100644 (file)
@@ -422,6 +422,7 @@ config CPU_BIG_ENDIAN
 
 config CPU_LITTLE_ENDIAN
        bool "Build little endian kernel"
+       select PPC64_BOOT_WRAPPER
        help
          Build a little endian kernel.
 
@@ -430,3 +431,7 @@ config CPU_LITTLE_ENDIAN
          little endian powerpc.
 
 endchoice
+
+config PPC64_BOOT_WRAPPER
+       def_bool n
+       depends on CPU_LITTLE_ENDIAN
index 90745eaa45fe9551b71c2479fc1ce8060f8abd0c..c8017a7bcabd2b9e44b669357da5fc6eb9c0c090 100644 (file)
@@ -40,6 +40,7 @@
 #include <asm/firmware.h>
 #include <asm/rtas.h>
 #include <asm/cputhreads.h>
+#include <asm/code-patching.h>
 
 #include "interrupt.h"
 #include <asm/udbg.h>
@@ -70,8 +71,8 @@ static cpumask_t of_spin_map;
 static inline int smp_startup_cpu(unsigned int lcpu)
 {
        int status;
-       unsigned long start_here = __pa((u32)*((unsigned long *)
-                                              generic_secondary_smp_init));
+       unsigned long start_here =
+                       __pa(ppc_function_entry(generic_secondary_smp_init));
        unsigned int pcpu;
        int start_cpu;
 
index 2a7024d8d8b1333f646bce95738d83b6e9ba0999..a25f496c2ef9065b98547423031b953c95597eff 100644 (file)
@@ -65,6 +65,7 @@ config MVME5100
        select PPC_INDIRECT_PCI
        select PPC_I8259
        select PPC_NATIVE
+       select PPC_UDBG_16550
        help
          This option enables support for the Motorola (now Emerson) MVME5100
          board.
index 56f45adcd0895aceb35f7be4ef800b2c39e60b77..81ab555aa491ed118291d150f2dfaba82a1f4f03 100644 (file)
@@ -66,7 +66,7 @@ sleep_common:
        std     r3, 48(r1)
 
        /* Only do power savings when in astate 0 */
-       bl      .check_astate
+       bl      check_astate
        cmpwi   r3,0
        bne     1f
 
index 253fefe3d1a0e76fd4ed3996711b6f1784725d6c..79d0cdf786d021b3b6d6be31d364d3ce86549408 100644 (file)
@@ -42,11 +42,19 @@ static int ioda_eeh_event(struct notifier_block *nb,
 {
        uint64_t changed_evts = (uint64_t)change;
 
-       /* We simply send special EEH event */
-       if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
-           (events & OPAL_EVENT_PCI_ERROR) &&
-           eeh_enabled())
+       /*
+        * We simply send special EEH event if EEH has
+        * been enabled, or clear pending events in
+        * case that we enable EEH soon
+        */
+       if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
+           !(events & OPAL_EVENT_PCI_ERROR))
+               return 0;
+
+       if (eeh_enabled())
                eeh_send_failure_event(NULL);
+       else
+               opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
 
        return 0;
 }
@@ -141,7 +149,9 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
        }
 
 #ifdef CONFIG_DEBUG_FS
-       if (phb->dbgfs) {
+       if (!phb->has_dbgfs && phb->dbgfs) {
+               phb->has_dbgfs = 1;
+
                debugfs_create_file("err_injct_outbound", 0600,
                                    phb->dbgfs, hose,
                                    &ioda_eeh_outb_dbgfs_ops);
@@ -154,7 +164,14 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
        }
 #endif
 
-       phb->eeh_state |= PNV_EEH_STATE_ENABLED;
+       /* If EEH is enabled, we're going to rely on that.
+        * Otherwise, we restore to conventional mechanism
+        * to clear frozen PE during PCI config access.
+        */
+       if (eeh_enabled())
+               phb->flags |= PNV_PHB_FLAG_EEH;
+       else
+               phb->flags &= ~PNV_PHB_FLAG_EEH;
 
        return 0;
 }
@@ -268,6 +285,21 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
                return EEH_STATE_NOT_SUPPORT;
        }
 
+       /*
+        * If we're in middle of PE reset, return normal
+        * state to keep EEH core going. For PHB reset, we
+        * still expect to have fenced PHB cleared with
+        * PHB reset.
+        */
+       if (!(pe->type & EEH_PE_PHB) &&
+           (pe->state & EEH_PE_RESET)) {
+               result = (EEH_STATE_MMIO_ACTIVE |
+                         EEH_STATE_DMA_ACTIVE |
+                         EEH_STATE_MMIO_ENABLED |
+                         EEH_STATE_DMA_ENABLED);
+               return result;
+       }
+
        /* Retrieve PE status through OPAL */
        pe_no = pe->addr;
        ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
@@ -347,52 +379,6 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
        return result;
 }
 
-static int ioda_eeh_pe_clear(struct eeh_pe *pe)
-{
-       struct pci_controller *hose;
-       struct pnv_phb *phb;
-       u32 pe_no;
-       u8 fstate;
-       u16 pcierr;
-       s64 ret;
-
-       pe_no = pe->addr;
-       hose = pe->phb;
-       phb = pe->phb->private_data;
-
-       /* Clear the EEH error on the PE */
-       ret = opal_pci_eeh_freeze_clear(phb->opal_id,
-                       pe_no, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
-       if (ret) {
-               pr_err("%s: Failed to clear EEH error for "
-                      "PHB#%x-PE#%x, err=%lld\n",
-                      __func__, hose->global_number, pe_no, ret);
-               return -EIO;
-       }
-
-       /*
-        * Read the PE state back and verify that the frozen
-        * state has been removed.
-        */
-       ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
-                       &fstate, &pcierr, NULL);
-       if (ret) {
-               pr_err("%s: Failed to get EEH status on "
-                      "PHB#%x-PE#%x\n, err=%lld\n",
-                      __func__, hose->global_number, pe_no, ret);
-               return -EIO;
-       }
-
-       if (fstate != OPAL_EEH_STOPPED_NOT_FROZEN) {
-               pr_err("%s: Frozen state not cleared on "
-                      "PHB#%x-PE#%x, sts=%x\n",
-                      __func__, hose->global_number, pe_no, fstate);
-               return -EIO;
-       }
-
-       return 0;
-}
-
 static s64 ioda_eeh_phb_poll(struct pnv_phb *phb)
 {
        s64 rc = OPAL_HARDWARE;
@@ -402,13 +388,16 @@ static s64 ioda_eeh_phb_poll(struct pnv_phb *phb)
                if (rc <= 0)
                        break;
 
-               msleep(rc);
+               if (system_state < SYSTEM_RUNNING)
+                       udelay(1000 * rc);
+               else
+                       msleep(rc);
        }
 
        return rc;
 }
 
-static int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
+int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
 {
        struct pnv_phb *phb = hose->private_data;
        s64 rc = OPAL_HARDWARE;
@@ -431,9 +420,17 @@ static int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
 
        /*
         * Poll state of the PHB until the request is done
-        * successfully.
+        * successfully. The PHB reset is usually PHB complete
+        * reset followed by hot reset on root bus. So we also
+        * need the PCI bus settlement delay.
         */
        rc = ioda_eeh_phb_poll(phb);
+       if (option == EEH_RESET_DEACTIVATE) {
+               if (system_state < SYSTEM_RUNNING)
+                       udelay(1000 * EEH_PE_RST_SETTLE_TIME);
+               else
+                       msleep(EEH_PE_RST_SETTLE_TIME);
+       }
 out:
        if (rc != OPAL_SUCCESS)
                return -EIO;
@@ -471,6 +468,8 @@ static int ioda_eeh_root_reset(struct pci_controller *hose, int option)
 
        /* Poll state of the PHB until the request is done */
        rc = ioda_eeh_phb_poll(phb);
+       if (option == EEH_RESET_DEACTIVATE)
+               msleep(EEH_PE_RST_SETTLE_TIME);
 out:
        if (rc != OPAL_SUCCESS)
                return -EIO;
@@ -478,32 +477,149 @@ out:
        return 0;
 }
 
-static int ioda_eeh_bridge_reset(struct pci_controller *hose,
-               struct pci_dev *dev, int option)
+static bool ioda_eeh_is_plx_dnport(struct pci_dev *dev, int *reg,
+                                  int *mask, int *len)
 {
-       u16 ctrl;
+       unsigned short *pid;
+       unsigned short ids[] = {
+               0x10b5, 0x8748, 0x0080, 0x0400, /* PLX#8748     */
+               0x0000, 0x0000, 0x0000, 0x0000, /* End flag     */
+       };
+
+       if (!pci_is_pcie(dev))
+               return false;
+       if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)
+               return false;
+
+       pid = &ids[0];
+       while (!reg) {
+               if (pid[0] == 0x0)
+                       break;
 
-       pr_debug("%s: Reset device %04x:%02x:%02x.%01x with option %d\n",
-                __func__, hose->global_number, dev->bus->number,
-                PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), option);
+               if (dev->vendor == pid[0] &&
+                   dev->device == pid[1]) {
+                        *reg  = pid[2];
+                        *mask = pid[3];
+                        *len  = 2;
+                        return true;
+                }
+        }
+
+       *reg  = PCI_BRIDGE_CONTROL;
+       *mask = PCI_BRIDGE_CTL_BUS_RESET;
+       *len  = 2;
+       return false;
+}
+
+static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
+
+{
+       struct device_node *dn = pci_device_to_OF_node(dev);
+       struct eeh_dev *edev = of_node_to_eeh_dev(dn);
+       int aer = edev ? edev->aer_cap : 0;
+       int reg, mask, val, len;
+       bool is_plx_dnport;
+
+       pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n",
+                __func__, pci_domain_nr(dev->bus),
+                dev->bus->number, option);
+
+
+       is_plx_dnport = ioda_eeh_is_plx_dnport(dev, &reg, &mask, &len);
+       if (option == EEH_RESET_FUNDAMENTAL)
+               if (!is_plx_dnport || !edev)
+                       option = EEH_RESET_HOT;
+
+       if (option == EEH_RESET_HOT) {
+               reg  = PCI_BRIDGE_CONTROL;
+               mask = PCI_BRIDGE_CTL_BUS_RESET;
+               len  = 2;
+       }
+
+       if (option == EEH_RESET_DEACTIVATE) {
+               if (!is_plx_dnport || !edev ||
+                   !(edev->mode & EEH_DEV_FRESET)) {
+                       reg  = PCI_BRIDGE_CONTROL;
+                       mask = PCI_BRIDGE_CTL_BUS_RESET;
+                       len  = 2;
+               }
+       }
 
        switch (option) {
        case EEH_RESET_FUNDAMENTAL:
+               edev->mode |= EEH_DEV_FRESET;
+               /* Fall through */
        case EEH_RESET_HOT:
-               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
-               ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
-               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+               if (aer) {
+                       /* Mask receiver error */
+                       eeh_ops->read_config(dn, aer + PCI_ERR_COR_MASK,
+                                            4, &val);
+                       val |= PCI_ERR_COR_RCVR;
+                       eeh_ops->write_config(dn, aer + PCI_ERR_COR_MASK,
+                                             4, val);
+
+                       /* Mask linkDown */
+                       eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
+                                            4, &val);
+                       val |= PCI_ERR_UNC_SURPDN;
+                        eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
+                                             4, val);
+               }
+
+               eeh_ops->read_config(dn, reg, len, &val);
+               val |= mask;
+               eeh_ops->write_config(dn, reg, len, val);
+               msleep(EEH_PE_RST_HOLD_TIME);
+
                break;
        case EEH_RESET_DEACTIVATE:
-               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
-               ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+               eeh_ops->read_config(dn, reg, len, &val);
+               val &= ~mask;
+               eeh_ops->write_config(dn, reg, len, val);
+               msleep(EEH_PE_RST_SETTLE_TIME);
+
+               if (edev)
+                       edev->mode &= ~EEH_DEV_FRESET;
+               if (aer) {
+                       /* Clear receive error and enable it */
+                       eeh_ops->write_config(dn, aer + PCI_ERR_COR_STATUS,
+                                             4, PCI_ERR_COR_RCVR);
+                       eeh_ops->read_config(dn, aer + PCI_ERR_COR_MASK,
+                                            4, &val);
+                        val &= ~PCI_ERR_COR_RCVR;
+                       eeh_ops->write_config(dn, aer + PCI_ERR_COR_MASK,
+                                             4, val);
+
+                       /* Clear linkDown and enable it */
+                       eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_STATUS,
+                                             4, PCI_ERR_UNC_SURPDN);
+                       eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
+                                            4, &val);
+                       val &= ~PCI_ERR_UNC_SURPDN;
+                       eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
+                                             4, val);
+               }
+
                break;
        }
 
        return 0;
 }
 
+void pnv_pci_reset_secondary_bus(struct pci_dev *dev)
+{
+       struct pci_controller *hose;
+
+       if (pci_is_root_bus(dev->bus)) {
+               hose = pci_bus_to_host(dev->bus);
+               ioda_eeh_root_reset(hose, EEH_RESET_HOT);
+               ioda_eeh_root_reset(hose, EEH_RESET_DEACTIVATE);
+       } else {
+               ioda_eeh_bridge_reset(dev, EEH_RESET_HOT);
+               ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE);
+       }
+}
+
 /**
  * ioda_eeh_reset - Reset the indicated PE
  * @pe: EEH PE
@@ -523,36 +639,28 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
        int ret;
 
        /*
-        * Anyway, we have to clear the problematic state for the
-        * corresponding PE. However, we needn't do it if the PE
-        * is PHB associated. That means the PHB is having fatal
-        * errors and it needs reset. Further more, the AIB interface
-        * isn't reliable any more.
-        */
-       if (!(pe->type & EEH_PE_PHB) &&
-           (option == EEH_RESET_HOT ||
-           option == EEH_RESET_FUNDAMENTAL)) {
-               ret = ioda_eeh_pe_clear(pe);
-               if (ret)
-                       return -EIO;
-       }
-
-       /*
-        * The rules applied to reset, either fundamental or hot reset:
+        * For PHB reset, we always have complete reset. For those PEs whose
+        * primary bus derived from root complex (root bus) or root port
+        * (usually bus#1), we apply hot or fundamental reset on the root port.
+        * For other PEs, we always have hot reset on the PE primary bus.
         *
-        * We always reset the direct upstream bridge of the PE. If the
-        * direct upstream bridge isn't root bridge, we always take hot
-        * reset no matter what option (fundamental or hot) is. Otherwise,
-        * we should do the reset according to the required option.
+        * Here, we have different design to pHyp, which always clear the
+        * frozen state during PE reset. However, the good idea here from
+        * benh is to keep frozen state before we get PE reset done completely
+        * (until BAR restore). With the frozen state, HW drops illegal IO
+        * or MMIO access, which can incur recrusive frozen PE during PE
+        * reset. The side effect is that EEH core has to clear the frozen
+        * state explicitly after BAR restore.
         */
        if (pe->type & EEH_PE_PHB) {
                ret = ioda_eeh_phb_reset(hose, option);
        } else {
                bus = eeh_pe_bus_get(pe);
-               if (pci_is_root_bus(bus))
+               if (pci_is_root_bus(bus) ||
+                   pci_is_root_bus(bus->parent))
                        ret = ioda_eeh_root_reset(hose, option);
                else
-                       ret = ioda_eeh_bridge_reset(hose, bus->self, option);
+                       ret = ioda_eeh_bridge_reset(bus->self, option);
        }
 
        return ret;
@@ -639,22 +747,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
        }
 }
 
-static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
-                              struct eeh_pe **pe)
-{
-       struct eeh_pe *phb_pe;
-
-       phb_pe = eeh_phb_pe_get(hose);
-       if (!phb_pe) {
-               pr_warning("%s Can't find PE for PHB#%d\n",
-                          __func__, hose->global_number);
-               return -EEXIST;
-       }
-
-       *pe = phb_pe;
-       return 0;
-}
-
 static int ioda_eeh_get_pe(struct pci_controller *hose,
                           u16 pe_no, struct eeh_pe **pe)
 {
@@ -662,7 +754,8 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,
        struct eeh_dev dev;
 
        /* Find the PHB PE */
-       if (ioda_eeh_get_phb_pe(hose, &phb_pe))
+       phb_pe = eeh_phb_pe_get(hose);
+       if (!phb_pe)
                return -EEXIST;
 
        /* Find the PE according to PE# */
@@ -690,6 +783,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
 {
        struct pci_controller *hose;
        struct pnv_phb *phb;
+       struct eeh_pe *phb_pe;
        u64 frozen_pe_no;
        u16 err_type, severity;
        long rc;
@@ -706,10 +800,12 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
        list_for_each_entry(hose, &hose_list, list_node) {
                /*
                 * If the subordinate PCI buses of the PHB has been
-                * removed, we needn't take care of it any more.
+                * removed or is exactly under error recovery, we
+                * needn't take care of it any more.
                 */
                phb = hose->private_data;
-               if (phb->eeh_state & PNV_EEH_STATE_REMOVED)
+               phb_pe = eeh_phb_pe_get(hose);
+               if (!phb_pe || (phb_pe->state & EEH_PE_ISOLATED))
                        continue;
 
                rc = opal_pci_next_error(phb->opal_id,
@@ -742,12 +838,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                switch (err_type) {
                case OPAL_EEH_IOC_ERROR:
                        if (severity == OPAL_EEH_SEV_IOC_DEAD) {
-                               list_for_each_entry(hose, &hose_list,
-                                                   list_node) {
-                                       phb = hose->private_data;
-                                       phb->eeh_state |= PNV_EEH_STATE_REMOVED;
-                               }
-
                                pr_err("EEH: dead IOC detected\n");
                                ret = EEH_NEXT_ERR_DEAD_IOC;
                        } else if (severity == OPAL_EEH_SEV_INF) {
@@ -760,17 +850,12 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                        break;
                case OPAL_EEH_PHB_ERROR:
                        if (severity == OPAL_EEH_SEV_PHB_DEAD) {
-                               if (ioda_eeh_get_phb_pe(hose, pe))
-                                       break;
-
+                               *pe = phb_pe;
                                pr_err("EEH: dead PHB#%x detected\n",
                                        hose->global_number);
-                               phb->eeh_state |= PNV_EEH_STATE_REMOVED;
                                ret = EEH_NEXT_ERR_DEAD_PHB;
                        } else if (severity == OPAL_EEH_SEV_PHB_FENCED) {
-                               if (ioda_eeh_get_phb_pe(hose, pe))
-                                       break;
-
+                               *pe = phb_pe;
                                pr_err("EEH: fenced PHB#%x detected\n",
                                        hose->global_number);
                                ret = EEH_NEXT_ERR_FENCED_PHB;
@@ -788,17 +873,21 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                         * If we can't find the corresponding PE, the
                         * PEEV / PEST would be messy. So we force an
                         * fenced PHB so that it can be recovered.
+                        *
+                        * If the PE has been marked as isolated, that
+                        * should have been removed permanently or in
+                        * progress with recovery. We needn't report
+                        * it again.
                         */
                        if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) {
-                               if (!ioda_eeh_get_phb_pe(hose, pe)) {
-                                       pr_err("EEH: Escalated fenced PHB#%x "
-                                              "detected for PE#%llx\n",
-                                               hose->global_number,
-                                               frozen_pe_no);
-                                       ret = EEH_NEXT_ERR_FENCED_PHB;
-                               } else {
-                                       ret = EEH_NEXT_ERR_NONE;
-                               }
+                               *pe = phb_pe;
+                               pr_err("EEH: Escalated fenced PHB#%x "
+                                      "detected for PE#%llx\n",
+                                       hose->global_number,
+                                       frozen_pe_no);
+                               ret = EEH_NEXT_ERR_FENCED_PHB;
+                       } else if ((*pe)->state & EEH_PE_ISOLATED) {
+                               ret = EEH_NEXT_ERR_NONE;
                        } else {
                                pr_err("EEH: Frozen PE#%x on PHB#%x detected\n",
                                        (*pe)->addr, (*pe)->phb->global_number);
index a59788e83b8b377152ed5d70db86fbb7bc9fb805..56a206f32f77e750dccb117691099ac0f850d6d1 100644 (file)
@@ -126,6 +126,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
        edev->mode      &= 0xFFFFFF00;
        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
                edev->mode |= EEH_DEV_BRIDGE;
+       edev->pcix_cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
        if (pci_is_pcie(dev)) {
                edev->pcie_cap = pci_pcie_cap(dev);
 
@@ -133,6 +134,9 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
                        edev->mode |= EEH_DEV_ROOT_PORT;
                else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)
                        edev->mode |= EEH_DEV_DS_PORT;
+
+               edev->aer_cap = pci_find_ext_capability(dev,
+                                                       PCI_EXT_CAP_ID_ERR);
        }
 
        edev->config_addr       = ((dev->bus->number << 8) | dev->devfn);
index b9827b0d87e4cd69cdff9f51216ea9429c79fb41..788a1977b9a5203cc9a477be6f9a2a7b71cdd754 100644 (file)
@@ -209,89 +209,20 @@ static struct kobj_type dump_ktype = {
        .default_attrs = dump_default_attrs,
 };
 
-static void free_dump_sg_list(struct opal_sg_list *list)
-{
-       struct opal_sg_list *sg1;
-       while (list) {
-               sg1 = list->next;
-               kfree(list);
-               list = sg1;
-       }
-       list = NULL;
-}
-
-static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump)
-{
-       struct opal_sg_list *sg1, *list = NULL;
-       void *addr;
-       int64_t size;
-
-       addr = dump->buffer;
-       size = dump->size;
-
-       sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!sg1)
-               goto nomem;
-
-       list = sg1;
-       sg1->num_entries = 0;
-       while (size > 0) {
-               /* Translate virtual address to physical address */
-               sg1->entry[sg1->num_entries].data =
-                       (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
-
-               if (size > PAGE_SIZE)
-                       sg1->entry[sg1->num_entries].length = PAGE_SIZE;
-               else
-                       sg1->entry[sg1->num_entries].length = size;
-
-               sg1->num_entries++;
-               if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
-                       sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
-                       if (!sg1->next)
-                               goto nomem;
-
-                       sg1 = sg1->next;
-                       sg1->num_entries = 0;
-               }
-               addr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       return list;
-
-nomem:
-       pr_err("%s : Failed to allocate memory\n", __func__);
-       free_dump_sg_list(list);
-       return NULL;
-}
-
-static void sglist_to_phy_addr(struct opal_sg_list *list)
-{
-       struct opal_sg_list *sg, *next;
-
-       for (sg = list; sg; sg = next) {
-               next = sg->next;
-               /* Don't translate NULL pointer for last entry */
-               if (sg->next)
-                       sg->next = (struct opal_sg_list *)__pa(sg->next);
-               else
-                       sg->next = NULL;
-
-               /* Convert num_entries to length */
-               sg->num_entries =
-                       sg->num_entries * sizeof(struct opal_sg_entry) + 16;
-       }
-}
-
-static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type)
+static int64_t dump_read_info(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type)
 {
+       __be32 id, size, type;
        int rc;
-       *type = 0xffffffff;
 
-       rc = opal_dump_info2(id, size, type);
+       type = cpu_to_be32(0xffffffff);
 
+       rc = opal_dump_info2(&id, &size, &type);
        if (rc == OPAL_PARAMETER)
-               rc = opal_dump_info(id, size);
+               rc = opal_dump_info(&id, &size);
+
+       *dump_id = be32_to_cpu(id);
+       *dump_size = be32_to_cpu(size);
+       *dump_type = be32_to_cpu(type);
 
        if (rc)
                pr_warn("%s: Failed to get dump info (%d)\n",
@@ -314,15 +245,12 @@ static int64_t dump_read_data(struct dump_obj *dump)
        }
 
        /* Generate SG list */
-       list = dump_data_to_sglist(dump);
+       list = opal_vmalloc_to_sg_list(dump->buffer, dump->size);
        if (!list) {
                rc = -ENOMEM;
                goto out;
        }
 
-       /* Translate sg list addr to real address */
-       sglist_to_phy_addr(list);
-
        /* First entry address */
        addr = __pa(list);
 
@@ -341,7 +269,7 @@ static int64_t dump_read_data(struct dump_obj *dump)
                        __func__, dump->id);
 
        /* Free SG list */
-       free_dump_sg_list(list);
+       opal_free_sg_list(list);
 
 out:
        return rc;
index ef7bc2a978627422d659d783ea21f0869975df53..10268c41d8302dd39ed73f4e0ad98dd6deb5e25f 100644 (file)
@@ -238,18 +238,25 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
 
 static void elog_work_fn(struct work_struct *work)
 {
-       size_t elog_size;
+       __be64 size;
+       __be64 id;
+       __be64 type;
+       uint64_t elog_size;
        uint64_t log_id;
        uint64_t elog_type;
        int rc;
        char name[2+16+1];
 
-       rc = opal_get_elog_size(&log_id, &elog_size, &elog_type);
+       rc = opal_get_elog_size(&id, &size, &type);
        if (rc != OPAL_SUCCESS) {
                pr_err("ELOG: Opal log read failed\n");
                return;
        }
 
+       elog_size = be64_to_cpu(size);
+       log_id = be64_to_cpu(id);
+       elog_type = be64_to_cpu(type);
+
        BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
 
        if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
index 714ef972406bcacf66a4a896283c6fb25963ca16..145a80bc535492be11a521c97f9aa724a0122cc0 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
+#include <linux/delay.h>
 
 #include <asm/opal.h>
 
@@ -79,9 +80,6 @@
 /* XXX: Assume candidate image size is <= 1GB */
 #define MAX_IMAGE_SIZE 0x40000000
 
-/* Flash sg list version */
-#define SG_LIST_VERSION (1UL)
-
 /* Image status */
 enum {
        IMAGE_INVALID,
@@ -131,11 +129,15 @@ static DEFINE_MUTEX(image_data_mutex);
  */
 static inline void opal_flash_validate(void)
 {
-       struct validate_flash_t *args_buf = &validate_flash_data;
+       long ret;
+       void *buf = validate_flash_data.buf;
+       __be32 size, result;
 
-       args_buf->status = opal_validate_flash(__pa(args_buf->buf),
-                                              &(args_buf->buf_size),
-                                              &(args_buf->result));
+       ret = opal_validate_flash(__pa(buf), &size, &result);
+
+       validate_flash_data.status = ret;
+       validate_flash_data.buf_size = be32_to_cpu(size);
+       validate_flash_data.result = be32_to_cpu(result);
 }
 
 /*
@@ -267,94 +269,12 @@ static ssize_t manage_store(struct kobject *kobj,
        return count;
 }
 
-/*
- * Free sg list
- */
-static void free_sg_list(struct opal_sg_list *list)
-{
-       struct opal_sg_list *sg1;
-       while (list) {
-               sg1 = list->next;
-               kfree(list);
-               list = sg1;
-       }
-       list = NULL;
-}
-
-/*
- * Build candidate image scatter gather list
- *
- * list format:
- *   -----------------------------------
- *  |  VER (8) | Entry length in bytes  |
- *   -----------------------------------
- *  |  Pointer to next entry            |
- *   -----------------------------------
- *  |  Address of memory area 1         |
- *   -----------------------------------
- *  |  Length of memory area 1          |
- *   -----------------------------------
- *  |   .........                       |
- *   -----------------------------------
- *  |   .........                       |
- *   -----------------------------------
- *  |  Address of memory area N         |
- *   -----------------------------------
- *  |  Length of memory area N          |
- *   -----------------------------------
- */
-static struct opal_sg_list *image_data_to_sglist(void)
-{
-       struct opal_sg_list *sg1, *list = NULL;
-       void *addr;
-       int size;
-
-       addr = image_data.data;
-       size = image_data.size;
-
-       sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!sg1)
-               return NULL;
-
-       list = sg1;
-       sg1->num_entries = 0;
-       while (size > 0) {
-               /* Translate virtual address to physical address */
-               sg1->entry[sg1->num_entries].data =
-                       (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
-
-               if (size > PAGE_SIZE)
-                       sg1->entry[sg1->num_entries].length = PAGE_SIZE;
-               else
-                       sg1->entry[sg1->num_entries].length = size;
-
-               sg1->num_entries++;
-               if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
-                       sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
-                       if (!sg1->next) {
-                               pr_err("%s : Failed to allocate memory\n",
-                                      __func__);
-                               goto nomem;
-                       }
-
-                       sg1 = sg1->next;
-                       sg1->num_entries = 0;
-               }
-               addr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       return list;
-nomem:
-       free_sg_list(list);
-       return NULL;
-}
-
 /*
  * OPAL update flash
  */
 static int opal_flash_update(int op)
 {
-       struct opal_sg_list *sg, *list, *next;
+       struct opal_sg_list *list;
        unsigned long addr;
        int64_t rc = OPAL_PARAMETER;
 
@@ -364,35 +284,13 @@ static int opal_flash_update(int op)
                goto flash;
        }
 
-       list = image_data_to_sglist();
+       list = opal_vmalloc_to_sg_list(image_data.data, image_data.size);
        if (!list)
                goto invalid_img;
 
        /* First entry address */
        addr = __pa(list);
 
-       /* Translate sg list address to absolute */
-       for (sg = list; sg; sg = next) {
-               next = sg->next;
-               /* Don't translate NULL pointer for last entry */
-               if (sg->next)
-                       sg->next = (struct opal_sg_list *)__pa(sg->next);
-               else
-                       sg->next = NULL;
-
-               /*
-                * Convert num_entries to version/length format
-                * to satisfy OPAL.
-                */
-               sg->num_entries = (SG_LIST_VERSION << 56) |
-                       (sg->num_entries * sizeof(struct opal_sg_entry) + 16);
-       }
-
-       pr_alert("FLASH: Image is %u bytes\n", image_data.size);
-       pr_alert("FLASH: Image update requested\n");
-       pr_alert("FLASH: Image will be updated during system reboot\n");
-       pr_alert("FLASH: This will take several minutes. Do not power off!\n");
-
 flash:
        rc = opal_update_flash(addr);
 
@@ -400,6 +298,47 @@ invalid_img:
        return rc;
 }
 
+/* Return CPUs to OPAL before starting FW update */
+static void flash_return_cpu(void *info)
+{
+       int cpu = smp_processor_id();
+
+       if (!cpu_online(cpu))
+               return;
+
+       /* Disable IRQ */
+       hard_irq_disable();
+
+       /* Return the CPU to OPAL */
+       opal_return_cpu();
+}
+
+/* This gets called just before system reboots */
+void opal_flash_term_callback(void)
+{
+       struct cpumask mask;
+
+       if (update_flash_data.status != FLASH_IMG_READY)
+               return;
+
+       pr_alert("FLASH: Flashing new firmware\n");
+       pr_alert("FLASH: Image is %u bytes\n", image_data.size);
+       pr_alert("FLASH: Performing flash and reboot/shutdown\n");
+       pr_alert("FLASH: This will take several minutes. Do not power off!\n");
+
+       /* Small delay to help getting the above message out */
+       msleep(500);
+
+       /* Return secondary CPUs to firmware */
+       cpumask_copy(&mask, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &mask);
+       if (!cpumask_empty(&mask))
+               smp_call_function_many(&mask,
+                                      flash_return_cpu, NULL, false);
+       /* Hard disable interrupts */
+       hard_irq_disable();
+}
+
 /*
  * Show candidate image status
  */
index 6b614726baf2add5f95237647f128c5c7119e173..d202f9bc3683f5ad0072282173ddfb510b1aec9a 100644 (file)
@@ -39,10 +39,11 @@ struct param_attr {
        struct kobj_attribute kobj_attr;
 };
 
-static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
+static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
 {
        struct opal_msg msg;
-       int ret, token;
+       ssize_t ret;
+       int token;
 
        token = opal_async_get_token_interruptible();
        if (token < 0) {
@@ -59,7 +60,7 @@ static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
 
        ret = opal_async_wait_response(token, &msg);
        if (ret) {
-               pr_err("%s: Failed to wait for the async response, %d\n",
+               pr_err("%s: Failed to wait for the async response, %zd\n",
                                __func__, ret);
                goto out_token;
        }
@@ -111,7 +112,7 @@ static ssize_t sys_param_show(struct kobject *kobj,
 {
        struct param_attr *attr = container_of(kobj_attr, struct param_attr,
                        kobj_attr);
-       int ret;
+       ssize_t ret;
 
        mutex_lock(&opal_sysparam_mutex);
        ret = opal_get_sys_param(attr->param_id, attr->param_size,
@@ -121,9 +122,10 @@ static ssize_t sys_param_show(struct kobject *kobj,
 
        memcpy(buf, param_data_buf, attr->param_size);
 
+       ret = attr->param_size;
 out:
        mutex_unlock(&opal_sysparam_mutex);
-       return ret ? ret : attr->param_size;
+       return ret;
 }
 
 static ssize_t sys_param_store(struct kobject *kobj,
@@ -131,14 +133,20 @@ static ssize_t sys_param_store(struct kobject *kobj,
 {
        struct param_attr *attr = container_of(kobj_attr, struct param_attr,
                        kobj_attr);
-       int ret;
+       ssize_t ret;
+
+        /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
+        if (count > MAX_PARAM_DATA_LEN)
+                count = MAX_PARAM_DATA_LEN;
 
        mutex_lock(&opal_sysparam_mutex);
        memcpy(param_data_buf, buf, count);
        ret = opal_set_sys_param(attr->param_id, attr->param_size,
                        param_data_buf);
        mutex_unlock(&opal_sysparam_mutex);
-       return ret ? ret : count;
+       if (!ret)
+               ret = count;
+       return ret;
 }
 
 void __init opal_sys_param_init(void)
@@ -214,13 +222,13 @@ void __init opal_sys_param_init(void)
        }
 
        if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
-               pr_err("SYSPARAM: Missing propery param-len in the DT\n");
+               pr_err("SYSPARAM: Missing property param-len in the DT\n");
                goto out_free_perm;
        }
 
 
        if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
-               pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
+               pr_err("SYSPARAM: Missing property param-perm in the DT\n");
                goto out_free_perm;
        }
 
@@ -233,6 +241,12 @@ void __init opal_sys_param_init(void)
 
        /* For each of the parameters, populate the parameter attributes */
        for (i = 0; i < count; i++) {
+               if (size[i] > MAX_PARAM_DATA_LEN) {
+                       pr_warn("SYSPARAM: Not creating parameter %d as size "
+                               "exceeds buffer length\n", i);
+                       continue;
+               }
+
                sysfs_attr_init(&attr[i].kobj_attr.attr);
                attr[i].param_id = id[i];
                attr[i].param_size = size[i];
index 3cd262897c272c5ee62f577bf4c9cef052f5a8c0..11a3169ee583635607a41406a7a571872cee97d9 100644 (file)
 _GLOBAL(opal_query_takeover)
        mfcr    r0
        stw     r0,8(r1)
+       stdu    r1,-STACKFRAMESIZE(r1)
        std     r3,STK_PARAM(R3)(r1)
        std     r4,STK_PARAM(R4)(r1)
        li      r3,H_HAL_TAKEOVER
        li      r4,H_HAL_TAKEOVER_QUERY_MAGIC
        HVSC
+       addi    r1,r1,STACKFRAMESIZE
        ld      r10,STK_PARAM(R3)(r1)
        std     r4,0(r10)
        ld      r10,STK_PARAM(R4)(r1)
index f531ffe35b3e052e870c5359619165e7bb5f0421..b5ebc545a373c93c09a21265de03f237833bfaf5 100644 (file)
@@ -32,7 +32,7 @@
        std     r12,PACASAVEDMSR(r13);  \
        andc    r12,r12,r0;             \
        mtmsrd  r12,1;                  \
-       LOAD_REG_ADDR(r0,.opal_return); \
+       LOAD_REG_ADDR(r0,opal_return);  \
        mtlr    r0;                     \
        li      r0,MSR_DR|MSR_IR|MSR_LE;\
        andc    r12,r12,r0;             \
@@ -44,7 +44,7 @@
        mtspr   SPRN_HSRR0,r12;         \
        hrfid
 
-_STATIC(opal_return)
+opal_return:
        /*
         * Fixup endian on OPAL return... we should be able to simplify
         * this by instead converting the below trampoline to a set of
index 49d2f00019e5d8092f7f32e9b3c6dfc53cceeee6..360ad80c754ce3c97ad9b9fead5ad4806e5f6666 100644 (file)
@@ -242,14 +242,14 @@ void opal_notifier_update_evt(uint64_t evt_mask,
 void opal_notifier_enable(void)
 {
        int64_t rc;
-       uint64_t evt = 0;
+       __be64 evt = 0;
 
        atomic_set(&opal_notifier_hold, 0);
 
        /* Process pending events */
        rc = opal_poll_events(&evt);
        if (rc == OPAL_SUCCESS && evt)
-               opal_do_notifier(evt);
+               opal_do_notifier(be64_to_cpu(evt));
 }
 
 void opal_notifier_disable(void)
@@ -529,7 +529,7 @@ static irqreturn_t opal_interrupt(int irq, void *data)
 
        opal_handle_interrupt(virq_to_hw(irq), &events);
 
-       opal_do_notifier(events);
+       opal_do_notifier(be64_to_cpu(events));
 
        return IRQ_HANDLED;
 }
@@ -638,3 +638,66 @@ void opal_shutdown(void)
 
 /* Export this so that test modules can use it */
 EXPORT_SYMBOL_GPL(opal_invalid_call);
+
+/* Convert a region of vmalloc memory to an opal sg list */
+struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
+                                            unsigned long vmalloc_size)
+{
+       struct opal_sg_list *sg, *first = NULL;
+       unsigned long i = 0;
+
+       sg = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!sg)
+               goto nomem;
+
+       first = sg;
+
+       while (vmalloc_size > 0) {
+               uint64_t data = vmalloc_to_pfn(vmalloc_addr) << PAGE_SHIFT;
+               uint64_t length = min(vmalloc_size, PAGE_SIZE);
+
+               sg->entry[i].data = cpu_to_be64(data);
+               sg->entry[i].length = cpu_to_be64(length);
+               i++;
+
+               if (i >= SG_ENTRIES_PER_NODE) {
+                       struct opal_sg_list *next;
+
+                       next = kzalloc(PAGE_SIZE, GFP_KERNEL);
+                       if (!next)
+                               goto nomem;
+
+                       sg->length = cpu_to_be64(
+                                       i * sizeof(struct opal_sg_entry) + 16);
+                       i = 0;
+                       sg->next = cpu_to_be64(__pa(next));
+                       sg = next;
+               }
+
+               vmalloc_addr += length;
+               vmalloc_size -= length;
+       }
+
+       sg->length = cpu_to_be64(i * sizeof(struct opal_sg_entry) + 16);
+
+       return first;
+
+nomem:
+       pr_err("%s : Failed to allocate memory\n", __func__);
+       opal_free_sg_list(first);
+       return NULL;
+}
+
+void opal_free_sg_list(struct opal_sg_list *sg)
+{
+       while (sg) {
+               uint64_t next = be64_to_cpu(sg->next);
+
+               kfree(sg);
+
+               if (next)
+                       sg = __va(next);
+               else
+                       sg = NULL;
+       }
+}
index 3b2b4fb3585b6b9fac45878041772285591d1d63..de19edeaa7a75f1e21dedd0babbf57727c6d4afb 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/crash_dump.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -343,7 +344,6 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
                                pci_name(dev));
                        continue;
                }
-               pci_dev_get(dev);
                pdn->pcidev = dev;
                pdn->pe_number = pe->pe_number;
                pe->dma_weight += pnv_ioda_dma_weight(dev);
@@ -462,7 +462,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
 
        pe = &phb->ioda.pe_array[pdn->pe_number];
        WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
-       set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
+       set_iommu_table_base(&pdev->dev, &pe->tce32_table);
 }
 
 static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
@@ -664,15 +664,15 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
                 * errors, and on the first pass the data will be a relative
                 * bus number, print that out instead.
                 */
-               tbl->it_busno = 0;
                pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
                tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
                                8);
-               tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE |
-                              TCE_PCI_SWINV_PAIR;
+               tbl->it_type |= (TCE_PCI_SWINV_CREATE |
+                                TCE_PCI_SWINV_FREE   |
+                                TCE_PCI_SWINV_PAIR);
        }
        iommu_init_table(tbl, phb->hose->node);
-       iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
+       iommu_register_group(tbl, phb->hose->global_number, pe->pe_number);
 
        if (pe->pdev)
                set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
@@ -794,14 +794,13 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
                 * errors, and on the first pass the data will be a relative
                 * bus number, print that out instead.
                 */
-               tbl->it_busno = 0;
                pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
                tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
                                8);
-               tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE;
+               tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
        }
        iommu_init_table(tbl, phb->hose->node);
-       iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
+       iommu_register_group(tbl, phb->hose->global_number, pe->pe_number);
 
        if (pe->pdev)
                set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
@@ -1387,12 +1386,24 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
        ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
        ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
        ppc_md.pcibios_window_alignment = pnv_pci_window_alignment;
+       ppc_md.pcibios_reset_secondary_bus = pnv_pci_reset_secondary_bus;
        pci_add_flags(PCI_REASSIGN_ALL_RSRC);
 
        /* Reset IODA tables to a clean state */
        rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
        if (rc)
                pr_warning("  OPAL Error %ld performing IODA table reset !\n", rc);
+
+       /* If we're running in kdump kerenl, the previous kerenl never
+        * shutdown PCI devices correctly. We already got IODA table
+        * cleaned out. So we have to issue PHB reset to stop all PCI
+        * transactions from previous kerenl.
+        */
+       if (is_kdump_kernel()) {
+               pr_info("  Issue PHB reset ...\n");
+               ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
+               ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET);
+       }
 }
 
 void __init pnv_pci_init_ioda2_phb(struct device_node *np)
index 8518817dcdfdc95d04e3b1fc10bfe54432330079..eefbfcc3fd8c40a9d50b9839fb2292f723c7970d 100644 (file)
@@ -131,65 +131,60 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
        int i;
 
        data = (struct OpalIoP7IOCPhbErrorData *)common;
-       pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n",
+       pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n",
                hose->global_number, common->version);
 
        if (data->brdgCtl)
-               pr_info("  brdgCtl:     %08x\n",
+               pr_info("brdgCtl:     %08x\n",
                        data->brdgCtl);
        if (data->portStatusReg || data->rootCmplxStatus ||
            data->busAgentStatus)
-               pr_info("  UtlSts:      %08x %08x %08x\n",
+               pr_info("UtlSts:      %08x %08x %08x\n",
                        data->portStatusReg, data->rootCmplxStatus,
                        data->busAgentStatus);
        if (data->deviceStatus || data->slotStatus   ||
            data->linkStatus   || data->devCmdStatus ||
            data->devSecStatus)
-               pr_info("  RootSts:     %08x %08x %08x %08x %08x\n",
+               pr_info("RootSts:     %08x %08x %08x %08x %08x\n",
                        data->deviceStatus, data->slotStatus,
                        data->linkStatus, data->devCmdStatus,
                        data->devSecStatus);
        if (data->rootErrorStatus   || data->uncorrErrorStatus ||
            data->corrErrorStatus)
-               pr_info("  RootErrSts:  %08x %08x %08x\n",
+               pr_info("RootErrSts:  %08x %08x %08x\n",
                        data->rootErrorStatus, data->uncorrErrorStatus,
                        data->corrErrorStatus);
        if (data->tlpHdr1 || data->tlpHdr2 ||
            data->tlpHdr3 || data->tlpHdr4)
-               pr_info("  RootErrLog:  %08x %08x %08x %08x\n",
+               pr_info("RootErrLog:  %08x %08x %08x %08x\n",
                        data->tlpHdr1, data->tlpHdr2,
                        data->tlpHdr3, data->tlpHdr4);
        if (data->sourceId || data->errorClass ||
            data->correlator)
-               pr_info("  RootErrLog1: %08x %016llx %016llx\n",
+               pr_info("RootErrLog1: %08x %016llx %016llx\n",
                        data->sourceId, data->errorClass,
                        data->correlator);
        if (data->p7iocPlssr || data->p7iocCsr)
-               pr_info("  PhbSts:      %016llx %016llx\n",
+               pr_info("PhbSts:      %016llx %016llx\n",
                        data->p7iocPlssr, data->p7iocCsr);
-       if (data->lemFir || data->lemErrorMask ||
-           data->lemWOF)
-               pr_info("  Lem:         %016llx %016llx %016llx\n",
+       if (data->lemFir)
+               pr_info("Lem:         %016llx %016llx %016llx\n",
                        data->lemFir, data->lemErrorMask,
                        data->lemWOF);
-       if (data->phbErrorStatus || data->phbFirstErrorStatus ||
-           data->phbErrorLog0   || data->phbErrorLog1)
-               pr_info("  PhbErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->phbErrorStatus)
+               pr_info("PhbErr:      %016llx %016llx %016llx %016llx\n",
                        data->phbErrorStatus, data->phbFirstErrorStatus,
                        data->phbErrorLog0, data->phbErrorLog1);
-       if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
-           data->mmioErrorLog0   || data->mmioErrorLog1)
-               pr_info("  OutErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->mmioErrorStatus)
+               pr_info("OutErr:      %016llx %016llx %016llx %016llx\n",
                        data->mmioErrorStatus, data->mmioFirstErrorStatus,
                        data->mmioErrorLog0, data->mmioErrorLog1);
-       if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
-           data->dma0ErrorLog0   || data->dma0ErrorLog1)
-               pr_info("  InAErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->dma0ErrorStatus)
+               pr_info("InAErr:      %016llx %016llx %016llx %016llx\n",
                        data->dma0ErrorStatus, data->dma0FirstErrorStatus,
                        data->dma0ErrorLog0, data->dma0ErrorLog1);
-       if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
-           data->dma1ErrorLog0   || data->dma1ErrorLog1)
-               pr_info("  InBErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->dma1ErrorStatus)
+               pr_info("InBErr:      %016llx %016llx %016llx %016llx\n",
                        data->dma1ErrorStatus, data->dma1FirstErrorStatus,
                        data->dma1ErrorLog0, data->dma1ErrorLog1);
 
@@ -198,7 +193,7 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
                    (data->pestB[i] >> 63) == 0)
                        continue;
 
-               pr_info("  PE[%3d] A/B: %016llx %016llx\n",
+               pr_info("PE[%3d] A/B: %016llx %016llx\n",
                        i, data->pestA[i], data->pestB[i]);
        }
 }
@@ -210,69 +205,63 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
        int i;
 
        data = (struct OpalIoPhb3ErrorData*)common;
-       pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n",
+       pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n",
                hose->global_number, common->version);
        if (data->brdgCtl)
-               pr_info("  brdgCtl:     %08x\n",
+               pr_info("brdgCtl:     %08x\n",
                        data->brdgCtl);
        if (data->portStatusReg || data->rootCmplxStatus ||
            data->busAgentStatus)
-               pr_info("  UtlSts:      %08x %08x %08x\n",
+               pr_info("UtlSts:      %08x %08x %08x\n",
                        data->portStatusReg, data->rootCmplxStatus,
                        data->busAgentStatus);
        if (data->deviceStatus || data->slotStatus   ||
            data->linkStatus   || data->devCmdStatus ||
            data->devSecStatus)
-               pr_info("  RootSts:     %08x %08x %08x %08x %08x\n",
+               pr_info("RootSts:     %08x %08x %08x %08x %08x\n",
                        data->deviceStatus, data->slotStatus,
                        data->linkStatus, data->devCmdStatus,
                        data->devSecStatus);
        if (data->rootErrorStatus || data->uncorrErrorStatus ||
            data->corrErrorStatus)
-               pr_info("  RootErrSts:  %08x %08x %08x\n",
+               pr_info("RootErrSts:  %08x %08x %08x\n",
                        data->rootErrorStatus, data->uncorrErrorStatus,
                        data->corrErrorStatus);
        if (data->tlpHdr1 || data->tlpHdr2 ||
            data->tlpHdr3 || data->tlpHdr4)
-               pr_info("  RootErrLog:  %08x %08x %08x %08x\n",
+               pr_info("RootErrLog:  %08x %08x %08x %08x\n",
                        data->tlpHdr1, data->tlpHdr2,
                        data->tlpHdr3, data->tlpHdr4);
        if (data->sourceId || data->errorClass ||
            data->correlator)
-               pr_info("  RootErrLog1: %08x %016llx %016llx\n",
+               pr_info("RootErrLog1: %08x %016llx %016llx\n",
                        data->sourceId, data->errorClass,
                        data->correlator);
-       if (data->nFir || data->nFirMask ||
-           data->nFirWOF)
-               pr_info("  nFir:        %016llx %016llx %016llx\n",
+       if (data->nFir)
+               pr_info("nFir:        %016llx %016llx %016llx\n",
                        data->nFir, data->nFirMask,
                        data->nFirWOF);
        if (data->phbPlssr || data->phbCsr)
-               pr_info("  PhbSts:      %016llx %016llx\n",
+               pr_info("PhbSts:      %016llx %016llx\n",
                        data->phbPlssr, data->phbCsr);
-       if (data->lemFir || data->lemErrorMask ||
-           data->lemWOF)
-               pr_info("  Lem:         %016llx %016llx %016llx\n",
+       if (data->lemFir)
+               pr_info("Lem:         %016llx %016llx %016llx\n",
                        data->lemFir, data->lemErrorMask,
                        data->lemWOF);
-       if (data->phbErrorStatus || data->phbFirstErrorStatus ||
-           data->phbErrorLog0   || data->phbErrorLog1)
-               pr_info("  PhbErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->phbErrorStatus)
+               pr_info("PhbErr:      %016llx %016llx %016llx %016llx\n",
                        data->phbErrorStatus, data->phbFirstErrorStatus,
                        data->phbErrorLog0, data->phbErrorLog1);
-       if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
-           data->mmioErrorLog0   || data->mmioErrorLog1)
-               pr_info("  OutErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->mmioErrorStatus)
+               pr_info("OutErr:      %016llx %016llx %016llx %016llx\n",
                        data->mmioErrorStatus, data->mmioFirstErrorStatus,
                        data->mmioErrorLog0, data->mmioErrorLog1);
-       if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
-           data->dma0ErrorLog0   || data->dma0ErrorLog1)
-               pr_info("  InAErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->dma0ErrorStatus)
+               pr_info("InAErr:      %016llx %016llx %016llx %016llx\n",
                        data->dma0ErrorStatus, data->dma0FirstErrorStatus,
                        data->dma0ErrorLog0, data->dma0ErrorLog1);
-       if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
-           data->dma1ErrorLog0   || data->dma1ErrorLog1)
-               pr_info("  InBErr:      %016llx %016llx %016llx %016llx\n",
+       if (data->dma1ErrorStatus)
+               pr_info("InBErr:      %016llx %016llx %016llx %016llx\n",
                        data->dma1ErrorStatus, data->dma1FirstErrorStatus,
                        data->dma1ErrorLog0, data->dma1ErrorLog1);
 
@@ -281,7 +270,7 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
                    (data->pestB[i] >> 63) == 0)
                        continue;
 
-               pr_info("  PE[%3d] A/B: %016llx %016llx\n",
+               pr_info("PE[%3d] A/B: %016llx %016llx\n",
                        i, data->pestA[i], data->pestB[i]);
        }
 }
@@ -384,9 +373,6 @@ int pnv_pci_cfg_read(struct device_node *dn,
        struct pci_dn *pdn = PCI_DN(dn);
        struct pnv_phb *phb = pdn->phb->private_data;
        u32 bdfn = (pdn->busno << 8) | pdn->devfn;
-#ifdef CONFIG_EEH
-       struct eeh_pe *phb_pe = NULL;
-#endif
        s64 rc;
 
        switch (size) {
@@ -412,31 +398,9 @@ int pnv_pci_cfg_read(struct device_node *dn,
        default:
                return PCIBIOS_FUNC_NOT_SUPPORTED;
        }
+
        cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
                __func__, pdn->busno, pdn->devfn, where, size, *val);
-
-       /*
-        * Check if the specified PE has been put into frozen
-        * state. On the other hand, we needn't do that while
-        * the PHB has been put into frozen state because of
-        * PHB-fatal errors.
-        */
-#ifdef CONFIG_EEH
-       phb_pe = eeh_phb_pe_get(pdn->phb);
-       if (phb_pe && (phb_pe->state & EEH_PE_ISOLATED))
-               return PCIBIOS_SUCCESSFUL;
-
-       if (phb->eeh_state & PNV_EEH_STATE_ENABLED) {
-               if (*val == EEH_IO_ERROR_VALUE(size) &&
-                   eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-       } else {
-               pnv_pci_config_check_eeh(phb, dn);
-       }
-#else
-       pnv_pci_config_check_eeh(phb, dn);
-#endif
-
        return PCIBIOS_SUCCESSFUL;
 }
 
@@ -463,33 +427,74 @@ int pnv_pci_cfg_write(struct device_node *dn,
                return PCIBIOS_FUNC_NOT_SUPPORTED;
        }
 
-       /* Check if the PHB got frozen due to an error (no response) */
-#ifdef CONFIG_EEH
-       if (!(phb->eeh_state & PNV_EEH_STATE_ENABLED))
-               pnv_pci_config_check_eeh(phb, dn);
-#else
-       pnv_pci_config_check_eeh(phb, dn);
-#endif
-
        return PCIBIOS_SUCCESSFUL;
 }
 
+#if CONFIG_EEH
+static bool pnv_pci_cfg_check(struct pci_controller *hose,
+                             struct device_node *dn)
+{
+       struct eeh_dev *edev = NULL;
+       struct pnv_phb *phb = hose->private_data;
+
+       /* EEH not enabled ? */
+       if (!(phb->flags & PNV_PHB_FLAG_EEH))
+               return true;
+
+       /* PE reset or device removed ? */
+       edev = of_node_to_eeh_dev(dn);
+       if (edev) {
+               if (edev->pe &&
+                   (edev->pe->state & EEH_PE_RESET))
+                       return false;
+
+               if (edev->mode & EEH_DEV_REMOVED)
+                       return false;
+       }
+
+       return true;
+}
+#else
+static inline pnv_pci_cfg_check(struct pci_controller *hose,
+                               struct device_node *dn)
+{
+       return true;
+}
+#endif /* CONFIG_EEH */
+
 static int pnv_pci_read_config(struct pci_bus *bus,
                               unsigned int devfn,
                               int where, int size, u32 *val)
 {
        struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
        struct pci_dn *pdn;
+       struct pnv_phb *phb;
+       bool found = false;
+       int ret;
 
+       *val = 0xFFFFFFFF;
        for (dn = busdn->child; dn; dn = dn->sibling) {
                pdn = PCI_DN(dn);
-               if (pdn && pdn->devfn == devfn)
-                       return pnv_pci_cfg_read(dn, where, size, val);
+               if (pdn && pdn->devfn == devfn) {
+                       phb = pdn->phb->private_data;
+                       found = true;
+                       break;
+               }
        }
 
-       *val = 0xFFFFFFFF;
-       return PCIBIOS_DEVICE_NOT_FOUND;
+       if (!found || !pnv_pci_cfg_check(pdn->phb, dn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
 
+       ret = pnv_pci_cfg_read(dn, where, size, val);
+       if (phb->flags & PNV_PHB_FLAG_EEH) {
+               if (*val == EEH_IO_ERROR_VALUE(size) &&
+                   eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
+                        return PCIBIOS_DEVICE_NOT_FOUND;
+       } else {
+               pnv_pci_config_check_eeh(phb, dn);
+       }
+
+       return ret;
 }
 
 static int pnv_pci_write_config(struct pci_bus *bus,
@@ -498,14 +503,27 @@ static int pnv_pci_write_config(struct pci_bus *bus,
 {
        struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
        struct pci_dn *pdn;
+       struct pnv_phb *phb;
+       bool found = false;
+       int ret;
 
        for (dn = busdn->child; dn; dn = dn->sibling) {
                pdn = PCI_DN(dn);
-               if (pdn && pdn->devfn == devfn)
-                       return pnv_pci_cfg_write(dn, where, size, val);
+               if (pdn && pdn->devfn == devfn) {
+                       phb = pdn->phb->private_data;
+                       found = true;
+                       break;
+               }
        }
 
-       return PCIBIOS_DEVICE_NOT_FOUND;
+       if (!found || !pnv_pci_cfg_check(pdn->phb, dn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       ret = pnv_pci_cfg_write(dn, where, size, val);
+       if (!(phb->flags & PNV_PHB_FLAG_EEH))
+               pnv_pci_config_check_eeh(phb, dn);
+
+       return ret;
 }
 
 struct pci_ops pnv_pci_ops = {
index cde169442775c1684f0cd9f2db799d17c685deb3..676232c34328143a4d01719ee7ba5b40b0455965 100644 (file)
@@ -81,28 +81,27 @@ struct pnv_eeh_ops {
        int (*configure_bridge)(struct eeh_pe *pe);
        int (*next_error)(struct eeh_pe **pe);
 };
-
-#define PNV_EEH_STATE_ENABLED  (1 << 0)        /* EEH enabled  */
-#define PNV_EEH_STATE_REMOVED  (1 << 1)        /* PHB removed  */
-
 #endif /* CONFIG_EEH */
 
+#define PNV_PHB_FLAG_EEH       (1 << 0)
+
 struct pnv_phb {
        struct pci_controller   *hose;
        enum pnv_phb_type       type;
        enum pnv_phb_model      model;
        u64                     hub_id;
        u64                     opal_id;
+       int                     flags;
        void __iomem            *regs;
        int                     initialized;
        spinlock_t              lock;
 
 #ifdef CONFIG_EEH
        struct pnv_eeh_ops      *eeh_ops;
-       int                     eeh_state;
 #endif
 
 #ifdef CONFIG_DEBUG_FS
+       int                     has_dbgfs;
        struct dentry           *dbgfs;
 #endif
 
@@ -205,5 +204,7 @@ extern void pnv_pci_init_ioda_hub(struct device_node *np);
 extern void pnv_pci_init_ioda2_phb(struct device_node *np);
 extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
                                        __be64 *startp, __be64 *endp, bool rm);
+extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
+extern int ioda_eeh_phb_reset(struct pci_controller *hose, int option);
 
 #endif /* __POWERNV_PCI_H */
index 61cf8fa9c61b50489009b94c99c993fffaddde28..865aab40ded700c298453871b49c844f4bfad245 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <linux/bug.h>
 #include <linux/pci.h>
+#include <linux/cpufreq.h>
 
 #include <asm/machdep.h>
 #include <asm/firmware.h>
@@ -98,11 +99,32 @@ static void pnv_show_cpuinfo(struct seq_file *m)
        of_node_put(root);
 }
 
+static void pnv_prepare_going_down(void)
+{
+       /*
+        * Disable all notifiers from OPAL, we can't
+        * service interrupts anymore anyway
+        */
+       opal_notifier_disable();
+
+       /* Soft disable interrupts */
+       local_irq_disable();
+
+       /*
+        * Return secondary CPUs to firwmare if a flash update
+        * is pending otherwise we will get all sort of error
+        * messages about CPU being stuck etc.. This will also
+        * have the side effect of hard disabling interrupts so
+        * past this point, the kernel is effectively dead.
+        */
+       opal_flash_term_callback();
+}
+
 static void  __noreturn pnv_restart(char *cmd)
 {
        long rc = OPAL_BUSY;
 
-       opal_notifier_disable();
+       pnv_prepare_going_down();
 
        while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
                rc = opal_cec_reboot();
@@ -119,7 +141,7 @@ static void __noreturn pnv_power_off(void)
 {
        long rc = OPAL_BUSY;
 
-       opal_notifier_disable();
+       pnv_prepare_going_down();
 
        while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
                rc = opal_cec_power_down(0);
@@ -162,18 +184,62 @@ static void pnv_shutdown(void)
 }
 
 #ifdef CONFIG_KEXEC
+static void pnv_kexec_wait_secondaries_down(void)
+{
+       int my_cpu, i, notified = -1;
+
+       my_cpu = get_cpu();
+
+       for_each_online_cpu(i) {
+               uint8_t status;
+               int64_t rc;
+
+               if (i == my_cpu)
+                       continue;
+
+               for (;;) {
+                       rc = opal_query_cpu_status(get_hard_smp_processor_id(i),
+                                                  &status);
+                       if (rc != OPAL_SUCCESS || status != OPAL_THREAD_STARTED)
+                               break;
+                       barrier();
+                       if (i != notified) {
+                               printk(KERN_INFO "kexec: waiting for cpu %d "
+                                      "(physical %d) to enter OPAL\n",
+                                      i, paca[i].hw_cpu_id);
+                               notified = i;
+                       }
+               }
+       }
+}
+
 static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
 {
        xics_kexec_teardown_cpu(secondary);
 
-       /* Return secondary CPUs to firmware on OPAL v3 */
-       if (firmware_has_feature(FW_FEATURE_OPALv3) && secondary) {
+       /* On OPAL v3, we return all CPUs to firmware */
+
+       if (!firmware_has_feature(FW_FEATURE_OPALv3))
+               return;
+
+       if (secondary) {
+               /* Return secondary CPUs to firmware on OPAL v3 */
                mb();
                get_paca()->kexec_state = KEXEC_STATE_REAL_MODE;
                mb();
 
                /* Return the CPU to OPAL */
                opal_return_cpu();
+       } else if (crash_shutdown) {
+               /*
+                * On crash, we don't wait for secondaries to go
+                * down as they might be unreachable or hung, so
+                * instead we just wait a bit and move on.
+                */
+               mdelay(1);
+       } else {
+               /* Primary waits for the secondaries to have reached OPAL */
+               pnv_kexec_wait_secondaries_down();
        }
 }
 #endif /* CONFIG_KEXEC */
@@ -225,6 +291,25 @@ static int __init pnv_probe(void)
        return 1;
 }
 
+/*
+ * Returns the cpu frequency for 'cpu' in Hz. This is used by
+ * /proc/cpuinfo
+ */
+unsigned long pnv_get_proc_freq(unsigned int cpu)
+{
+       unsigned long ret_freq;
+
+       ret_freq = cpufreq_quick_get(cpu) * 1000ul;
+
+       /*
+        * If the backend cpufreq driver does not exist,
+         * then fallback to old way of reporting the clockrate.
+        */
+       if (!ret_freq)
+               ret_freq = ppc_proc_freq;
+       return ret_freq;
+}
+
 define_machine(powernv) {
        .name                   = "PowerNV",
        .probe                  = pnv_probe,
@@ -232,6 +317,7 @@ define_machine(powernv) {
        .setup_arch             = pnv_setup_arch,
        .init_IRQ               = pnv_init_IRQ,
        .show_cpuinfo           = pnv_show_cpuinfo,
+       .get_proc_freq          = pnv_get_proc_freq,
        .progress               = pnv_progress,
        .machine_shutdown       = pnv_shutdown,
        .power_save             = power7_idle,
index 908672bdcea6b2c77d75763a05d10f476e2b2d75..1601a1ea02c4322cbc53f21d00b6f56c039e2276 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/cputhreads.h>
 #include <asm/xics.h>
 #include <asm/opal.h>
+#include <asm/runlatch.h>
+#include <asm/code-patching.h>
 
 #include "powernv.h"
 
@@ -49,8 +51,8 @@ static void pnv_smp_setup_cpu(int cpu)
 int pnv_smp_kick_cpu(int nr)
 {
        unsigned int pcpu = get_hard_smp_processor_id(nr);
-       unsigned long start_here = __pa(*((unsigned long *)
-                                         generic_secondary_smp_init));
+       unsigned long start_here =
+                       __pa(ppc_function_entry(generic_secondary_smp_init));
        long rc;
 
        BUG_ON(nr < 0 || nr >= NR_CPUS);
@@ -156,7 +158,9 @@ static void pnv_smp_cpu_kill_self(void)
         */
        mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
        while (!generic_check_cpu_restart(cpu)) {
+               ppc64_runlatch_off();
                power7_nap();
+               ppc64_runlatch_on();
                if (!generic_check_cpu_restart(cpu)) {
                        DBG("CPU%d Unexpected exit while offline !\n", cpu);
                        /* We may be getting an IPI, so we re-enable
index 8a8f0472d98fd0e56d9c199c85c4d513e04f8d9a..0bec0c02c5e718cc493dad1b273b09150b5f6632 100644 (file)
@@ -175,6 +175,36 @@ static int pseries_eeh_find_cap(struct device_node *dn, int cap)
        return 0;
 }
 
+static int pseries_eeh_find_ecap(struct device_node *dn, int cap)
+{
+       struct pci_dn *pdn = PCI_DN(dn);
+       struct eeh_dev *edev = of_node_to_eeh_dev(dn);
+       u32 header;
+       int pos = 256;
+       int ttl = (4096 - 256) / 8;
+
+       if (!edev || !edev->pcie_cap)
+               return 0;
+       if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL)
+               return 0;
+       else if (!header)
+               return 0;
+
+       while (ttl-- > 0) {
+               if (PCI_EXT_CAP_ID(header) == cap && pos)
+                       return pos;
+
+               pos = PCI_EXT_CAP_NEXT(header);
+               if (pos < 256)
+                       break;
+
+               if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL)
+                       break;
+       }
+
+       return 0;
+}
+
 /**
  * pseries_eeh_of_probe - EEH probe on the given device
  * @dn: OF node
@@ -220,7 +250,9 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
         * or PCIe switch downstream port.
         */
        edev->class_code = class_code;
+       edev->pcix_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_PCIX);
        edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP);
+       edev->aer_cap = pseries_eeh_find_ecap(dn, PCI_EXT_CAP_ID_ERR);
        edev->mode &= 0xFFFFFF00;
        if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
                edev->mode |= EEH_DEV_BRIDGE;
@@ -464,6 +496,7 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state)
                        } else {
                                result = EEH_STATE_NOT_SUPPORT;
                        }
+                       break;
                default:
                        result = EEH_STATE_NOT_SUPPORT;
                }
@@ -499,11 +532,19 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
        /* If fundamental-reset not supported, try hot-reset */
        if (option == EEH_RESET_FUNDAMENTAL &&
            ret == -8) {
+               option = EEH_RESET_HOT;
                ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
                                config_addr, BUID_HI(pe->phb->buid),
-                               BUID_LO(pe->phb->buid), EEH_RESET_HOT);
+                               BUID_LO(pe->phb->buid), option);
        }
 
+       /* We need reset hold or settlement delay */
+       if (option == EEH_RESET_FUNDAMENTAL ||
+           option == EEH_RESET_HOT)
+               msleep(EEH_PE_RST_HOLD_TIME);
+       else
+               msleep(EEH_PE_RST_SETTLE_TIME);
+
        return ret;
 }
 
index 9b8e05078a63e73a2993cc89890793353a45f9ea..20d62975856fb7fa5795a566629bbb69aa7a3139 100644 (file)
@@ -88,13 +88,14 @@ void set_default_offline_state(int cpu)
 
 static void rtas_stop_self(void)
 {
-       struct rtas_args args = {
-               .token = cpu_to_be32(rtas_stop_self_token),
+       static struct rtas_args args = {
                .nargs = 0,
                .nret = 1,
                .rets = &args.args[0],
        };
 
+       args.token = cpu_to_be32(rtas_stop_self_token);
+
        local_irq_disable();
 
        BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
index 573b488fc48b8a9b79674806d27599993c96b362..7f75c94af822c40322d8a4a751e983ad0e2bcdae 100644 (file)
@@ -100,10 +100,10 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
 
        start_pfn = base >> PAGE_SHIFT;
 
-       if (!pfn_valid(start_pfn)) {
-               memblock_remove(base, memblock_size);
-               return 0;
-       }
+       lock_device_hotplug();
+
+       if (!pfn_valid(start_pfn))
+               goto out;
 
        block_sz = memory_block_size_bytes();
        sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
@@ -114,8 +114,10 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
                base += MIN_MEMORY_BLOCK_SIZE;
        }
 
+out:
        /* Update memory regions for memory remove */
        memblock_remove(base, memblock_size);
+       unlock_device_hotplug();
        return 0;
 }
 
index 444fe7759e55097236a42534009304baa3cf1693..7891a86066e82dadeb0a66c56b75e233ca83c488 100644 (file)
@@ -49,7 +49,7 @@ END_FTR_SECTION(0, 1);                                                \
        std     r0,16(r1);                                      \
        addi    r4,r1,STK_PARAM(FIRST_REG);                     \
        stdu    r1,-STACK_FRAME_OVERHEAD(r1);                   \
-       bl      .__trace_hcall_entry;                           \
+       bl      __trace_hcall_entry;                            \
        addi    r1,r1,STACK_FRAME_OVERHEAD;                     \
        ld      r0,16(r1);                                      \
        ld      r3,STK_PARAM(R3)(r1);                           \
@@ -83,7 +83,7 @@ END_FTR_SECTION(0, 1);                                                \
        mr      r3,r6;                                          \
        std     r0,16(r1);                                      \
        stdu    r1,-STACK_FRAME_OVERHEAD(r1);                   \
-       bl      .__trace_hcall_exit;                            \
+       bl      __trace_hcall_exit;                             \
        addi    r1,r1,STACK_FRAME_OVERHEAD;                     \
        ld      r0,16(r1);                                      \
        ld      r3,STK_PARAM(R3)(r1);                           \
index 2db8cc691bf49dcd5b72b150c48bde8ec440f841..215c3c269617f308a633bdeb60db823d1f25cfaa 100644 (file)
@@ -510,7 +510,11 @@ static void __init pSeries_setup_arch(void)
 static int __init pSeries_init_panel(void)
 {
        /* Manually leave the kernel version on the panel. */
+#ifdef __BIG_ENDIAN__
        ppc_md.progress("Linux ppc64\n", 0);
+#else
+       ppc_md.progress("Linux ppc64le\n", 0);
+#endif
        ppc_md.progress(init_utsname()->version, 0);
 
        return 0;
index 24f58cb0a543ece1cb92242b36ec8e18c145f5be..a3555b10c1a54dc3d13cd6feb4a5d2301c64343e 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/xics.h>
 #include <asm/dbell.h>
 #include <asm/plpar_wrappers.h>
+#include <asm/code-patching.h>
 
 #include "pseries.h"
 #include "offline_states.h"
@@ -96,8 +97,8 @@ int smp_query_cpu_stopped(unsigned int pcpu)
 static inline int smp_startup_cpu(unsigned int lcpu)
 {
        int status;
-       unsigned long start_here = __pa((u32)*((unsigned long *)
-                                              generic_secondary_smp_init));
+       unsigned long start_here =
+                       __pa(ppc_function_entry(generic_secondary_smp_init));
        unsigned int pcpu;
        int start_cpu;
 
index 268bc899c1f7168ca5827920010af0b53595c228..8c79ce016cf10a1f48148fc7775be474ee40de2d 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/reg_a2.h>
 #include <asm/scom.h>
 #include <asm/udbg.h>
+#include <asm/code-patching.h>
 
 #include "wsp.h"
 
@@ -405,7 +406,7 @@ int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, struct device_node *np)
                        goto fail;
        }
 
-       start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init
+       start_here = ppc_function_entry(core_setup ? generic_secondary_smp_init
                                        : generic_secondary_thread_init);
        pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here);
 
index 7baa70d6dc016c85b8e4874f7618dbf9145d30ac..a19332a3871551713e2194e8490aaa15cb493c36 100644 (file)
@@ -7,6 +7,12 @@ config PPC4xx_PCI_EXPRESS
        depends on PCI && 4xx
        default n
 
+config PPC4xx_HSTA_MSI
+       bool
+       depends on PCI_MSI
+       depends on PCI && 4xx
+       default n
+
 config PPC4xx_MSI
        bool
        depends on PCI_MSI
index afbcc37aa094559200aff7c477bcefeabdae2c49..f7cb2a1b01fa053ddbd7df7aca8a423fc84af56f 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_OF_RTC)          += of_rtc.o
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_4xx)              += ppc4xx_pci.o
 endif
+obj-$(CONFIG_PPC4xx_HSTA_MSI)  += ppc4xx_hsta_msi.o
 obj-$(CONFIG_PPC4xx_MSI)       += ppc4xx_msi.o
 obj-$(CONFIG_PPC4xx_CPM)       += ppc4xx_cpm.o
 obj-$(CONFIG_PPC4xx_GPIO)      += ppc4xx_gpio.o
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
new file mode 100644 (file)
index 0000000..11c8884
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * MSI support for PPC4xx SoCs using High Speed Transfer Assist (HSTA) for
+ * generation of the interrupt.
+ *
+ * Copyright Â© 2013 Alistair Popple <alistair@popple.id.au> IBM 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/semaphore.h>
+#include <asm/msi_bitmap.h>
+
+struct ppc4xx_hsta_msi {
+       struct device *dev;
+
+       /* The ioremapped HSTA MSI IO space */
+       u32 __iomem *data;
+
+       /* Physical address of HSTA MSI IO space */
+       u64 address;
+       struct msi_bitmap bmp;
+
+       /* An array mapping offsets to hardware IRQs */
+       int *irq_map;
+
+       /* Number of hwirqs supported */
+       int irq_count;
+};
+static struct ppc4xx_hsta_msi ppc4xx_hsta_msi;
+
+static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       struct msi_msg msg;
+       struct msi_desc *entry;
+       int irq, hwirq;
+       u64 addr;
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1);
+               if (irq < 0) {
+                       pr_debug("%s: Failed to allocate msi interrupt\n",
+                                __func__);
+                       return irq;
+               }
+
+               hwirq = ppc4xx_hsta_msi.irq_map[irq];
+               if (hwirq == NO_IRQ) {
+                       pr_err("%s: Failed mapping irq %d\n", __func__, irq);
+                       return -EINVAL;
+               }
+
+               /*
+                * HSTA generates interrupts on writes to 128-bit aligned
+                * addresses.
+                */
+               addr = ppc4xx_hsta_msi.address + irq*0x10;
+               msg.address_hi = upper_32_bits(addr);
+               msg.address_lo = lower_32_bits(addr);
+
+               /* Data is not used by the HSTA. */
+               msg.data = 0;
+
+               pr_debug("%s: Setup irq %d (0x%0llx)\n", __func__, hwirq,
+                        (((u64) msg.address_hi) << 32) | msg.address_lo);
+
+               if (irq_set_msi_desc(hwirq, entry)) {
+                       pr_err(
+                       "%s: Invalid hwirq %d specified in device tree\n",
+                       __func__, hwirq);
+                       msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
+                       return -EINVAL;
+               }
+               write_msi_msg(hwirq, &msg);
+       }
+
+       return 0;
+}
+
+static int hsta_find_hwirq_offset(int hwirq)
+{
+       int irq;
+
+       /* Find the offset given the hwirq */
+       for (irq = 0; irq < ppc4xx_hsta_msi.irq_count; irq++)
+               if (ppc4xx_hsta_msi.irq_map[irq] == hwirq)
+                       return irq;
+
+       return -EINVAL;
+}
+
+static void hsta_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct msi_desc *entry;
+       int irq;
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               if (entry->irq == NO_IRQ)
+                       continue;
+
+               irq = hsta_find_hwirq_offset(entry->irq);
+
+               /* entry->irq should always be in irq_map */
+               BUG_ON(irq < 0);
+               irq_set_msi_desc(entry->irq, NULL);
+               msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
+               pr_debug("%s: Teardown IRQ %u (index %u)\n", __func__,
+                        entry->irq, irq);
+       }
+}
+
+static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+       /* We don't support MSI-X */
+       if (type == PCI_CAP_ID_MSIX) {
+               pr_debug("%s: MSI-X not supported.\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int hsta_msi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *mem;
+       int irq, ret, irq_count;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (IS_ERR(mem)) {
+               dev_err(dev, "Unable to get mmio space\n");
+               return -EINVAL;
+       }
+
+       irq_count = of_irq_count(dev->of_node);
+       if (!irq_count) {
+               dev_err(dev, "Unable to find IRQ range\n");
+               return -EINVAL;
+       }
+
+       ppc4xx_hsta_msi.dev = dev;
+       ppc4xx_hsta_msi.address = mem->start;
+       ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem));
+       ppc4xx_hsta_msi.irq_count = irq_count;
+       if (IS_ERR(ppc4xx_hsta_msi.data)) {
+               dev_err(dev, "Unable to map memory\n");
+               return -ENOMEM;
+       }
+
+       ret = msi_bitmap_alloc(&ppc4xx_hsta_msi.bmp, irq_count, dev->of_node);
+       if (ret)
+               goto out;
+
+       ppc4xx_hsta_msi.irq_map = kmalloc(sizeof(int) * irq_count, GFP_KERNEL);
+       if (IS_ERR(ppc4xx_hsta_msi.irq_map)) {
+               ret = -ENOMEM;
+               goto out1;
+       }
+
+       /* Setup a mapping from irq offsets to hardware irq numbers */
+       for (irq = 0; irq < irq_count; irq++) {
+               ppc4xx_hsta_msi.irq_map[irq] =
+                       irq_of_parse_and_map(dev->of_node, irq);
+               if (ppc4xx_hsta_msi.irq_map[irq] == NO_IRQ) {
+                       dev_err(dev, "Unable to map IRQ\n");
+                       ret = -EINVAL;
+                       goto out2;
+               }
+       }
+
+       ppc_md.setup_msi_irqs = hsta_setup_msi_irqs;
+       ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs;
+       ppc_md.msi_check_device = hsta_msi_check_device;
+       return 0;
+
+out2:
+       kfree(ppc4xx_hsta_msi.irq_map);
+
+out1:
+       msi_bitmap_free(&ppc4xx_hsta_msi.bmp);
+
+out:
+       iounmap(ppc4xx_hsta_msi.data);
+       return ret;
+}
+
+static const struct of_device_id hsta_msi_ids[] = {
+       {
+               .compatible = "ibm,hsta-msi",
+       },
+       {}
+};
+
+static struct platform_driver hsta_msi_driver = {
+       .probe = hsta_msi_probe,
+       .driver = {
+               .name = "hsta-msi",
+               .owner = THIS_MODULE,
+               .of_match_table = hsta_msi_ids,
+       },
+};
+
+static int hsta_msi_init(void)
+{
+       return platform_driver_register(&hsta_msi_driver);
+}
+subsys_initcall(hsta_msi_init);
index 64603a10b86313aace9d570494fcd86853357253..df6e2fc4ff926c1bceeb6c978f6aef519fae5f62 100644 (file)
@@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
                return -ENXIO;
        }
 
-       /* Check that we are fully contained within 32 bits space */
-       if (res->end > 0xffffffff) {
+       /* Check that we are fully contained within 32 bits space if we are not
+        * running on a 460sx or 476fpe which have 64 bit bus addresses.
+        */
+       if (res->end > 0xffffffff &&
+           !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
+             || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
                printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n",
                       hose->dn->full_name);
                return -ENXIO;
@@ -1058,7 +1062,7 @@ static int __init apm821xx_pciex_core_init(struct device_node *np)
        return 1;
 }
 
-static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+static int __init apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
 {
        u32 val;
 
@@ -1440,7 +1444,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
                ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops;
 #endif
 #ifdef CONFIG_476FPE
-       if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe"))
+       if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")
+               || of_device_is_compatible(np, "ibm,plb-pciex-476gtr"))
                ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops;
 #endif
        if (ppc4xx_pciex_hwops == NULL) {
@@ -1751,7 +1756,10 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port    *port,
                        dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
                                sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT
                                        | DCRO_PEGPL_OMRxMSKL_VAL);
-               else if (of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe"))
+               else if (of_device_is_compatible(
+                               port->node, "ibm,plb-pciex-476fpe") ||
+                       of_device_is_compatible(
+                               port->node, "ibm,plb-pciex-476gtr"))
                        dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
                                sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT
                                        | DCRO_PEGPL_OMRxMSKL_VAL);
@@ -1881,7 +1889,10 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
                        sa |= PCI_BASE_ADDRESS_MEM_PREFETCH;
 
                if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") ||
-                   of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe"))
+                   of_device_is_compatible(
+                           port->node, "ibm,plb-pciex-476fpe") ||
+                   of_device_is_compatible(
+                           port->node, "ibm,plb-pciex-476gtr"))
                        sa |= PCI_BASE_ADDRESS_MEM_TYPE_64;
 
                out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa));
index d68fe34799b0fc8f988b81bbeaf3a14d40afc8e3..009c58b575c09d91483b347da749bfcd75a28cd1 100644 (file)
@@ -60,7 +60,6 @@ config PCI_QUIRKS
 
 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
@@ -130,6 +129,7 @@ config S390
        select HAVE_KVM if 64BIT
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
+       select HAVE_MEMBLOCK_PHYS_MAP
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
@@ -139,6 +139,7 @@ config S390
        select HAVE_VIRT_CPU_ACCOUNTING
        select KTIME_SCALAR if 32BIT
        select MODULES_USE_ELF_RELA
+       select NO_BOOTMEM
        select OLD_SIGACTION
        select OLD_SIGSUSPEND3
        select SYSCTL_EXCEPTION_TRACE
@@ -329,6 +330,16 @@ config SYSVIPC_COMPAT
 config KEYS_COMPAT
        def_bool y if COMPAT && KEYS
 
+config S390_TICKET_SPINLOCK
+       bool "Use ticket spinlocks"
+       depends on S390 && SMP
+       default n
+       help
+         This enables support for ticket spinlocks. Ticket spinlocks
+         are more fair by means that waiting CPUs will get the lock
+         in the order they tried to obtain it.
+         The tradeoff is more complex code that could impact performance.
+
 config SMP
        def_bool y
        prompt "Symmetric multi-processing support"
@@ -592,21 +603,14 @@ 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
          into a specially reserved region and then later executed after
          a crash by kdump/kexec.
-         For more details see Documentation/kdump/kdump.txt
-
-config ZFCPDUMP
-       def_bool n
-       prompt "zfcpdump support"
-       depends on 64BIT && 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.
+         This option also enables s390 zfcpdump.
+         See also <file:Documentation/s390/zfcpdump.txt>
 
 endmenu
 
index 42be537431338b5261a829a5266cd6fc2852b3ed..edcf2a70694204c9685cb6ed019f8c93496749c6 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 
 #include "appldata.h"
index ebc2913f9ee0bd29f1a8594da675a279d38c8640..057ce0ca6377dc3b28b775c3c1ca1797a8cbbf2c 100644 (file)
@@ -10,6 +10,8 @@ struct ccw_driver;
  * @count: number of attached slave devices
  * @dev: embedded device structure
  * @cdev: variable number of slave devices, allocated as needed
+ * @ungroup_work: work to be done when a ccwgroup notifier has action
+ *     type %BUS_NOTIFY_UNBIND_DRIVER
  */
 struct ccwgroup_device {
        enum {
index 69cf5b5eddc95dcb83372e10f444df01825583c9..a4811aa0304d03264c4e63626d61619c62d16f0c 100644 (file)
@@ -29,7 +29,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
        int cmparg = (encoded_op << 20) >> 20;
        int oldval = 0, newval, ret;
 
-       update_primary_asce(current);
+       load_kernel_asce();
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
@@ -79,7 +79,7 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 {
        int ret;
 
-       update_primary_asce(current);
+       load_kernel_asce();
        asm volatile(
                "   sacf 256\n"
                "0: cs   %1,%4,0(%5)\n"
index bbf8141408cdadf2881011a683937c3636e17375..26e03ce27c50288374b1a9f79a4e757fdf312c46 100644 (file)
@@ -93,7 +93,9 @@ struct _lowcore {
        __u32   save_area_sync[8];              /* 0x0200 */
        __u32   save_area_async[8];             /* 0x0220 */
        __u32   save_area_restart[1];           /* 0x0240 */
-       __u8    pad_0x0244[0x0248-0x0244];      /* 0x0244 */
+
+       /* CPU flags. */
+       __u32   cpu_flags;                      /* 0x0244 */
 
        /* Return psws. */
        psw_t   return_psw;                     /* 0x0248 */
@@ -139,7 +141,7 @@ struct _lowcore {
        __u32   percpu_offset;                  /* 0x02f0 */
        __u32   machine_flags;                  /* 0x02f4 */
        __u32   ftrace_func;                    /* 0x02f8 */
-       __u8    pad_0x02fc[0x0300-0x02fc];      /* 0x02fc */
+       __u32   spinlock_lockval;               /* 0x02fc */
 
        /* Interrupt response block */
        __u8    irb[64];                        /* 0x0300 */
@@ -237,7 +239,9 @@ struct _lowcore {
        __u64   save_area_sync[8];              /* 0x0200 */
        __u64   save_area_async[8];             /* 0x0240 */
        __u64   save_area_restart[1];           /* 0x0280 */
-       __u8    pad_0x0288[0x0290-0x0288];      /* 0x0288 */
+
+       /* CPU flags. */
+       __u64   cpu_flags;                      /* 0x0288 */
 
        /* Return psws. */
        psw_t   return_psw;                     /* 0x0290 */
@@ -285,7 +289,8 @@ struct _lowcore {
        __u64   machine_flags;                  /* 0x0388 */
        __u64   ftrace_func;                    /* 0x0390 */
        __u64   gmap;                           /* 0x0398 */
-       __u8    pad_0x03a0[0x0400-0x03a0];      /* 0x03a0 */
+       __u32   spinlock_lockval;               /* 0x03a0 */
+       __u8    pad_0x03a0[0x0400-0x03a4];      /* 0x03a4 */
 
        /* Interrupt response block. */
        __u8    irb[64];                        /* 0x0400 */
index 71be346d0e3c8074d7be6542815610567ff66606..056d7eff2a1655b72bb140b80c092926c8d9f181 100644 (file)
@@ -30,33 +30,31 @@ static inline int init_new_context(struct task_struct *tsk,
 
 #define destroy_context(mm)             do { } while (0)
 
-static inline void update_user_asce(struct mm_struct *mm, int load_primary)
+static inline void set_user_asce(struct mm_struct *mm)
 {
        pgd_t *pgd = mm->pgd;
 
        S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
-       if (load_primary)
-               __ctl_load(S390_lowcore.user_asce, 1, 1);
        set_fs(current->thread.mm_segment);
+       set_cpu_flag(CIF_ASCE);
 }
 
-static inline void clear_user_asce(struct mm_struct *mm, int load_primary)
+static inline void clear_user_asce(void)
 {
        S390_lowcore.user_asce = S390_lowcore.kernel_asce;
 
-       if (load_primary)
-               __ctl_load(S390_lowcore.user_asce, 1, 1);
+       __ctl_load(S390_lowcore.user_asce, 1, 1);
        __ctl_load(S390_lowcore.user_asce, 7, 7);
 }
 
-static inline void update_primary_asce(struct task_struct *tsk)
+static inline void load_kernel_asce(void)
 {
        unsigned long asce;
 
        __ctl_store(asce, 1, 1);
        if (asce != S390_lowcore.kernel_asce)
                __ctl_load(S390_lowcore.kernel_asce, 1, 1);
-       set_tsk_thread_flag(tsk, TIF_ASCE);
+       set_cpu_flag(CIF_ASCE);
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
@@ -64,25 +62,17 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        int cpu = smp_processor_id();
 
-       update_primary_asce(tsk);
        if (prev == next)
                return;
        if (MACHINE_HAS_TLB_LC)
                cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
-       if (atomic_inc_return(&next->context.attach_count) >> 16) {
-               /* Delay update_user_asce until all TLB flushes are done. */
-               set_tsk_thread_flag(tsk, TIF_TLB_WAIT);
-               /* Clear old ASCE by loading the kernel ASCE. */
-               clear_user_asce(next, 0);
-       } else {
-               cpumask_set_cpu(cpu, mm_cpumask(next));
-               update_user_asce(next, 0);
-               if (next->context.flush_mm)
-                       /* Flush pending TLBs */
-                       __tlb_flush_mm(next);
-       }
+       /* Clear old ASCE by loading the kernel ASCE. */
+       __ctl_load(S390_lowcore.kernel_asce, 1, 1);
+       __ctl_load(S390_lowcore.kernel_asce, 7, 7);
+       /* Delay loading of the new ASCE to control registers CR1 & CR7 */
+       set_cpu_flag(CIF_ASCE);
+       atomic_inc(&next->context.attach_count);
        atomic_dec(&prev->context.attach_count);
-       WARN_ON(atomic_read(&prev->context.attach_count) < 0);
        if (MACHINE_HAS_TLB_LC)
                cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
 }
@@ -93,15 +83,14 @@ static inline void finish_arch_post_lock_switch(void)
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
 
-       if (!test_tsk_thread_flag(tsk, TIF_TLB_WAIT))
+       if (!mm)
                return;
        preempt_disable();
-       clear_tsk_thread_flag(tsk, TIF_TLB_WAIT);
        while (atomic_read(&mm->context.attach_count) >> 16)
                cpu_relax();
 
        cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-       update_user_asce(mm, 0);
+       set_user_asce(mm);
        if (mm->context.flush_mm)
                __tlb_flush_mm(mm);
        preempt_enable();
@@ -113,7 +102,9 @@ static inline void finish_arch_post_lock_switch(void)
 static inline void activate_mm(struct mm_struct *prev,
                                struct mm_struct *next)
 {
-        switch_mm(prev, next, current);
+       switch_mm(prev, next, current);
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
+       set_user_asce(next);
 }
 
 static inline void arch_dup_mmap(struct mm_struct *oldmm,
index 2583466f576b617181ed8b39f1db6c32106bd999..c030900320e0baf62a3e9eb0b879c300620ab4ae 100644 (file)
@@ -78,10 +78,16 @@ struct zpci_dev {
        enum zpci_state state;
        u32             fid;            /* function ID, used by sclp */
        u32             fh;             /* function handle, used by insn's */
+       u16             vfn;            /* virtual function number */
        u16             pchid;          /* physical channel ID */
        u8              pfgid;          /* function group ID */
+       u8              pft;            /* pci function type */
        u16             domain;
 
+       u8 pfip[CLP_PFIP_NR_SEGMENTS];  /* pci function internal path */
+       u32 uid;                        /* user defined id */
+       u8 util_str[CLP_UTIL_STR_LEN];  /* utility string */
+
        /* IRQ stuff */
        u64             msi_addr;       /* MSI address */
        struct airq_iv *aibv;           /* adapter interrupt bit vector */
@@ -120,6 +126,8 @@ static inline bool zdev_enabled(struct zpci_dev *zdev)
        return (zdev->fh & (1UL << 31)) ? true : false;
 }
 
+extern const struct attribute_group *zpci_attr_groups[];
+
 /* -----------------------------------------------------------------------------
   Prototypes
 ----------------------------------------------------------------------------- */
@@ -166,10 +174,6 @@ static inline void zpci_exit_slot(struct zpci_dev *zdev) {}
 struct zpci_dev *get_zdev(struct pci_dev *);
 struct zpci_dev *get_zdev_by_fid(u32);
 
-/* sysfs */
-int zpci_sysfs_add_device(struct device *);
-void zpci_sysfs_remove_device(struct device *);
-
 /* DMA */
 int zpci_dma_init(void);
 void zpci_dma_exit(void);
index d31d739f8689e2a81b0f41d8df0bfc4388aeadff..dd78f92f1cce5fc419e795e325800d1c78a155ac 100644 (file)
@@ -44,6 +44,7 @@ struct clp_fh_list_entry {
 #define CLP_SET_DISABLE_PCI_FN 1       /* Yes, 1 disables it */
 
 #define CLP_UTIL_STR_LEN       64
+#define CLP_PFIP_NR_SEGMENTS   4
 
 /* List PCI functions request */
 struct clp_req_list_pci {
@@ -85,7 +86,7 @@ struct clp_rsp_query_pci {
        struct clp_rsp_hdr hdr;
        u32 fmt                 :  4;   /* cmd request block format */
        u32                     : 28;
-       u64 reserved1;
+       u64                     : 64;
        u16 vfn;                        /* virtual fn number */
        u16                     :  7;
        u16 util_str_avail      :  1;   /* utility string available? */
@@ -94,10 +95,13 @@ struct clp_rsp_query_pci {
        u8 bar_size[PCI_BAR_COUNT];
        u16 pchid;
        u32 bar[PCI_BAR_COUNT];
-       u64 reserved2;
+       u8 pfip[CLP_PFIP_NR_SEGMENTS];  /* pci function internal path */
+       u32                     : 24;
+       u8 pft;                         /* pci function type */
        u64 sdma;                       /* start dma as */
        u64 edma;                       /* end dma as */
-       u64 reserved3[6];
+       u32 reserved[11];
+       u32 uid;                        /* user defined id */
        u8 util_str[CLP_UTIL_STR_LEN];  /* utility string */
 } __packed;
 
index dc5fc4f90e52b86a3152d434bbd7425d3f644337..6f02d452bbee3741ac164ed3f1f16fe0970d2fe8 100644 (file)
 #ifndef __ASM_S390_PROCESSOR_H
 #define __ASM_S390_PROCESSOR_H
 
+#define CIF_MCCK_PENDING       0       /* machine check handling is pending */
+#define CIF_ASCE               1       /* user asce needs fixup / uaccess */
+
+#define _CIF_MCCK_PENDING      (1<<CIF_MCCK_PENDING)
+#define _CIF_ASCE              (1<<CIF_ASCE)
+
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
 #include <asm/setup.h>
 #include <asm/runtime_instr.h>
 
+static inline void set_cpu_flag(int flag)
+{
+       S390_lowcore.cpu_flags |= (1U << flag);
+}
+
+static inline void clear_cpu_flag(int flag)
+{
+       S390_lowcore.cpu_flags &= ~(1U << flag);
+}
+
+static inline int test_cpu_flag(int flag)
+{
+       return !!(S390_lowcore.cpu_flags & (1U << flag));
+}
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
index f4783c0b7b43cfd4e58c2c4bfed19013f465fb1b..1b5300cd6d22ce86e0c88e589e37e39a8ff19737 100644 (file)
@@ -8,6 +8,12 @@
 
 #include <uapi/asm/ptrace.h>
 
+#define PIF_SYSCALL            0       /* inside a system call */
+#define PIF_PER_TRAP           1       /* deliver sigtrap on return to user */
+
+#define _PIF_SYSCALL           (1<<PIF_SYSCALL)
+#define _PIF_PER_TRAP          (1<<PIF_PER_TRAP)
+
 #ifndef __ASSEMBLY__
 
 #define PSW_KERNEL_BITS        (PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_HOME | \
@@ -29,6 +35,7 @@ struct pt_regs
        unsigned int int_code;
        unsigned int int_parm;
        unsigned long int_parm_long;
+       unsigned long flags;
 };
 
 /*
@@ -79,6 +86,21 @@ struct per_struct_kernel {
 #define PER_CONTROL_SUSPENSION         0x00400000UL
 #define PER_CONTROL_ALTERATION         0x00200000UL
 
+static inline void set_pt_regs_flag(struct pt_regs *regs, int flag)
+{
+       regs->flags |= (1U << flag);
+}
+
+static inline void clear_pt_regs_flag(struct pt_regs *regs, int flag)
+{
+       regs->flags &= ~(1U << flag);
+}
+
+static inline int test_pt_regs_flag(struct pt_regs *regs, int flag)
+{
+       return !!(regs->flags & (1U << flag));
+}
+
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
index b31b22dba94859087a019975ace0f505d69fdf5e..089a49814c505b506ed1689230a470ebfc575d03 100644 (file)
@@ -9,7 +9,6 @@
 
 
 #define PARMAREA               0x10400
-#define MEMORY_CHUNKS          256
 
 #ifndef __ASSEMBLY__
 
 #endif /* CONFIG_64BIT */
 #define COMMAND_LINE      ((char *)            (0x10480))
 
-#define CHUNK_READ_WRITE 0
-#define CHUNK_READ_ONLY  1
-
-struct mem_chunk {
-       unsigned long addr;
-       unsigned long size;
-       int type;
-};
-
-extern struct mem_chunk memory_chunk[];
 extern int memory_end_set;
 extern unsigned long memory_end;
+extern unsigned long max_physmem_end;
 
-void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize);
-void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
-                    unsigned long size);
+extern void detect_memory_memblock(void);
 
 /*
  * Machine features detected in head.S
index 21703f85b48d8d0c1c1c229791a2cfe1dc9294d8..4f1307962a95a307d6dff37acf897abba8f7595d 100644 (file)
@@ -30,7 +30,6 @@ extern int smp_store_status(int cpu);
 extern int smp_vcpu_scheduled(int cpu);
 extern void smp_yield_cpu(int cpu);
 extern void smp_yield(void);
-extern void smp_stop_cpu(void);
 extern void smp_cpu_set_polarization(int cpu, int val);
 extern int smp_cpu_get_polarization(int cpu);
 extern void smp_fill_possible_mask(void);
@@ -54,6 +53,8 @@ static inline void smp_yield_cpu(int cpu) { }
 static inline void smp_yield(void) { }
 static inline void smp_fill_possible_mask(void) { }
 
+#endif /* CONFIG_SMP */
+
 static inline void smp_stop_cpu(void)
 {
        u16 pcpu = stap();
@@ -64,8 +65,6 @@ static inline void smp_stop_cpu(void)
        }
 }
 
-#endif /* CONFIG_SMP */
-
 #ifdef CONFIG_HOTPLUG_CPU
 extern int smp_rescan_cpus(void);
 extern void __noreturn cpu_die(void);
index 83e5d216105e86a2df2ab1367bcfc3fd1590542a..84faa13aa7aeb6f7a39297ecaab277008b3e0231 100644 (file)
@@ -1,7 +1,8 @@
 /*
  *  S390 version
- *    Copyright IBM Corp. 1999
+ *    Copyright IBM Corp. 1999, 2014
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *              Philipp Hachtmann (phacht@linux.vnet.ibm.com)
  *
  *  Derived from "include/asm-i386/spinlock.h"
  */
 
 #include <linux/smp.h>
 
+#define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval)
+
 extern int spin_retry;
 
 static inline int
-_raw_compare_and_swap(volatile unsigned int *lock,
-                     unsigned int old, unsigned int new)
+_raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new)
 {
+       unsigned int old_expected = old;
+
        asm volatile(
                "       cs      %0,%3,%1"
                : "=d" (old), "=Q" (*lock)
                : "0" (old), "d" (new), "Q" (*lock)
                : "cc", "memory" );
-       return old;
+       return old == old_expected;
 }
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
- * We make no fairness assumptions. They have a cost.
- *
  * (the type definitions are in asm/spinlock_types.h)
  */
 
-#define arch_spin_is_locked(x) ((x)->owner_cpu != 0)
-#define arch_spin_unlock_wait(lock) \
-       do { while (arch_spin_is_locked(lock)) \
-                arch_spin_relax(lock); } while (0)
+void arch_spin_lock_wait(arch_spinlock_t *);
+int arch_spin_trylock_retry(arch_spinlock_t *);
+void arch_spin_relax(arch_spinlock_t *);
+
+#ifdef CONFIG_S390_TICKET_SPINLOCK
+
+void arch_spin_unlock_slow(arch_spinlock_t *lp);
+
+static inline u32 arch_spin_lockval(u32 cpu)
+{
+       arch_spinlock_t new;
+
+       new.tickets.owner = ~cpu;
+       new.tickets.head = 0;
+       new.tickets.tail = 0;
+       return new.lock;
+}
+
+static inline void arch_spin_lock_wait_flags(arch_spinlock_t *lp,
+                                            unsigned long flags)
+{
+       arch_spin_lock_wait(lp);
+}
+
+#else /* CONFIG_S390_TICKET_SPINLOCK */
+
+void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags);
+
+static inline u32 arch_spin_lockval(int cpu)
+{
+       return ~cpu;
+}
+
+static inline void arch_spin_unlock_slow(arch_spinlock_t *lp)
+{
+}
 
-extern void arch_spin_lock_wait(arch_spinlock_t *);
-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);
+#endif /* CONFIG_S390_TICKET_SPINLOCK */
 
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 {
-       return lock.owner_cpu == 0;
+       return lock.lock == 0;
 }
 
-static inline void arch_spin_lock(arch_spinlock_t *lp)
+static inline int arch_spin_is_locked(arch_spinlock_t *lp)
 {
-       int old;
+       return ACCESS_ONCE(lp->lock) != 0;
+}
 
-       old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-       if (likely(old == 0))
-               return;
-       arch_spin_lock_wait(lp);
+static inline int arch_spin_trylock_once(arch_spinlock_t *lp)
+{
+       return _raw_compare_and_swap(&lp->lock, 0, SPINLOCK_LOCKVAL);
 }
 
-static inline void arch_spin_lock_flags(arch_spinlock_t *lp,
-                                        unsigned long flags)
+static inline int arch_spin_tryrelease_once(arch_spinlock_t *lp)
 {
-       int old;
+       return _raw_compare_and_swap(&lp->lock, SPINLOCK_LOCKVAL, 0);
+}
 
-       old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-       if (likely(old == 0))
-               return;
-       arch_spin_lock_wait_flags(lp, flags);
+static inline void arch_spin_lock(arch_spinlock_t *lp)
+{
+       if (unlikely(!arch_spin_trylock_once(lp)))
+               arch_spin_lock_wait(lp);
 }
 
-static inline int arch_spin_trylock(arch_spinlock_t *lp)
+static inline void arch_spin_lock_flags(arch_spinlock_t *lp,
+                                       unsigned long flags)
 {
-       int old;
+       if (unlikely(!arch_spin_trylock_once(lp)))
+               arch_spin_lock_wait_flags(lp, flags);
+}
 
-       old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-       if (likely(old == 0))
-               return 1;
-       return arch_spin_trylock_retry(lp);
+static inline int arch_spin_trylock(arch_spinlock_t *lp)
+{
+       if (unlikely(!arch_spin_trylock_once(lp)))
+               return arch_spin_trylock_retry(lp);
+       return 1;
 }
 
 static inline void arch_spin_unlock(arch_spinlock_t *lp)
 {
-       _raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
+       if (unlikely(!arch_spin_tryrelease_once(lp)))
+               arch_spin_unlock_slow(lp);
 }
-               
+
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       while (arch_spin_is_locked(lock))
+               arch_spin_relax(lock);
+}
+
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
@@ -119,7 +161,7 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        unsigned int old;
        old = rw->lock & 0x7fffffffU;
-       if (_raw_compare_and_swap(&rw->lock, old, old + 1) != old)
+       if (!_raw_compare_and_swap(&rw->lock, old, old + 1))
                _raw_read_lock_wait(rw);
 }
 
@@ -127,30 +169,28 @@ static inline void arch_read_lock_flags(arch_rwlock_t *rw, unsigned long flags)
 {
        unsigned int old;
        old = rw->lock & 0x7fffffffU;
-       if (_raw_compare_and_swap(&rw->lock, old, old + 1) != old)
+       if (!_raw_compare_and_swap(&rw->lock, old, old + 1))
                _raw_read_lock_wait_flags(rw, flags);
 }
 
 static inline void arch_read_unlock(arch_rwlock_t *rw)
 {
-       unsigned int old, cmp;
+       unsigned int old;
 
-       old = rw->lock;
        do {
-               cmp = old;
-               old = _raw_compare_and_swap(&rw->lock, old, old - 1);
-       } while (cmp != old);
+               old = ACCESS_ONCE(rw->lock);
+       } while (!_raw_compare_and_swap(&rw->lock, old, old - 1));
 }
 
 static inline void arch_write_lock(arch_rwlock_t *rw)
 {
-       if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0))
+       if (unlikely(!_raw_compare_and_swap(&rw->lock, 0, 0x80000000)))
                _raw_write_lock_wait(rw);
 }
 
 static inline void arch_write_lock_flags(arch_rwlock_t *rw, unsigned long flags)
 {
-       if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0))
+       if (unlikely(!_raw_compare_and_swap(&rw->lock, 0, 0x80000000)))
                _raw_write_lock_wait_flags(rw, flags);
 }
 
@@ -163,14 +203,14 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
        unsigned int old;
        old = rw->lock & 0x7fffffffU;
-       if (likely(_raw_compare_and_swap(&rw->lock, old, old + 1) == old))
+       if (likely(_raw_compare_and_swap(&rw->lock, old, old + 1)))
                return 1;
        return _raw_read_trylock_retry(rw);
 }
 
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
-       if (likely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0))
+       if (likely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000)))
                return 1;
        return _raw_write_trylock_retry(rw);
 }
index 9c76656a0af035bf04d55680a03c589ef0e1b0f1..472e12254a5150b1025d764e5bb6f2d7a9be7c67 100644 (file)
@@ -5,14 +5,31 @@
 # error "please don't include this file directly"
 #endif
 
+#ifdef CONFIG_S390_TICKET_SPINLOCK
+
+typedef struct arch_spinlock {
+       union {
+               unsigned int lock;
+               struct __raw_tickets {
+                       u16 owner;
+                       u8 tail;
+                       u8 head;
+               } tickets;
+       };
+} arch_spinlock_t;
+
+#else /* CONFIG_S390_TICKET_SPINLOCK */
+
 typedef struct {
-       volatile unsigned int owner_cpu;
+       unsigned int lock;
 } __attribute__ ((aligned (4))) arch_spinlock_t;
 
-#define __ARCH_SPIN_LOCK_UNLOCKED      { 0 }
+#endif /* CONFIG_S390_TICKET_SPINLOCK */
+
+#define __ARCH_SPIN_LOCK_UNLOCKED { .lock = 0, }
 
 typedef struct {
-       volatile unsigned int lock;
+       unsigned int lock;
 } arch_rwlock_t;
 
 #define __ARCH_RW_LOCK_UNLOCKED                { 0 }
index e759181357fc5823c490696c23d047878c4ec753..29c81f82705e139dc53a9af3f72b0db3d9e14695 100644 (file)
@@ -132,7 +132,6 @@ static inline void restore_access_regs(unsigned int *acrs)
                update_cr_regs(next);                                   \
        }                                                               \
        prev = __switch_to(prev,next);                                  \
-       update_primary_asce(current);                                   \
 } while (0)
 
 #define finish_arch_switch(prev) do {                                       \
index 777687055e7be576eb793d3a09aae71b97595ed9..abad78d5b10c7ec24cea4133c83ab119897ce6bc 100644 (file)
@@ -28,7 +28,7 @@ extern const unsigned int sys_call_table_emu[];
 static inline long syscall_get_nr(struct task_struct *task,
                                  struct pt_regs *regs)
 {
-       return test_tsk_thread_flag(task, TIF_SYSCALL) ?
+       return test_pt_regs_flag(regs, PIF_SYSCALL) ?
                (regs->int_code & 0xffff) : -1;
 }
 
index 50630e6a35de394688ac59207a5c523370493388..b833e9c0bfbf2feb6e4f9dc2559e22385115e9b2 100644 (file)
@@ -77,32 +77,22 @@ static inline struct thread_info *current_thread_info(void)
 /*
  * thread information flags bit numbers
  */
-#define TIF_SYSCALL            0       /* inside a system call */
-#define TIF_NOTIFY_RESUME      1       /* callback before returning to user */
-#define TIF_SIGPENDING         2       /* signal pending */
-#define TIF_NEED_RESCHED       3       /* rescheduling necessary */
-#define TIF_TLB_WAIT           4       /* wait for TLB flush completion */
-#define TIF_ASCE               5       /* primary asce needs fixup / uaccess */
-#define TIF_PER_TRAP           6       /* deliver sigtrap on return to user */
-#define TIF_MCCK_PENDING       7       /* machine check handling is pending */
-#define TIF_SYSCALL_TRACE      8       /* syscall trace active */
-#define TIF_SYSCALL_AUDIT      9       /* syscall auditing active */
-#define TIF_SECCOMP            10      /* secure computing */
-#define TIF_SYSCALL_TRACEPOINT 11      /* syscall tracepoint instrumentation */
-#define TIF_31BIT              17      /* 32bit process */
-#define TIF_MEMDIE             18      /* is terminating due to OOM killer */
-#define TIF_RESTORE_SIGMASK    19      /* restore signal mask in do_signal() */
-#define TIF_SINGLE_STEP                20      /* This task is single stepped */
-#define TIF_BLOCK_STEP         21      /* This task is block stepped */
+#define TIF_NOTIFY_RESUME      0       /* callback before returning to user */
+#define TIF_SIGPENDING         1       /* signal pending */
+#define TIF_NEED_RESCHED       2       /* rescheduling necessary */
+#define TIF_SYSCALL_TRACE      3       /* syscall trace active */
+#define TIF_SYSCALL_AUDIT      4       /* syscall auditing active */
+#define TIF_SECCOMP            5       /* secure computing */
+#define TIF_SYSCALL_TRACEPOINT 6       /* syscall tracepoint instrumentation */
+#define TIF_31BIT              16      /* 32bit process */
+#define TIF_MEMDIE             17      /* is terminating due to OOM killer */
+#define TIF_RESTORE_SIGMASK    18      /* restore signal mask in do_signal() */
+#define TIF_SINGLE_STEP                19      /* This task is single stepped */
+#define TIF_BLOCK_STEP         20      /* This task is block stepped */
 
-#define _TIF_SYSCALL           (1<<TIF_SYSCALL)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
-#define _TIF_TLB_WAIT          (1<<TIF_TLB_WAIT)
-#define _TIF_ASCE              (1<<TIF_ASCE)
-#define _TIF_PER_TRAP          (1<<TIF_PER_TRAP)
-#define _TIF_MCCK_PENDING      (1<<TIF_MCCK_PENDING)
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
index 1be64a1506d0164593bafc6fdc847570813b1934..cd4c68e0398dd9bc04b0ed76e80afe3c55a6fd81 100644 (file)
@@ -132,6 +132,34 @@ unsigned long __must_check __copy_to_user(void __user *to, const void *from,
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+
+#define __put_get_user_asm(to, from, size, spec)               \
+({                                                             \
+       register unsigned long __reg0 asm("0") = spec;          \
+       int __rc;                                               \
+                                                               \
+       asm volatile(                                           \
+               "0:     mvcos   %1,%3,%2\n"                     \
+               "1:     xr      %0,%0\n"                        \
+               "2:\n"                                          \
+               ".pushsection .fixup, \"ax\"\n"                 \
+               "3:     lhi     %0,%5\n"                        \
+               "       jg      2b\n"                           \
+               ".popsection\n"                                 \
+               EX_TABLE(0b,3b) EX_TABLE(1b,3b)                 \
+               : "=d" (__rc), "=Q" (*(to))                     \
+               : "d" (size), "Q" (*(from)),                    \
+                 "d" (__reg0), "K" (-EFAULT)                   \
+               : "cc");                                        \
+       __rc;                                                   \
+})
+
+#define __put_user_fn(x, ptr, size) __put_get_user_asm(ptr, x, size, 0x810000UL)
+#define __get_user_fn(x, ptr, size) __put_get_user_asm(x, ptr, size, 0x81UL)
+
+#else /* CONFIG_HAVE_MARCH_Z10_FEATURES */
+
 static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
 {
        size = __copy_to_user(ptr, x, size);
@@ -144,6 +172,8 @@ static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long s
        return size ? -EFAULT : 0;
 }
 
+#endif /* CONFIG_HAVE_MARCH_Z10_FEATURES */
+
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
index cc10cdd4d6a24ccbb9d02d12154da7eae25cb076..76c4e2f70cab6ce3ccb72c483ad671e60e940106 100644 (file)
@@ -50,6 +50,7 @@ int main(void)
        DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
        DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm));
        DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
+       DEFINE(__PT_FLAGS, offsetof(struct pt_regs, flags));
        DEFINE(__PT_SIZE, sizeof(struct pt_regs));
        BLANK();
        DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
@@ -115,6 +116,7 @@ int main(void)
        DEFINE(__LC_SAVE_AREA_SYNC, offsetof(struct _lowcore, save_area_sync));
        DEFINE(__LC_SAVE_AREA_ASYNC, offsetof(struct _lowcore, save_area_async));
        DEFINE(__LC_SAVE_AREA_RESTART, offsetof(struct _lowcore, save_area_restart));
+       DEFINE(__LC_CPU_FLAGS, offsetof(struct _lowcore, cpu_flags));
        DEFINE(__LC_RETURN_PSW, offsetof(struct _lowcore, return_psw));
        DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw));
        DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer));
index 7df5ed9f44d7c2d471e99bd3f21195d958638c3d..f204d6920368366feeda238c782cf0fead4a29f3 100644 (file)
@@ -213,7 +213,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
               sizeof(current->thread.fp_regs));
 
        restore_fp_regs(current->thread.fp_regs.fprs);
-       clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */
+       clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
        return 0;
 }
 
index d7658c4b2ed5817c75cd6a90c91b3a1b93738809..a3b9150e6802973b3b82a6db379c7959dfb48e9d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/bootmem.h>
 #include <linux/elf.h>
+#include <linux/memblock.h>
 #include <asm/os_info.h>
 #include <asm/elf.h>
 #include <asm/ipl.h>
 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
 #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
 
+static struct memblock_region oldmem_region;
+
+static struct memblock_type oldmem_type = {
+       .cnt = 1,
+       .max = 1,
+       .total_size = 0,
+       .regions = &oldmem_region,
+};
+
+#define for_each_dump_mem_range(i, nid, p_start, p_end, p_nid)         \
+       for (i = 0, __next_mem_range(&i, nid, &memblock.physmem,        \
+                                    &oldmem_type, p_start,             \
+                                    p_end, p_nid);                     \
+            i != (u64)ULLONG_MAX;                                      \
+            __next_mem_range(&i, nid, &memblock.physmem,               \
+                             &oldmem_type,                             \
+                             p_start, p_end, p_nid))
+
 struct dump_save_areas dump_save_areas;
 
 /*
@@ -263,19 +282,6 @@ static void *kzalloc_panic(int len)
        return rc;
 }
 
-/*
- * Get memory layout and create hole for oldmem
- */
-static struct mem_chunk *get_memory_layout(void)
-{
-       struct mem_chunk *chunk_array;
-
-       chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk));
-       detect_memory_layout(chunk_array, 0);
-       create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE);
-       return chunk_array;
-}
-
 /*
  * Initialize ELF note
  */
@@ -490,52 +496,33 @@ static int get_cpu_cnt(void)
  */
 static int get_mem_chunk_cnt(void)
 {
-       struct mem_chunk *chunk_array, *mem_chunk;
-       int i, cnt = 0;
+       int cnt = 0;
+       u64 idx;
 
-       chunk_array = get_memory_layout();
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               mem_chunk = &chunk_array[i];
-               if (chunk_array[i].type != CHUNK_READ_WRITE &&
-                   chunk_array[i].type != CHUNK_READ_ONLY)
-                       continue;
-               if (mem_chunk->size == 0)
-                       continue;
+       for_each_dump_mem_range(idx, NUMA_NO_NODE, NULL, NULL, NULL)
                cnt++;
-       }
-       kfree(chunk_array);
        return cnt;
 }
 
 /*
  * Initialize ELF loads (new kernel)
  */
-static int loads_init(Elf64_Phdr *phdr, u64 loads_offset)
+static void loads_init(Elf64_Phdr *phdr, u64 loads_offset)
 {
-       struct mem_chunk *chunk_array, *mem_chunk;
-       int i;
+       phys_addr_t start, end;
+       u64 idx;
 
-       chunk_array = get_memory_layout();
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               mem_chunk = &chunk_array[i];
-               if (mem_chunk->size == 0)
-                       continue;
-               if (chunk_array[i].type != CHUNK_READ_WRITE &&
-                   chunk_array[i].type != CHUNK_READ_ONLY)
-                       continue;
-               else
-                       phdr->p_filesz = mem_chunk->size;
+       for_each_dump_mem_range(idx, NUMA_NO_NODE, &start, &end, NULL) {
+               phdr->p_filesz = end - start;
                phdr->p_type = PT_LOAD;
-               phdr->p_offset = mem_chunk->addr;
-               phdr->p_vaddr = mem_chunk->addr;
-               phdr->p_paddr = mem_chunk->addr;
-               phdr->p_memsz = mem_chunk->size;
+               phdr->p_offset = start;
+               phdr->p_vaddr = start;
+               phdr->p_paddr = start;
+               phdr->p_memsz = end - start;
                phdr->p_flags = PF_R | PF_W | PF_X;
                phdr->p_align = PAGE_SIZE;
                phdr++;
        }
-       kfree(chunk_array);
-       return i;
 }
 
 /*
@@ -584,6 +571,14 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
        /* If we cannot get HSA size for zfcpdump return error */
        if (ipl_info.type == IPL_TYPE_FCP_DUMP && !sclp_get_hsa_size())
                return -ENODEV;
+
+       /* For kdump, exclude previous crashkernel memory */
+       if (OLDMEM_BASE) {
+               oldmem_region.base = OLDMEM_BASE;
+               oldmem_region.size = OLDMEM_SIZE;
+               oldmem_type.total_size = OLDMEM_SIZE;
+       }
+
        mem_chunk_cnt = get_mem_chunk_cnt();
 
        alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
index a734f3585cebdd8eda8db980fb0343bae16a1b1b..0dff972a169c16dd533c8256de9771e96f459e01 100644 (file)
@@ -258,13 +258,19 @@ static __init void setup_topology(void)
 static void early_pgm_check_handler(void)
 {
        const struct exception_table_entry *fixup;
+       unsigned long cr0, cr0_new;
        unsigned long addr;
 
        addr = S390_lowcore.program_old_psw.addr;
        fixup = search_exception_tables(addr & PSW_ADDR_INSN);
        if (!fixup)
                disabled_wait(0);
+       /* Disable low address protection before storing into lowcore. */
+       __ctl_store(cr0, 0, 0);
+       cr0_new = cr0 & ~(1UL << 28);
+       __ctl_load(cr0_new, 0, 0);
        S390_lowcore.program_old_psw.addr = extable_fixup(fixup)|PSW_ADDR_AMODE;
+       __ctl_load(cr0, 0, 0);
 }
 
 static noinline __init void setup_lowcore_early(void)
index 1662038516c0db29d59a4a87dce89f374428cd51..18e5af848f9a67b7aa7374fe46da9a62d4f6ad95 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/linkage.h>
+#include <asm/processor.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
 #include <asm/ptrace.h>
@@ -37,18 +38,16 @@ __PT_R13     =      __PT_GPRS + 524
 __PT_R14     = __PT_GPRS + 56
 __PT_R15     = __PT_GPRS + 60
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING | _TIF_PER_TRAP | _TIF_ASCE)
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING | _TIF_ASCE)
-_TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
-                _TIF_SYSCALL_TRACEPOINT)
-_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
-
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
 STACK_INIT  = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
 
+_TIF_WORK      = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
+_TIF_TRACE     = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
+                  _TIF_SYSCALL_TRACEPOINT)
+_CIF_WORK      = (_CIF_MCCK_PENDING | _CIF_ASCE)
+_PIF_WORK      = (_PIF_PER_TRAP)
+
 #define BASED(name) name-system_call(%r13)
 
        .macro  TRACE_IRQS_ON
@@ -160,13 +159,7 @@ ENTRY(__switch_to)
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        mvc     __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
        l       %r15,__THREAD_ksp(%r3)          # load kernel stack of next
-       lhi     %r6,_TIF_TRANSFER               # transfer TIF bits
-       n       %r6,__TI_flags(%r4)             # isolate TIF bits
-       jz      0f
-       o       %r6,__TI_flags(%r5)             # set TIF bits of next
-       st      %r6,__TI_flags(%r5)
-       ni      __TI_flags+3(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
-0:     lm      %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
+       lm      %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        br      %r14
 
 __critical_start:
@@ -181,6 +174,7 @@ sysc_stm:
        stm     %r8,%r15,__LC_SAVE_AREA_SYNC
        l       %r12,__LC_THREAD_INFO
        l       %r13,__LC_SVC_NEW_PSW+4
+       lhi     %r14,_PIF_SYSCALL
 sysc_per:
        l       %r15,__LC_KERNEL_STACK
        la      %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
@@ -190,8 +184,8 @@ sysc_vtime:
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_PSW(8,%r11),__LC_SVC_OLD_PSW
        mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
+       st      %r14,__PT_FLAGS(%r11)
 sysc_do_svc:
-       oi      __TI_flags+3(%r12),_TIF_SYSCALL
        l       %r10,__TI_sysc_table(%r12)      # 31 bit system call table
        lh      %r8,__PT_INT_CODE+2(%r11)
        sla     %r8,2                           # shift and test for svc0
@@ -207,7 +201,7 @@ sysc_nr_ok:
        st      %r2,__PT_ORIG_GPR2(%r11)
        st      %r7,STACK_FRAME_OVERHEAD(%r15)
        l       %r9,0(%r8,%r10)                 # get system call addr.
-       tm      __TI_flags+2(%r12),_TIF_TRACE >> 8
+       tm      __TI_flags+3(%r12),_TIF_TRACE
        jnz     sysc_tracesys
        basr    %r14,%r9                        # call sys_xxxx
        st      %r2,__PT_R2(%r11)               # store return value
@@ -217,9 +211,12 @@ sysc_return:
 sysc_tif:
        tm      __PT_PSW+1(%r11),0x01           # returning to user ?
        jno     sysc_restore
-       tm      __TI_flags+3(%r12),_TIF_WORK_SVC
-       jnz     sysc_work                       # check for work
-       ni      __TI_flags+3(%r12),255-_TIF_SYSCALL
+       tm      __PT_FLAGS+3(%r11),_PIF_WORK
+       jnz     sysc_work
+       tm      __TI_flags+3(%r12),_TIF_WORK
+       jnz     sysc_work                       # check for thread work
+       tm      __LC_CPU_FLAGS+3,_CIF_WORK
+       jnz     sysc_work
 sysc_restore:
        mvc     __LC_RETURN_PSW(8),__PT_PSW(%r11)
        stpt    __LC_EXIT_TIMER
@@ -231,17 +228,17 @@ sysc_done:
 # One of the work bits is on. Find out which one.
 #
 sysc_work:
-       tm      __TI_flags+3(%r12),_TIF_MCCK_PENDING
+       tm      __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING
        jo      sysc_mcck_pending
        tm      __TI_flags+3(%r12),_TIF_NEED_RESCHED
        jo      sysc_reschedule
-       tm      __TI_flags+3(%r12),_TIF_PER_TRAP
+       tm      __PT_FLAGS+3(%r11),_PIF_PER_TRAP
        jo      sysc_singlestep
        tm      __TI_flags+3(%r12),_TIF_SIGPENDING
        jo      sysc_sigpending
        tm      __TI_flags+3(%r12),_TIF_NOTIFY_RESUME
        jo      sysc_notify_resume
-       tm      __TI_flags+3(%r12),_TIF_ASCE
+       tm      __LC_CPU_FLAGS+3,_CIF_ASCE
        jo      sysc_uaccess
        j       sysc_return             # beware of critical section cleanup
 
@@ -254,7 +251,7 @@ sysc_reschedule:
        br      %r1                     # call schedule
 
 #
-# _TIF_MCCK_PENDING is set, call handler
+# _CIF_MCCK_PENDING is set, call handler
 #
 sysc_mcck_pending:
        l       %r1,BASED(.Lhandle_mcck)
@@ -262,10 +259,10 @@ sysc_mcck_pending:
        br      %r1                     # TIF bit will be cleared by handler
 
 #
-# _TIF_ASCE is set, load user space asce
+# _CIF_ASCE is set, load user space asce
 #
 sysc_uaccess:
-       ni      __TI_flags+3(%r12),255-_TIF_ASCE
+       ni      __LC_CPU_FLAGS+3,255-_CIF_ASCE
        lctl    %c1,%c1,__LC_USER_ASCE  # load primary asce
        j       sysc_return
 
@@ -276,7 +273,7 @@ sysc_sigpending:
        lr      %r2,%r11                # pass pointer to pt_regs
        l       %r1,BASED(.Ldo_signal)
        basr    %r14,%r1                # call do_signal
-       tm      __TI_flags+3(%r12),_TIF_SYSCALL
+       tm      __PT_FLAGS+3(%r11),_PIF_SYSCALL
        jno     sysc_return
        lm      %r2,%r7,__PT_R2(%r11)   # load svc arguments
        l       %r10,__TI_sysc_table(%r12)      # 31 bit system call table
@@ -297,10 +294,10 @@ sysc_notify_resume:
        br      %r1                     # call do_notify_resume
 
 #
-# _TIF_PER_TRAP is set, call do_per_trap
+# _PIF_PER_TRAP is set, call do_per_trap
 #
 sysc_singlestep:
-       ni      __TI_flags+3(%r12),255-_TIF_PER_TRAP
+       ni      __PT_FLAGS+3(%r11),255-_PIF_PER_TRAP
        lr      %r2,%r11                # pass pointer to pt_regs
        l       %r1,BASED(.Ldo_per_trap)
        la      %r14,BASED(sysc_return)
@@ -330,7 +327,7 @@ sysc_tracego:
        basr    %r14,%r9                # call sys_xxx
        st      %r2,__PT_R2(%r11)       # store return value
 sysc_tracenogo:
-       tm      __TI_flags+2(%r12),_TIF_TRACE >> 8
+       tm      __TI_flags+3(%r12),_TIF_TRACE
        jz      sysc_return
        l       %r1,BASED(.Ltrace_exit)
        lr      %r2,%r11                # pass pointer to pt_regs
@@ -384,12 +381,13 @@ ENTRY(pgm_check_handler)
        stm     %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(4,%r11),__LC_PGM_ILC
        mvc     __PT_INT_PARM_LONG(4,%r11),__LC_TRANS_EXC_CODE
+       xc      __PT_FLAGS(4,%r11),__PT_FLAGS(%r11)
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
        jz      0f
        l       %r1,__TI_task(%r12)
        tmh     %r8,0x0001              # kernel per event ?
        jz      pgm_kprobe
-       oi      __TI_flags+3(%r12),_TIF_PER_TRAP
+       oi      __PT_FLAGS+3(%r11),_PIF_PER_TRAP
        mvc     __THREAD_per_address(4,%r1),__LC_PER_ADDRESS
        mvc     __THREAD_per_cause(2,%r1),__LC_PER_CAUSE
        mvc     __THREAD_per_paid(1,%r1),__LC_PER_PAID
@@ -420,9 +418,9 @@ pgm_kprobe:
 # single stepped system call
 #
 pgm_svcper:
-       oi      __TI_flags+3(%r12),_TIF_PER_TRAP
        mvc     __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW
        mvc     __LC_RETURN_PSW+4(4),BASED(.Lsysc_per)
+       lhi     %r14,_PIF_SYSCALL | _PIF_PER_TRAP
        lpsw    __LC_RETURN_PSW         # branch to sysc_per and enable irqs
 
 /*
@@ -445,6 +443,7 @@ io_skip:
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
        stm     %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+       xc      __PT_FLAGS(4,%r11),__PT_FLAGS(%r11)
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
 io_loop:
@@ -466,8 +465,10 @@ io_return:
        LOCKDEP_SYS_EXIT
        TRACE_IRQS_ON
 io_tif:
-       tm      __TI_flags+3(%r12),_TIF_WORK_INT
+       tm      __TI_flags+3(%r12),_TIF_WORK
        jnz     io_work                 # there is work to do (signals etc.)
+       tm      __LC_CPU_FLAGS+3,_CIF_WORK
+       jnz     io_work
 io_restore:
        mvc     __LC_RETURN_PSW(8),__PT_PSW(%r11)
        stpt    __LC_EXIT_TIMER
@@ -477,7 +478,7 @@ io_done:
 
 #
 # There is work todo, find out in which context we have been interrupted:
-# 1) if we return to user space we can do all _TIF_WORK_INT work
+# 1) if we return to user space we can do all _TIF_WORK work
 # 2) if we return to kernel code and preemptive scheduling is enabled check
 #    the preemption counter and if it is zero call preempt_schedule_irq
 # Before any work can be done, a switch to the kernel stack is required.
@@ -520,11 +521,9 @@ io_work_user:
 
 #
 # One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED
-#              and _TIF_MCCK_PENDING
 #
 io_work_tif:
-       tm      __TI_flags+3(%r12),_TIF_MCCK_PENDING
+       tm      __LC_CPU_FLAGS+3(%r12),_CIF_MCCK_PENDING
        jo      io_mcck_pending
        tm      __TI_flags+3(%r12),_TIF_NEED_RESCHED
        jo      io_reschedule
@@ -532,12 +531,12 @@ io_work_tif:
        jo      io_sigpending
        tm      __TI_flags+3(%r12),_TIF_NOTIFY_RESUME
        jo      io_notify_resume
-       tm      __TI_flags+3(%r12),_TIF_ASCE
+       tm      __LC_CPU_FLAGS+3,_CIF_ASCE
        jo      io_uaccess
        j       io_return               # beware of critical section cleanup
 
 #
-# _TIF_MCCK_PENDING is set, call handler
+# _CIF_MCCK_PENDING is set, call handler
 #
 io_mcck_pending:
        # TRACE_IRQS_ON already done at io_return
@@ -547,10 +546,10 @@ io_mcck_pending:
        j       io_return
 
 #
-# _TIF_ASCE is set, load user space asce
+# _CIF_ASCE is set, load user space asce
 #
 io_uaccess:
-       ni      __TI_flags+3(%r12),255-_TIF_ASCE
+       ni      __LC_CPU_FLAGS+3,255-_CIF_ASCE
        lctl    %c1,%c1,__LC_USER_ASCE  # load primary asce
        j       io_return
 
@@ -613,6 +612,7 @@ ext_skip:
        stm     %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
        mvc     __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
+       xc      __PT_FLAGS(4,%r11),__PT_FLAGS(%r11)
        TRACE_IRQS_OFF
        l       %r1,BASED(.Ldo_IRQ)
        lr      %r2,%r11                # pass pointer to pt_regs
@@ -677,6 +677,7 @@ mcck_skip:
        stm     %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32
        stm     %r8,%r9,__PT_PSW(%r11)
+       xc      __PT_FLAGS(4,%r11),__PT_FLAGS(%r11)
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
        l       %r1,BASED(.Ldo_machine_check)
        lr      %r2,%r11                # pass pointer to pt_regs
@@ -689,7 +690,7 @@ mcck_skip:
        la      %r11,STACK_FRAME_OVERHEAD(%r15)
        lr      %r15,%r1
        ssm     __LC_PGM_NEW_PSW        # turn dat on, keep irqs off
-       tm      __TI_flags+3(%r12),_TIF_MCCK_PENDING
+       tm      __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING
        jno     mcck_return
        TRACE_IRQS_OFF
        l       %r1,BASED(.Lhandle_mcck)
@@ -842,6 +843,8 @@ cleanup_system_call:
        stm     %r0,%r7,__PT_R0(%r9)
        mvc     __PT_PSW(8,%r9),__LC_SVC_OLD_PSW
        mvc     __PT_INT_CODE(4,%r9),__LC_SVC_ILC
+       xc      __PT_FLAGS(4,%r9),__PT_FLAGS(%r9)
+       mvi     __PT_FLAGS+3(%r9),_PIF_SYSCALL
        # setup saved register 15
        st      %r15,28(%r11)           # r15 stack pointer
        # set new psw address and exit
index 5963e43618bb0df3ca790ffa1ce65a9fefd86b0b..c41f3f9067200647441127790afa81ae070f22d7 100644 (file)
@@ -42,13 +42,11 @@ STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
 STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
 
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING | _TIF_PER_TRAP | _TIF_ASCE)
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING | _TIF_ASCE)
-_TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
-                _TIF_SYSCALL_TRACEPOINT)
-_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
+_TIF_WORK      = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
+_TIF_TRACE     = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
+                  _TIF_SYSCALL_TRACEPOINT)
+_CIF_WORK      = (_CIF_MCCK_PENDING | _CIF_ASCE)
+_PIF_WORK      = (_PIF_PER_TRAP)
 
 #define BASED(name) name-system_call(%r13)
 
@@ -190,13 +188,7 @@ ENTRY(__switch_to)
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        mvc     __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
        lg      %r15,__THREAD_ksp(%r3)          # load kernel stack of next
-       llill   %r6,_TIF_TRANSFER               # transfer TIF bits
-       ng      %r6,__TI_flags(%r4)             # isolate TIF bits
-       jz      0f
-       og      %r6,__TI_flags(%r5)             # set TIF bits of next
-       stg     %r6,__TI_flags(%r5)
-       ni      __TI_flags+7(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
-0:     lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
+       lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        br      %r14
 
 __critical_start:
@@ -211,6 +203,7 @@ sysc_stmg:
        stmg    %r8,%r15,__LC_SAVE_AREA_SYNC
        lg      %r10,__LC_LAST_BREAK
        lg      %r12,__LC_THREAD_INFO
+       lghi    %r14,_PIF_SYSCALL
 sysc_per:
        lg      %r15,__LC_KERNEL_STACK
        la      %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
@@ -221,8 +214,8 @@ sysc_vtime:
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
        mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
+       stg     %r14,__PT_FLAGS(%r11)
 sysc_do_svc:
-       oi      __TI_flags+7(%r12),_TIF_SYSCALL
        lg      %r10,__TI_sysc_table(%r12)      # address of system call table
        llgh    %r8,__PT_INT_CODE+2(%r11)
        slag    %r8,%r8,2                       # shift and test for svc 0
@@ -238,7 +231,7 @@ sysc_nr_ok:
        stg     %r2,__PT_ORIG_GPR2(%r11)
        stg     %r7,STACK_FRAME_OVERHEAD(%r15)
        lgf     %r9,0(%r8,%r10)                 # get system call add.
-       tm      __TI_flags+6(%r12),_TIF_TRACE >> 8
+       tm      __TI_flags+7(%r12),_TIF_TRACE
        jnz     sysc_tracesys
        basr    %r14,%r9                        # call sys_xxxx
        stg     %r2,__PT_R2(%r11)               # store return value
@@ -248,9 +241,12 @@ sysc_return:
 sysc_tif:
        tm      __PT_PSW+1(%r11),0x01           # returning to user ?
        jno     sysc_restore
-       tm      __TI_flags+7(%r12),_TIF_WORK_SVC
+       tm      __PT_FLAGS+7(%r11),_PIF_WORK
+       jnz     sysc_work
+       tm      __TI_flags+7(%r12),_TIF_WORK
        jnz     sysc_work                       # check for work
-       ni      __TI_flags+7(%r12),255-_TIF_SYSCALL
+       tm      __LC_CPU_FLAGS+7,_CIF_WORK
+       jnz     sysc_work
 sysc_restore:
        lg      %r14,__LC_VDSO_PER_CPU
        lmg     %r0,%r10,__PT_R0(%r11)
@@ -265,17 +261,17 @@ sysc_done:
 # One of the work bits is on. Find out which one.
 #
 sysc_work:
-       tm      __TI_flags+7(%r12),_TIF_MCCK_PENDING
+       tm      __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING
        jo      sysc_mcck_pending
        tm      __TI_flags+7(%r12),_TIF_NEED_RESCHED
        jo      sysc_reschedule
-       tm      __TI_flags+7(%r12),_TIF_PER_TRAP
+       tm      __PT_FLAGS+7(%r11),_PIF_PER_TRAP
        jo      sysc_singlestep
        tm      __TI_flags+7(%r12),_TIF_SIGPENDING
        jo      sysc_sigpending
        tm      __TI_flags+7(%r12),_TIF_NOTIFY_RESUME
        jo      sysc_notify_resume
-       tm      __TI_flags+7(%r12),_TIF_ASCE
+       tm      __LC_CPU_FLAGS+7,_CIF_ASCE
        jo      sysc_uaccess
        j       sysc_return             # beware of critical section cleanup
 
@@ -287,17 +283,17 @@ sysc_reschedule:
        jg      schedule
 
 #
-# _TIF_MCCK_PENDING is set, call handler
+# _CIF_MCCK_PENDING is set, call handler
 #
 sysc_mcck_pending:
        larl    %r14,sysc_return
        jg      s390_handle_mcck        # TIF bit will be cleared by handler
 
 #
-# _TIF_ASCE is set, load user space asce
+# _CIF_ASCE is set, load user space asce
 #
 sysc_uaccess:
-       ni      __TI_flags+7(%r12),255-_TIF_ASCE
+       ni      __LC_CPU_FLAGS+7,255-_CIF_ASCE
        lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
        j       sysc_return
 
@@ -307,7 +303,7 @@ sysc_uaccess:
 sysc_sigpending:
        lgr     %r2,%r11                # pass pointer to pt_regs
        brasl   %r14,do_signal
-       tm      __TI_flags+7(%r12),_TIF_SYSCALL
+       tm      __PT_FLAGS+7(%r11),_PIF_SYSCALL
        jno     sysc_return
        lmg     %r2,%r7,__PT_R2(%r11)   # load svc arguments
        lg      %r10,__TI_sysc_table(%r12)      # address of system call table
@@ -327,10 +323,10 @@ sysc_notify_resume:
        jg      do_notify_resume
 
 #
-# _TIF_PER_TRAP is set, call do_per_trap
+# _PIF_PER_TRAP is set, call do_per_trap
 #
 sysc_singlestep:
-       ni      __TI_flags+7(%r12),255-_TIF_PER_TRAP
+       ni      __PT_FLAGS+7(%r11),255-_PIF_PER_TRAP
        lgr     %r2,%r11                # pass pointer to pt_regs
        larl    %r14,sysc_return
        jg      do_per_trap
@@ -357,7 +353,7 @@ sysc_tracego:
        basr    %r14,%r9                # call sys_xxx
        stg     %r2,__PT_R2(%r11)       # store return value
 sysc_tracenogo:
-       tm      __TI_flags+6(%r12),_TIF_TRACE >> 8
+       tm      __TI_flags+7(%r12),_TIF_TRACE
        jz      sysc_return
        lgr     %r2,%r11                # pass pointer to pt_regs
        larl    %r14,sysc_return
@@ -416,12 +412,13 @@ ENTRY(pgm_check_handler)
        stmg    %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(4,%r11),__LC_PGM_ILC
        mvc     __PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        stg     %r10,__PT_ARGS(%r11)
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
        jz      0f
        tmhh    %r8,0x0001              # kernel per event ?
        jz      pgm_kprobe
-       oi      __TI_flags+7(%r12),_TIF_PER_TRAP
+       oi      __PT_FLAGS+7(%r11),_PIF_PER_TRAP
        mvc     __THREAD_per_address(8,%r14),__LC_PER_ADDRESS
        mvc     __THREAD_per_cause(2,%r14),__LC_PER_CAUSE
        mvc     __THREAD_per_paid(1,%r14),__LC_PER_PAID
@@ -451,10 +448,10 @@ pgm_kprobe:
 # single stepped system call
 #
 pgm_svcper:
-       oi      __TI_flags+7(%r12),_TIF_PER_TRAP
        mvc     __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW
        larl    %r14,sysc_per
        stg     %r14,__LC_RETURN_PSW+8
+       lghi    %r14,_PIF_SYSCALL | _PIF_PER_TRAP
        lpswe   __LC_RETURN_PSW         # branch to sysc_per and enable irqs
 
 /*
@@ -479,6 +476,7 @@ io_skip:
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 io_loop:
@@ -499,8 +497,10 @@ io_return:
        LOCKDEP_SYS_EXIT
        TRACE_IRQS_ON
 io_tif:
-       tm      __TI_flags+7(%r12),_TIF_WORK_INT
+       tm      __TI_flags+7(%r12),_TIF_WORK
        jnz     io_work                 # there is work to do (signals etc.)
+       tm      __LC_CPU_FLAGS+7,_CIF_WORK
+       jnz     io_work
 io_restore:
        lg      %r14,__LC_VDSO_PER_CPU
        lmg     %r0,%r10,__PT_R0(%r11)
@@ -513,7 +513,7 @@ io_done:
 
 #
 # There is work todo, find out in which context we have been interrupted:
-# 1) if we return to user space we can do all _TIF_WORK_INT work
+# 1) if we return to user space we can do all _TIF_WORK work
 # 2) if we return to kernel code and kvm is enabled check if we need to
 #    modify the psw to leave SIE
 # 3) if we return to kernel code and preemptive scheduling is enabled check
@@ -557,11 +557,9 @@ io_work_user:
 
 #
 # One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED
-#             and _TIF_MCCK_PENDING
 #
 io_work_tif:
-       tm      __TI_flags+7(%r12),_TIF_MCCK_PENDING
+       tm      __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING
        jo      io_mcck_pending
        tm      __TI_flags+7(%r12),_TIF_NEED_RESCHED
        jo      io_reschedule
@@ -569,12 +567,12 @@ io_work_tif:
        jo      io_sigpending
        tm      __TI_flags+7(%r12),_TIF_NOTIFY_RESUME
        jo      io_notify_resume
-       tm      __TI_flags+7(%r12),_TIF_ASCE
+       tm      __LC_CPU_FLAGS+7,_CIF_ASCE
        jo      io_uaccess
        j       io_return               # beware of critical section cleanup
 
 #
-# _TIF_MCCK_PENDING is set, call handler
+# _CIF_MCCK_PENDING is set, call handler
 #
 io_mcck_pending:
        # TRACE_IRQS_ON already done at io_return
@@ -583,10 +581,10 @@ io_mcck_pending:
        j       io_return
 
 #
-# _TIF_ASCE is set, load user space asce
+# _CIF_ASCE is set, load user space asce
 #
 io_uaccess:
-       ni      __TI_flags+7(%r12),255-_TIF_ASCE
+       ni      __LC_CPU_FLAGS+7,255-_CIF_ASCE
        lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
        j       io_return
 
@@ -650,6 +648,7 @@ ext_skip:
        mvc     __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
        mvc     __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
        mvc     __PT_INT_PARM_LONG(8,%r11),0(%r1)
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        lgr     %r2,%r11                # pass pointer to pt_regs
@@ -716,6 +715,7 @@ mcck_skip:
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),0(%r14)
        stmg    %r8,%r9,__PT_PSW(%r11)
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        lgr     %r2,%r11                # pass pointer to pt_regs
        brasl   %r14,s390_do_machine_check
@@ -727,7 +727,7 @@ mcck_skip:
        la      %r11,STACK_FRAME_OVERHEAD(%r1)
        lgr     %r15,%r1
        ssm     __LC_PGM_NEW_PSW        # turn dat on, keep irqs off
-       tm      __TI_flags+7(%r12),_TIF_MCCK_PENDING
+       tm      __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING
        jno     mcck_return
        TRACE_IRQS_OFF
        brasl   %r14,s390_handle_mcck
@@ -884,6 +884,8 @@ cleanup_system_call:
        stmg    %r0,%r7,__PT_R0(%r9)
        mvc     __PT_PSW(16,%r9),__LC_SVC_OLD_PSW
        mvc     __PT_INT_CODE(4,%r9),__LC_SVC_ILC
+       xc      __PT_FLAGS(8,%r9),__PT_FLAGS(%r9)
+       mvi     __PT_FLAGS+7(%r9),_PIF_SYSCALL
        # setup saved register r15
        stg     %r15,56(%r11)           # r15 stack pointer
        # set new psw address and exit
index 9a99856df1c93ea4d23612d7e2c4670cd82a1a81..6dbe80983a24fcd9ea04339d90fb2c993e7546f5 100644 (file)
@@ -59,7 +59,6 @@ ENTRY(startup_continue)
        .long   0                       # cr13: home space segment table
        .long   0xc0000000              # cr14: machine check handling off
        .long   0                       # cr15: linkage stack operations
-.Lmchunk:.long memory_chunk
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
 .Lparmaddr: .long PARMAREA
index c4c0338198791d4a187c73f8490c0fc39595078d..210e1285f75a44e4fb931e527bdf786eeba6c5ee 100644 (file)
@@ -55,7 +55,7 @@ void s390_handle_mcck(void)
        local_mcck_disable();
        mcck = __get_cpu_var(cpu_mcck);
        memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
-       clear_thread_flag(TIF_MCCK_PENDING);
+       clear_cpu_flag(CIF_MCCK_PENDING);
        local_mcck_enable();
        local_irq_restore(flags);
 
@@ -313,7 +313,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
                         */
                        mcck->kill_task = 1;
                        mcck->mcck_code = *(unsigned long long *) mci;
-                       set_thread_flag(TIF_MCCK_PENDING);
+                       set_cpu_flag(CIF_MCCK_PENDING);
                } else {
                        /*
                         * Couldn't restore all register contents while in
@@ -352,12 +352,12 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
        if (mci->cp) {
                /* Channel report word pending */
                mcck->channel_report = 1;
-               set_thread_flag(TIF_MCCK_PENDING);
+               set_cpu_flag(CIF_MCCK_PENDING);
        }
        if (mci->w) {
                /* Warning pending */
                mcck->warning = 1;
-               set_thread_flag(TIF_MCCK_PENDING);
+               set_cpu_flag(CIF_MCCK_PENDING);
        }
        nmi_exit();
 }
index dd145321d2151d11f37c7694968f384326eb7804..93b9ca42e5c0ace2ac209789befa3242850b0043 100644 (file)
@@ -64,7 +64,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 void arch_cpu_idle(void)
 {
        local_mcck_disable();
-       if (test_thread_flag(TIF_MCCK_PENDING)) {
+       if (test_cpu_flag(CIF_MCCK_PENDING)) {
                local_mcck_enable();
                local_irq_enable();
                return;
@@ -76,7 +76,7 @@ void arch_cpu_idle(void)
 
 void arch_cpu_idle_exit(void)
 {
-       if (test_thread_flag(TIF_MCCK_PENDING))
+       if (test_cpu_flag(CIF_MCCK_PENDING))
                s390_handle_mcck();
 }
 
@@ -123,7 +123,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
        memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
        memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
        clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
-       clear_tsk_thread_flag(p, TIF_PER_TRAP);
        /* Initialize per thread user and system timer values */
        ti = task_thread_info(p);
        ti->user_timer = 0;
@@ -152,6 +151,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
        }
        frame->childregs = *current_pt_regs();
        frame->childregs.gprs[2] = 0;   /* child returns 0 on fork. */
+       frame->childregs.flags = 0;
        if (new_stackp)
                frame->childregs.gprs[15] = new_stackp;
 
index 1c82619eb4f768343f8a9c20f8f30a00ba7370fd..2d716734b5b1b2b482e580aee483d07b014c301f 100644 (file)
@@ -136,7 +136,7 @@ void ptrace_disable(struct task_struct *task)
        memset(&task->thread.per_user, 0, sizeof(task->thread.per_user));
        memset(&task->thread.per_event, 0, sizeof(task->thread.per_event));
        clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
-       clear_tsk_thread_flag(task, TIF_PER_TRAP);
+       clear_pt_regs_flag(task_pt_regs(task), PIF_PER_TRAP);
        task->thread.per_flags = 0;
 }
 
@@ -813,7 +813,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                 * debugger stored an invalid system call number. Skip
                 * the system call and the system call restart handling.
                 */
-               clear_thread_flag(TIF_SYSCALL);
+               clear_pt_regs_flag(regs, PIF_SYSCALL);
                ret = -1;
        }
 
index 88d1ca81e2dd7fc5ac74fc31c4b0eca47aec754f..1e2264b46e4c1d21e31b1edeb39d935ea789c359 100644 (file)
@@ -78,10 +78,9 @@ EXPORT_SYMBOL(console_irq);
 unsigned long elf_hwcap = 0;
 char elf_platform[ELF_PLATFORM_SIZE];
 
-struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
-
 int __initdata memory_end_set;
 unsigned long __initdata memory_end;
+unsigned long __initdata max_physmem_end;
 
 unsigned long VMALLOC_START;
 EXPORT_SYMBOL(VMALLOC_START);
@@ -212,7 +211,7 @@ static void __init conmode_default(void)
        }
 }
 
-#ifdef CONFIG_ZFCPDUMP
+#ifdef CONFIG_CRASH_DUMP
 static void __init setup_zfcpdump(void)
 {
        if (ipl_info.type != IPL_TYPE_FCP_DUMP)
@@ -224,7 +223,7 @@ static void __init setup_zfcpdump(void)
 }
 #else
 static inline void setup_zfcpdump(void) {}
-#endif /* CONFIG_ZFCPDUMP */
+#endif /* CONFIG_CRASH_DUMP */
 
  /*
  * Reboot, halt and power_off stubs. They just call _machine_restart,
@@ -273,6 +272,7 @@ EXPORT_SYMBOL_GPL(pm_power_off);
 static int __init early_parse_mem(char *p)
 {
        memory_end = memparse(p, &p);
+       memory_end &= PAGE_MASK;
        memory_end_set = 1;
        return 0;
 }
@@ -373,6 +373,10 @@ static void __init setup_lowcore(void)
        mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source);
        mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw);
 
+#ifdef CONFIG_SMP
+       lc->spinlock_lockval = arch_spin_lockval(0);
+#endif
+
        set_prefix((u32)(unsigned long) lc);
        lowcore_ptr[0] = lc;
 }
@@ -401,7 +405,8 @@ static struct resource __initdata *standard_resources[] = {
 static void __init setup_resources(void)
 {
        struct resource *res, *std_res, *sub_res;
-       int i, j;
+       struct memblock_region *reg;
+       int j;
 
        code_resource.start = (unsigned long) &_text;
        code_resource.end = (unsigned long) &_etext - 1;
@@ -410,24 +415,13 @@ static void __init setup_resources(void)
        bss_resource.start = (unsigned long) &__bss_start;
        bss_resource.end = (unsigned long) &__bss_stop - 1;
 
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               if (!memory_chunk[i].size)
-                       continue;
+       for_each_memblock(memory, reg) {
                res = alloc_bootmem_low(sizeof(*res));
                res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
-               switch (memory_chunk[i].type) {
-               case CHUNK_READ_WRITE:
-                       res->name = "System RAM";
-                       break;
-               case CHUNK_READ_ONLY:
-                       res->name = "System ROM";
-                       res->flags |= IORESOURCE_READONLY;
-                       break;
-               default:
-                       res->name = "reserved";
-               }
-               res->start = memory_chunk[i].addr;
-               res->end = res->start + memory_chunk[i].size - 1;
+
+               res->name = "System RAM";
+               res->start = reg->base;
+               res->end = reg->base + reg->size - 1;
                request_resource(&iomem_resource, res);
 
                for (j = 0; j < ARRAY_SIZE(standard_resources); j++) {
@@ -451,48 +445,11 @@ static void __init setup_resources(void)
 static void __init setup_memory_end(void)
 {
        unsigned long vmax, vmalloc_size, tmp;
-       unsigned long real_memory_size = 0;
-       int i;
-
-
-#ifdef CONFIG_ZFCPDUMP
-       if (ipl_info.type == IPL_TYPE_FCP_DUMP &&
-           !OLDMEM_BASE && sclp_get_hsa_size()) {
-               memory_end = sclp_get_hsa_size();
-               memory_end_set = 1;
-       }
-#endif
-       memory_end &= PAGE_MASK;
-
-       /*
-        * Make sure all chunks are MAX_ORDER aligned so we don't need the
-        * extra checks that HOLES_IN_ZONE would require.
-        */
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               unsigned long start, end;
-               struct mem_chunk *chunk;
-               unsigned long align;
-
-               chunk = &memory_chunk[i];
-               if (!chunk->size)
-                       continue;
-               align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
-               start = (chunk->addr + align - 1) & ~(align - 1);
-               end = (chunk->addr + chunk->size) & ~(align - 1);
-               if (start >= end)
-                       memset(chunk, 0, sizeof(*chunk));
-               else {
-                       chunk->addr = start;
-                       chunk->size = end - start;
-               }
-               real_memory_size = max(real_memory_size,
-                                      chunk->addr + chunk->size);
-       }
 
        /* Choose kernel address space layout: 2, 3, or 4 levels. */
 #ifdef CONFIG_64BIT
        vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN;
-       tmp = (memory_end ?: real_memory_size) / PAGE_SIZE;
+       tmp = (memory_end ?: max_physmem_end) / PAGE_SIZE;
        tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size;
        if (tmp <= (1UL << 42))
                vmax = 1UL << 42;       /* 3-level kernel page table */
@@ -520,21 +477,11 @@ static void __init setup_memory_end(void)
        vmemmap = (struct page *) tmp;
 
        /* Take care that memory_end is set and <= vmemmap */
-       memory_end = min(memory_end ?: real_memory_size, tmp);
-
-       /* Fixup memory chunk array to fit into 0..memory_end */
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               struct mem_chunk *chunk = &memory_chunk[i];
+       memory_end = min(memory_end ?: max_physmem_end, tmp);
+       max_pfn = max_low_pfn = PFN_DOWN(memory_end);
+       memblock_remove(memory_end, ULONG_MAX);
 
-               if (!chunk->size)
-                       continue;
-               if (chunk->addr >= memory_end) {
-                       memset(chunk, 0, sizeof(*chunk));
-                       continue;
-               }
-               if (chunk->addr + chunk->size > memory_end)
-                       chunk->size = memory_end - chunk->addr;
-       }
+       pr_notice("Max memory size: %luMB\n", memory_end >> 20);
 }
 
 static void __init setup_vmcoreinfo(void)
@@ -544,89 +491,6 @@ static void __init setup_vmcoreinfo(void)
 
 #ifdef CONFIG_CRASH_DUMP
 
-/*
- * Find suitable location for crashkernel memory
- */
-static unsigned long __init find_crash_base(unsigned long crash_size,
-                                           char **msg)
-{
-       unsigned long crash_base;
-       struct mem_chunk *chunk;
-       int i;
-
-       if (memory_chunk[0].size < crash_size) {
-               *msg = "first memory chunk must be at least crashkernel size";
-               return 0;
-       }
-       if (OLDMEM_BASE && crash_size == OLDMEM_SIZE)
-               return OLDMEM_BASE;
-
-       for (i = MEMORY_CHUNKS - 1; i >= 0; i--) {
-               chunk = &memory_chunk[i];
-               if (chunk->size == 0)
-                       continue;
-               if (chunk->type != CHUNK_READ_WRITE)
-                       continue;
-               if (chunk->size < crash_size)
-                       continue;
-               crash_base = (chunk->addr + chunk->size) - crash_size;
-               if (crash_base < crash_size)
-                       continue;
-               if (crash_base < sclp_get_hsa_size())
-                       continue;
-               if (crash_base < (unsigned long) INITRD_START + INITRD_SIZE)
-                       continue;
-               return crash_base;
-       }
-       *msg = "no suitable area found";
-       return 0;
-}
-
-/*
- * Check if crash_base and crash_size is valid
- */
-static int __init verify_crash_base(unsigned long crash_base,
-                                   unsigned long crash_size,
-                                   char **msg)
-{
-       struct mem_chunk *chunk;
-       int i;
-
-       /*
-        * Because we do the swap to zero, we must have at least 'crash_size'
-        * bytes free space before crash_base
-        */
-       if (crash_size > crash_base) {
-               *msg = "crashkernel offset must be greater than size";
-               return -EINVAL;
-       }
-
-       /* First memory chunk must be at least crash_size */
-       if (memory_chunk[0].size < crash_size) {
-               *msg = "first memory chunk must be at least crashkernel size";
-               return -EINVAL;
-       }
-       /* Check if we fit into the respective memory chunk */
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               chunk = &memory_chunk[i];
-               if (chunk->size == 0)
-                       continue;
-               if (crash_base < chunk->addr)
-                       continue;
-               if (crash_base >= chunk->addr + chunk->size)
-                       continue;
-               /* we have found the memory chunk */
-               if (crash_base + crash_size > chunk->addr + chunk->size) {
-                       *msg = "selected memory chunk is too small for "
-                               "crashkernel memory";
-                       return -EINVAL;
-               }
-               return 0;
-       }
-       *msg = "invalid memory range specified";
-       return -EINVAL;
-}
-
 /*
  * When kdump is enabled, we have to ensure that no memory from
  * the area [0 - crashkernel memory size] and
@@ -652,24 +516,45 @@ static struct notifier_block kdump_mem_nb = {
 
 #endif
 
+/*
+ * Make sure that the area behind memory_end is protected
+ */
+static void reserve_memory_end(void)
+{
+#ifdef CONFIG_CRASH_DUMP
+       if (ipl_info.type == IPL_TYPE_FCP_DUMP &&
+           !OLDMEM_BASE && sclp_get_hsa_size()) {
+               memory_end = sclp_get_hsa_size();
+               memory_end &= PAGE_MASK;
+               memory_end_set = 1;
+       }
+#endif
+       if (!memory_end_set)
+               return;
+       memblock_reserve(memory_end, ULONG_MAX);
+}
+
 /*
  * Make sure that oldmem, where the dump is stored, is protected
  */
 static void reserve_oldmem(void)
 {
 #ifdef CONFIG_CRASH_DUMP
-       unsigned long real_size = 0;
-       int i;
-
-       if (!OLDMEM_BASE)
-               return;
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               struct mem_chunk *chunk = &memory_chunk[i];
+       if (OLDMEM_BASE)
+               /* Forget all memory above the running kdump system */
+               memblock_reserve(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX);
+#endif
+}
 
-               real_size = max(real_size, chunk->addr + chunk->size);
-       }
-       create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE);
-       create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE);
+/*
+ * Make sure that oldmem, where the dump is stored, is protected
+ */
+static void remove_oldmem(void)
+{
+#ifdef CONFIG_CRASH_DUMP
+       if (OLDMEM_BASE)
+               /* Forget all memory above the running kdump system */
+               memblock_remove(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX);
 #endif
 }
 
@@ -680,167 +565,132 @@ static void __init reserve_crashkernel(void)
 {
 #ifdef CONFIG_CRASH_DUMP
        unsigned long long crash_base, crash_size;
-       char *msg = NULL;
+       phys_addr_t low, high;
        int rc;
 
        rc = parse_crashkernel(boot_command_line, memory_end, &crash_size,
                               &crash_base);
-       if (rc || crash_size == 0)
-               return;
+
        crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN);
        crash_size = ALIGN(crash_size, KEXEC_CRASH_MEM_ALIGN);
-       if (register_memory_notifier(&kdump_mem_nb))
+       if (rc || crash_size == 0)
                return;
-       if (!crash_base)
-               crash_base = find_crash_base(crash_size, &msg);
-       if (!crash_base) {
-               pr_info("crashkernel reservation failed: %s\n", msg);
-               unregister_memory_notifier(&kdump_mem_nb);
+
+       if (memblock.memory.regions[0].size < crash_size) {
+               pr_info("crashkernel reservation failed: %s\n",
+                       "first memory chunk must be at least crashkernel size");
                return;
        }
-       if (verify_crash_base(crash_base, crash_size, &msg)) {
-               pr_info("crashkernel reservation failed: %s\n", msg);
-               unregister_memory_notifier(&kdump_mem_nb);
+
+       low = crash_base ?: OLDMEM_BASE;
+       high = low + crash_size;
+       if (low >= OLDMEM_BASE && high <= OLDMEM_BASE + OLDMEM_SIZE) {
+               /* The crashkernel fits into OLDMEM, reuse OLDMEM */
+               crash_base = low;
+       } else {
+               /* Find suitable area in free memory */
+               low = max_t(unsigned long, crash_size, sclp_get_hsa_size());
+               high = crash_base ? crash_base + crash_size : ULONG_MAX;
+
+               if (crash_base && crash_base < low) {
+                       pr_info("crashkernel reservation failed: %s\n",
+                               "crash_base too low");
+                       return;
+               }
+               low = crash_base ?: low;
+               crash_base = memblock_find_in_range(low, high, crash_size,
+                                                   KEXEC_CRASH_MEM_ALIGN);
+       }
+
+       if (!crash_base) {
+               pr_info("crashkernel reservation failed: %s\n",
+                       "no suitable area found");
                return;
        }
+
+       if (register_memory_notifier(&kdump_mem_nb))
+               return;
+
        if (!OLDMEM_BASE && MACHINE_IS_VM)
                diag10_range(PFN_DOWN(crash_base), PFN_DOWN(crash_size));
        crashk_res.start = crash_base;
        crashk_res.end = crash_base + crash_size - 1;
        insert_resource(&iomem_resource, &crashk_res);
-       create_mem_hole(memory_chunk, crash_base, crash_size);
+       memblock_remove(crash_base, crash_size);
        pr_info("Reserving %lluMB of memory at %lluMB "
                "for crashkernel (System RAM: %luMB)\n",
-               crash_size >> 20, crash_base >> 20, memory_end >> 20);
+               crash_size >> 20, crash_base >> 20,
+               (unsigned long)memblock.memory.total_size >> 20);
        os_info_crashkernel_add(crash_base, crash_size);
 #endif
 }
 
-static void __init setup_memory(void)
+/*
+ * Reserve the initrd from being used by memblock
+ */
+static void __init reserve_initrd(void)
 {
-        unsigned long bootmap_size;
-       unsigned long start_pfn, end_pfn;
-       int i;
+#ifdef CONFIG_BLK_DEV_INITRD
+       initrd_start = INITRD_START;
+       initrd_end = initrd_start + INITRD_SIZE;
+       memblock_reserve(INITRD_START, INITRD_SIZE);
+#endif
+}
 
-       /*
-        * partially used pages are not usable - thus
-        * we are rounding upwards:
-        */
+/*
+ * Check for initrd being in usable memory
+ */
+static void __init check_initrd(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (INITRD_START && INITRD_SIZE &&
+           !memblock_is_region_memory(INITRD_START, INITRD_SIZE)) {
+               pr_err("initrd does not fit memory.\n");
+               memblock_free(INITRD_START, INITRD_SIZE);
+               initrd_start = initrd_end = 0;
+       }
+#endif
+}
+
+/*
+ * Reserve all kernel text
+ */
+static void __init reserve_kernel(void)
+{
+       unsigned long start_pfn;
        start_pfn = PFN_UP(__pa(&_end));
-       end_pfn = max_pfn = PFN_DOWN(memory_end);
 
-#ifdef CONFIG_BLK_DEV_INITRD
        /*
-        * Move the initrd in case the bitmap of the bootmem allocater
-        * would overwrite it.
+        * Reserve memory used for lowcore/command line/kernel image.
         */
+       memblock_reserve(0, (unsigned long)_ehead);
+       memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
+                        - (unsigned long)_stext);
+}
 
-       if (INITRD_START && INITRD_SIZE) {
-               unsigned long bmap_size;
-               unsigned long start;
-
-               bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1);
-               bmap_size = PFN_PHYS(bmap_size);
-
-               if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) {
-                       start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE;
-
+static void __init reserve_elfcorehdr(void)
+{
 #ifdef CONFIG_CRASH_DUMP
-                       if (OLDMEM_BASE) {
-                               /* Move initrd behind kdump oldmem */
-                               if (start + INITRD_SIZE > OLDMEM_BASE &&
-                                   start < OLDMEM_BASE + OLDMEM_SIZE)
-                                       start = OLDMEM_BASE + OLDMEM_SIZE;
-                       }
-#endif
-                       if (start + INITRD_SIZE > memory_end) {
-                               pr_err("initrd extends beyond end of "
-                                      "memory (0x%08lx > 0x%08lx) "
-                                      "disabling initrd\n",
-                                      start + INITRD_SIZE, memory_end);
-                               INITRD_START = INITRD_SIZE = 0;
-                       } else {
-                               pr_info("Moving initrd (0x%08lx -> "
-                                       "0x%08lx, size: %ld)\n",
-                                       INITRD_START, start, INITRD_SIZE);
-                               memmove((void *) start, (void *) INITRD_START,
-                                       INITRD_SIZE);
-                               INITRD_START = start;
-                       }
-               }
-       }
+       if (is_kdump_kernel())
+               memblock_reserve(elfcorehdr_addr - OLDMEM_BASE,
+                                PAGE_ALIGN(elfcorehdr_size));
 #endif
+}
 
-       /*
-        * Initialize the boot-time allocator
-        */
-       bootmap_size = init_bootmem(start_pfn, end_pfn);
+static void __init setup_memory(void)
+{
+       struct memblock_region *reg;
 
        /*
-        * Register RAM areas with the bootmem allocator.
+        * Init storage key for present memory
         */
-
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               unsigned long start_chunk, end_chunk, pfn;
-
-               if (!memory_chunk[i].size)
-                       continue;
-               start_chunk = PFN_DOWN(memory_chunk[i].addr);
-               end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size);
-               end_chunk = min(end_chunk, end_pfn);
-               if (start_chunk >= end_chunk)
-                       continue;
-               memblock_add_node(PFN_PHYS(start_chunk),
-                                 PFN_PHYS(end_chunk - start_chunk), 0);
-               pfn = max(start_chunk, start_pfn);
-               storage_key_init_range(PFN_PHYS(pfn), PFN_PHYS(end_chunk));
+       for_each_memblock(memory, reg) {
+               storage_key_init_range(reg->base, reg->base + reg->size);
        }
-
        psw_set_key(PAGE_DEFAULT_KEY);
 
-       free_bootmem_with_active_regions(0, max_pfn);
-
-       /*
-        * Reserve memory used for lowcore/command line/kernel image.
-        */
-       reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT);
-       reserve_bootmem((unsigned long)_stext,
-                       PFN_PHYS(start_pfn) - (unsigned long)_stext,
-                       BOOTMEM_DEFAULT);
-       /*
-        * Reserve the bootmem bitmap itself as well. We do this in two
-        * steps (first step was init_bootmem()) because this catches
-        * the (very unlikely) case of us accidentally initializing the
-        * bootmem allocator with an invalid RAM area.
-        */
-       reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size,
-                       BOOTMEM_DEFAULT);
-
-#ifdef CONFIG_CRASH_DUMP
-       if (crashk_res.start)
-               reserve_bootmem(crashk_res.start,
-                               crashk_res.end - crashk_res.start + 1,
-                               BOOTMEM_DEFAULT);
-       if (is_kdump_kernel())
-               reserve_bootmem(elfcorehdr_addr - OLDMEM_BASE,
-                               PAGE_ALIGN(elfcorehdr_size), BOOTMEM_DEFAULT);
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (INITRD_START && INITRD_SIZE) {
-               if (INITRD_START + INITRD_SIZE <= memory_end) {
-                       reserve_bootmem(INITRD_START, INITRD_SIZE,
-                                       BOOTMEM_DEFAULT);
-                       initrd_start = INITRD_START;
-                       initrd_end = initrd_start + INITRD_SIZE;
-               } else {
-                       pr_err("initrd extends beyond end of "
-                              "memory (0x%08lx > 0x%08lx) "
-                              "disabling initrd\n",
-                              initrd_start + INITRD_SIZE, memory_end);
-                       initrd_start = initrd_end = 0;
-               }
-       }
-#endif
+       /* Only cosmetics */
+       memblock_enforce_memory_limit(memblock_end_of_DRAM());
 }
 
 /*
@@ -989,23 +839,46 @@ void __init setup_arch(char **cmdline_p)
 
         ROOT_DEV = Root_RAM0;
 
+       /* Is init_mm really needed? */
        init_mm.start_code = PAGE_OFFSET;
        init_mm.end_code = (unsigned long) &_etext;
        init_mm.end_data = (unsigned long) &_edata;
        init_mm.brk = (unsigned long) &_end;
 
        parse_early_param();
-       detect_memory_layout(memory_chunk, memory_end);
        os_info_init();
        setup_ipl();
+
+       /* Do some memory reservations *before* memory is added to memblock */
+       reserve_memory_end();
        reserve_oldmem();
+       reserve_kernel();
+       reserve_initrd();
+       reserve_elfcorehdr();
+       memblock_allow_resize();
+
+       /* Get information about *all* installed memory */
+       detect_memory_memblock();
+
+       remove_oldmem();
+
+       /*
+        * Make sure all chunks are MAX_ORDER aligned so we don't need the
+        * extra checks that HOLES_IN_ZONE would require.
+        *
+        * Is this still required?
+        */
+       memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT));
+
        setup_memory_end();
-       reserve_crashkernel();
        setup_memory();
+
+       check_initrd();
+       reserve_crashkernel();
+
        setup_resources();
        setup_vmcoreinfo();
        setup_lowcore();
-
        smp_fill_possible_mask();
         cpu_init();
        s390_init_cpu_topology();
index d8fd508ccd1e180b7679d24939b253d31a56bc26..42b49f9e19bf844dead561e546a160f35d1407bb 100644 (file)
@@ -113,7 +113,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
               sizeof(current->thread.fp_regs));
 
        restore_fp_regs(current->thread.fp_regs.fprs);
-       clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */
+       clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
        return 0;
 }
 
@@ -356,7 +356,7 @@ void do_signal(struct pt_regs *regs)
         * call information.
         */
        current_thread_info()->system_call =
-               test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0;
+               test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0;
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
        if (signr > 0) {
@@ -384,7 +384,7 @@ void do_signal(struct pt_regs *regs)
                        }
                }
                /* No longer in a system call */
-               clear_thread_flag(TIF_SYSCALL);
+               clear_pt_regs_flag(regs, PIF_SYSCALL);
 
                if (is_compat_task())
                        handle_signal32(signr, &ka, &info, oldset, regs);
@@ -394,7 +394,7 @@ void do_signal(struct pt_regs *regs)
        }
 
        /* No handlers present - check for system call restart */
-       clear_thread_flag(TIF_SYSCALL);
+       clear_pt_regs_flag(regs, PIF_SYSCALL);
        if (current_thread_info()->system_call) {
                regs->int_code = current_thread_info()->system_call;
                switch (regs->gprs[2]) {
@@ -407,9 +407,9 @@ void do_signal(struct pt_regs *regs)
                case -ERESTARTNOINTR:
                        /* Restart system call with magic TIF bit. */
                        regs->gprs[2] = regs->orig_gpr2;
-                       set_thread_flag(TIF_SYSCALL);
+                       set_pt_regs_flag(regs, PIF_SYSCALL);
                        if (test_thread_flag(TIF_SINGLE_STEP))
-                               set_thread_flag(TIF_PER_TRAP);
+                               clear_pt_regs_flag(regs, PIF_PER_TRAP);
                        break;
                }
        }
index 86e65ec3422b9585a9281b7204bcfce24181f10d..243c7e51260055c3de2a57e2852ed82de075f18f 100644 (file)
@@ -170,6 +170,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
        lc->panic_stack = pcpu->panic_stack + PAGE_SIZE
                - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->cpu_nr = cpu;
+       lc->spinlock_lockval = arch_spin_lockval(cpu);
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE) {
                lc->extended_save_area_addr = get_zeroed_page(GFP_KERNEL);
@@ -226,6 +227,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
        cpumask_set_cpu(cpu, mm_cpumask(&init_mm));
        atomic_inc(&init_mm.context.attach_count);
        lc->cpu_nr = cpu;
+       lc->spinlock_lockval = arch_spin_lockval(cpu);
        lc->percpu_offset = __per_cpu_offset[cpu];
        lc->kernel_asce = S390_lowcore.kernel_asce;
        lc->machine_flags = S390_lowcore.machine_flags;
@@ -402,15 +404,6 @@ void smp_send_stop(void)
        }
 }
 
-/*
- * Stop the current cpu.
- */
-void smp_stop_cpu(void)
-{
-       pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
-       for (;;) ;
-}
-
 /*
  * This is the main routine where commands issued by other
  * cpus are handled.
@@ -519,7 +512,7 @@ void smp_ctl_clear_bit(int cr, int bit)
 }
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 
-#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_CRASH_DUMP)
+#ifdef CONFIG_CRASH_DUMP
 
 static void __init smp_get_save_area(int cpu, u16 address)
 {
@@ -534,14 +527,12 @@ static void __init smp_get_save_area(int cpu, u16 address)
        save_area = dump_save_area_create(cpu);
        if (!save_area)
                panic("could not allocate memory for save area\n");
-#ifdef CONFIG_CRASH_DUMP
        if (address == boot_cpu_address) {
                /* Copy the registers of the boot cpu. */
                copy_oldmem_page(1, (void *) save_area, sizeof(*save_area),
                                 SAVE_AREA_BASE - PAGE_SIZE, 0);
                return;
        }
-#endif
        /* Get the registers of a non-boot cpu. */
        __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
        memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
@@ -558,11 +549,11 @@ int smp_store_status(int cpu)
        return 0;
 }
 
-#else /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
+#else /* CONFIG_CRASH_DUMP */
 
 static inline void smp_get_save_area(int cpu, u16 address) { }
 
-#endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
+#endif /* CONFIG_CRASH_DUMP */
 
 void smp_cpu_set_polarization(int cpu, int val)
 {
@@ -809,6 +800,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
 void __init smp_setup_processor_id(void)
 {
        S390_lowcore.cpu_nr = 0;
+       S390_lowcore.spinlock_lockval = arch_spin_lockval(0);
 }
 
 /*
index 6298fed11cedf8bcfcb536474d33552a115f2fe2..fa3b8cdaadacf4cf14cf24976074f0319a0ebcf9 100644 (file)
@@ -333,7 +333,9 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info,
                nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
        nr_masks = max(nr_masks, 1);
        for (i = 0; i < nr_masks; i++) {
-               mask->next = alloc_bootmem(sizeof(struct mask_info));
+               mask->next = alloc_bootmem_align(
+                       roundup_pow_of_two(sizeof(struct mask_info)),
+                       roundup_pow_of_two(sizeof(struct mask_info)));
                mask = mask->next;
        }
 }
index b3ecb8f5b6ce2bcefb4fe92a64b99d2012cdd770..020659745df01214a286d58455fe4372df52a277 100644 (file)
@@ -906,7 +906,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
        if (need_resched())
                schedule();
 
-       if (test_thread_flag(TIF_MCCK_PENDING))
+       if (test_cpu_flag(CIF_MCCK_PENDING))
                s390_handle_mcck();
 
        if (!kvm_is_ucontrol(vcpu->kvm))
index f709983f41f883ed567aeba87a6c1e15bc196340..0946b99fe6c3653be529dafa99f7a40940fd343d 100644 (file)
@@ -1,8 +1,9 @@
 /*
  *    Out of line spinlock code.
  *
- *    Copyright IBM Corp. 2004, 2006
+ *    Copyright IBM Corp. 2004, 2014
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *              Philipp Hachtmann (phacht@linux.vnet.ibm.com)
  */
 
 #include <linux/types.h>
@@ -24,29 +25,111 @@ static int __init spin_retry_setup(char *str)
 }
 __setup("spin_retry=", spin_retry_setup);
 
+#ifdef CONFIG_S390_TICKET_SPINLOCK
+
+void arch_spin_lock_wait(arch_spinlock_t *lp)
+{
+       arch_spinlock_t cur, new;
+       int cpu, owner, count;
+       u8 ticket = 0;
+
+       cpu = smp_processor_id();
+       count = spin_retry;
+       while (1) {
+               new.lock = cur.lock = ACCESS_ONCE(lp->lock);
+               if (new.lock == 0) {
+                       /* The lock is free with no waiter, try to get it. */
+                       new.tickets.owner = (u16) ~cpu;
+               } else if (!ticket) {
+                       /* Try to get a ticket. */
+                       new.tickets.tail = (u8)(new.tickets.tail + 1) ? : 1;
+                       if (new.tickets.tail == new.tickets.head)
+                               /* Overflow, can't get a ticket. */
+                               new.tickets.tail = cur.tickets.tail;
+               } else if (new.tickets.head == ticket)
+                       new.tickets.owner = (u16) ~cpu;
+               /* Do the atomic update. */
+               if (cur.lock != new.lock &&
+                   _raw_compare_and_swap(&lp->lock, cur.lock, new.lock)) {
+                       /* Update successful. */
+                       if (new.tickets.owner == (u16) ~cpu)
+                               return;         /* Got the lock. */
+                       ticket = new.tickets.tail; /* Got a ticket. */
+                       count = 0;
+               }
+               /* Lock could not be acquired yet. */
+               if (count--)
+                       continue;
+               count = spin_retry;
+               owner = cur.tickets.owner;
+               if (ticket) {
+                       if (owner && smp_vcpu_scheduled(~owner)) {
+                               if (MACHINE_IS_LPAR)
+                                       continue;
+                       } else
+                               count = 0;
+               }
+               /* Yield the cpu. */
+               if (owner)
+                       smp_yield_cpu(~owner);
+               else
+                       smp_yield();
+       }
+}
+EXPORT_SYMBOL(arch_spin_lock_wait);
+
+void arch_spin_unlock_slow(arch_spinlock_t *lp)
+{
+       arch_spinlock_t cur, new;
+
+       do {
+               cur.lock = ACCESS_ONCE(lp->lock);
+               new.lock = 0;
+               if (cur.tickets.head != cur.tickets.tail) {
+                       new.tickets.tail = cur.tickets.tail;
+                       new.tickets.head = (u8)(cur.tickets.head + 1) ? : 1;
+                       new.tickets.owner = 0;
+               }
+       } while (!_raw_compare_and_swap(&lp->lock, cur.lock, new.lock));
+}
+EXPORT_SYMBOL(arch_spin_unlock_slow);
+
+void arch_spin_relax(arch_spinlock_t *lp)
+{
+       unsigned int cpu = lp->tickets.owner;
+
+       if (cpu != 0) {
+               if (MACHINE_IS_VM || MACHINE_IS_KVM ||
+                   !smp_vcpu_scheduled(~cpu))
+                       smp_yield_cpu(~cpu);
+       }
+}
+EXPORT_SYMBOL(arch_spin_relax);
+
+#else /* CONFIG_S390_TICKET_SPINLOCK */
+
 void arch_spin_lock_wait(arch_spinlock_t *lp)
 {
        int count = spin_retry;
-       unsigned int cpu = ~smp_processor_id();
+       unsigned int cpu = SPINLOCK_LOCKVAL;
        unsigned int owner;
 
        while (1) {
-               owner = lp->owner_cpu;
+               owner = lp->lock;
                if (!owner || smp_vcpu_scheduled(~owner)) {
                        for (count = spin_retry; count > 0; count--) {
                                if (arch_spin_is_locked(lp))
                                        continue;
-                               if (_raw_compare_and_swap(&lp->owner_cpu, 0,
-                                                         cpu) == 0)
+                               if (_raw_compare_and_swap(&lp->lock, 0, cpu))
                                        return;
                        }
                        if (MACHINE_IS_LPAR)
                                continue;
                }
-               owner = lp->owner_cpu;
+               owner = lp->lock;
                if (owner)
                        smp_yield_cpu(~owner);
-               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+               if (_raw_compare_and_swap(&lp->lock, 0, cpu))
                        return;
        }
 }
@@ -55,62 +138,62 @@ EXPORT_SYMBOL(arch_spin_lock_wait);
 void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
 {
        int count = spin_retry;
-       unsigned int cpu = ~smp_processor_id();
+       unsigned int cpu = SPINLOCK_LOCKVAL;
        unsigned int owner;
 
        local_irq_restore(flags);
        while (1) {
-               owner = lp->owner_cpu;
+               owner = lp->lock;
                if (!owner || smp_vcpu_scheduled(~owner)) {
                        for (count = spin_retry; count > 0; count--) {
                                if (arch_spin_is_locked(lp))
                                        continue;
                                local_irq_disable();
-                               if (_raw_compare_and_swap(&lp->owner_cpu, 0,
-                                                         cpu) == 0)
+                               if (_raw_compare_and_swap(&lp->lock, 0, cpu))
                                        return;
                                local_irq_restore(flags);
                        }
                        if (MACHINE_IS_LPAR)
                                continue;
                }
-               owner = lp->owner_cpu;
+               owner = lp->lock;
                if (owner)
                        smp_yield_cpu(~owner);
                local_irq_disable();
-               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+               if (_raw_compare_and_swap(&lp->lock, 0, cpu))
                        return;
                local_irq_restore(flags);
        }
 }
 EXPORT_SYMBOL(arch_spin_lock_wait_flags);
 
+void arch_spin_relax(arch_spinlock_t *lp)
+{
+       unsigned int cpu = lp->lock;
+       if (cpu != 0) {
+               if (MACHINE_IS_VM || MACHINE_IS_KVM ||
+                   !smp_vcpu_scheduled(~cpu))
+                       smp_yield_cpu(~cpu);
+       }
+}
+EXPORT_SYMBOL(arch_spin_relax);
+
+#endif /* CONFIG_S390_TICKET_SPINLOCK */
+
 int arch_spin_trylock_retry(arch_spinlock_t *lp)
 {
-       unsigned int cpu = ~smp_processor_id();
        int count;
 
        for (count = spin_retry; count > 0; count--) {
                if (arch_spin_is_locked(lp))
                        continue;
-               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+               if (arch_spin_trylock_once(lp))
                        return 1;
        }
        return 0;
 }
 EXPORT_SYMBOL(arch_spin_trylock_retry);
 
-void arch_spin_relax(arch_spinlock_t *lock)
-{
-       unsigned int cpu = lock->owner_cpu;
-       if (cpu != 0) {
-               if (MACHINE_IS_VM || MACHINE_IS_KVM ||
-                   !smp_vcpu_scheduled(~cpu))
-                       smp_yield_cpu(~cpu);
-       }
-}
-EXPORT_SYMBOL(arch_spin_relax);
-
 void _raw_read_lock_wait(arch_rwlock_t *rw)
 {
        unsigned int old;
@@ -124,7 +207,7 @@ void _raw_read_lock_wait(arch_rwlock_t *rw)
                if (!arch_read_can_lock(rw))
                        continue;
                old = rw->lock & 0x7fffffffU;
-               if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+               if (_raw_compare_and_swap(&rw->lock, old, old + 1))
                        return;
        }
 }
@@ -145,7 +228,7 @@ void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
                        continue;
                old = rw->lock & 0x7fffffffU;
                local_irq_disable();
-               if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+               if (_raw_compare_and_swap(&rw->lock, old, old + 1))
                        return;
        }
 }
@@ -160,7 +243,7 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw)
                if (!arch_read_can_lock(rw))
                        continue;
                old = rw->lock & 0x7fffffffU;
-               if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+               if (_raw_compare_and_swap(&rw->lock, old, old + 1))
                        return 1;
        }
        return 0;
@@ -178,7 +261,7 @@ void _raw_write_lock_wait(arch_rwlock_t *rw)
                }
                if (!arch_write_can_lock(rw))
                        continue;
-               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
                        return;
        }
 }
@@ -197,7 +280,7 @@ void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
                if (!arch_write_can_lock(rw))
                        continue;
                local_irq_disable();
-               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
                        return;
        }
 }
@@ -210,7 +293,7 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw)
        while (count-- > 0) {
                if (!arch_write_can_lock(rw))
                        continue;
-               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
                        return 1;
        }
        return 0;
index 7416efe8eae419c1249cf60c8f60dc268d1487cc..53dd5d7a0c964f4703562cefe915b0fb0317b554 100644 (file)
@@ -76,7 +76,7 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
 {
        unsigned long tmp1, tmp2;
 
-       update_primary_asce(current);
+       load_kernel_asce();
        tmp1 = -256UL;
        asm volatile(
                "   sacf  0\n"
@@ -159,7 +159,7 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
 {
        unsigned long tmp1, tmp2;
 
-       update_primary_asce(current);
+       load_kernel_asce();
        tmp1 = -256UL;
        asm volatile(
                "   sacf  0\n"
@@ -225,7 +225,7 @@ static inline unsigned long copy_in_user_mvc(void __user *to, const void __user
 {
        unsigned long tmp1;
 
-       update_primary_asce(current);
+       load_kernel_asce();
        asm volatile(
                "   sacf  256\n"
                "  "AHI"  %0,-1\n"
@@ -292,7 +292,7 @@ static inline unsigned long clear_user_xc(void __user *to, unsigned long size)
 {
        unsigned long tmp1, tmp2;
 
-       update_primary_asce(current);
+       load_kernel_asce();
        asm volatile(
                "   sacf  256\n"
                "  "AHI"  %0,-1\n"
@@ -358,7 +358,7 @@ unsigned long __strnlen_user(const char __user *src, unsigned long size)
 {
        if (unlikely(!size))
                return 0;
-       update_primary_asce(current);
+       load_kernel_asce();
        return strnlen_user_srst(src, size);
 }
 EXPORT_SYMBOL(__strnlen_user);
index 2f51a998a67e383b1ab50c0d08985109bd7e3e51..3f3b35403d0a4100bd0bd0bdee424f693ad93670 100644 (file)
@@ -415,7 +415,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
         * The instruction that caused the program check has
         * been nullified. Don't signal single step via SIGTRAP.
         */
-       clear_tsk_thread_flag(tsk, TIF_PER_TRAP);
+       clear_pt_regs_flag(regs, PIF_PER_TRAP);
 
        if (notify_page_fault(regs))
                return 0;
index cca388253a39f5636af7e10f0d416589abca59df..5535cfe0ee115fcfb48a3c7f27ce61c19a08b871 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/memblock.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <asm/ipl.h>
 #include <asm/sclp.h>
 #include <asm/setup.h>
 
 #define ADDR2G (1ULL << 31)
 
-static void find_memory_chunks(struct mem_chunk chunk[], unsigned long maxsize)
+#define CHUNK_READ_WRITE 0
+#define CHUNK_READ_ONLY  1
+
+static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size)
+{
+       memblock_add_range(&memblock.memory, start, size, 0, 0);
+       memblock_add_range(&memblock.physmem, start, size, 0, 0);
+}
+
+void __init detect_memory_memblock(void)
 {
        unsigned long long memsize, rnmax, rzm;
-       unsigned long addr = 0, size;
-       int i = 0, type;
+       unsigned long addr, size;
+       int type;
 
        rzm = sclp_get_rzm();
        rnmax = sclp_get_rnmax();
        memsize = rzm * rnmax;
        if (!rzm)
                rzm = 1ULL << 17;
-       if (sizeof(long) == 4) {
+       if (IS_ENABLED(CONFIG_32BIT)) {
                rzm = min(ADDR2G, rzm);
-               memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
+               memsize = min(ADDR2G, memsize);
        }
-       if (maxsize)
-               memsize = memsize ? min((unsigned long)memsize, maxsize) : maxsize;
+       max_physmem_end = memsize;
+       addr = 0;
+       /* keep memblock lists close to the kernel */
+       memblock_set_bottom_up(true);
        do {
                size = 0;
                type = tprot(addr);
                do {
                        size += rzm;
-                       if (memsize && addr + size >= memsize)
+                       if (max_physmem_end && addr + size >= max_physmem_end)
                                break;
                } while (type == tprot(addr + size));
                if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
-                       if (memsize && (addr + size > memsize))
-                               size = memsize - addr;
-                       chunk[i].addr = addr;
-                       chunk[i].size = size;
-                       chunk[i].type = type;
-                       i++;
+                       if (max_physmem_end && (addr + size > max_physmem_end))
+                               size = max_physmem_end - addr;
+                       memblock_physmem_add(addr, size);
                }
                addr += size;
-       } while (addr < memsize && i < MEMORY_CHUNKS);
-}
-
-/**
- * detect_memory_layout - fill mem_chunk array with memory layout data
- * @chunk: mem_chunk array to be filled
- * @maxsize: maximum address where memory detection should stop
- *
- * Fills the passed in memory chunk array with the memory layout of the
- * machine. The array must have a size of at least MEMORY_CHUNKS and will
- * be fully initialized afterwards.
- * If the maxsize paramater has a value > 0 memory detection will stop at
- * that address. It is guaranteed that all chunks have an ending address
- * that is smaller than maxsize.
- * If maxsize is 0 all memory will be detected.
- */
-void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize)
-{
-       unsigned long flags, flags_dat, cr0;
-
-       memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
-       /*
-        * Disable IRQs, DAT and low address protection so tprot does the
-        * right thing and we don't get scheduled away with low address
-        * protection disabled.
-        */
-       local_irq_save(flags);
-       flags_dat = __arch_local_irq_stnsm(0xfb);
-       /*
-        * In case DAT was enabled, make sure chunk doesn't reside in vmalloc
-        * space. We have disabled DAT and any access to vmalloc area will
-        * cause an exception.
-        * If DAT was disabled we are called from early ipl code.
-        */
-       if (test_bit(5, &flags_dat)) {
-               if (WARN_ON_ONCE(is_vmalloc_or_module_addr(chunk)))
-                       goto out;
-       }
-       __ctl_store(cr0, 0, 0);
-       __ctl_clear_bit(0, 28);
-       find_memory_chunks(chunk, maxsize);
-       __ctl_load(cr0, 0, 0);
-out:
-       __arch_local_irq_ssm(flags_dat);
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL(detect_memory_layout);
-
-/*
- * Create memory hole with given address and size.
- */
-void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
-                    unsigned long size)
-{
-       int i;
-
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               struct mem_chunk *chunk = &mem_chunk[i];
-
-               if (chunk->size == 0)
-                       continue;
-               if (addr > chunk->addr + chunk->size)
-                       continue;
-               if (addr + size <= chunk->addr)
-                       continue;
-               /* Split */
-               if ((addr > chunk->addr) &&
-                   (addr + size < chunk->addr + chunk->size)) {
-                       struct mem_chunk *new = chunk + 1;
-
-                       memmove(new, chunk, (MEMORY_CHUNKS-i-1) * sizeof(*new));
-                       new->addr = addr + size;
-                       new->size = chunk->addr + chunk->size - new->addr;
-                       chunk->size = addr - chunk->addr;
-                       continue;
-               } else if ((addr <= chunk->addr) &&
-                          (addr + size >= chunk->addr + chunk->size)) {
-                       memmove(chunk, chunk + 1, (MEMORY_CHUNKS-i-1) * sizeof(*chunk));
-                       memset(&mem_chunk[MEMORY_CHUNKS-1], 0, sizeof(*chunk));
-               } else if (addr + size < chunk->addr + chunk->size) {
-                       chunk->size =  chunk->addr + chunk->size - addr - size;
-                       chunk->addr = addr + size;
-               } else if (addr > chunk->addr) {
-                       chunk->size = addr - chunk->addr;
-               }
-       }
+       } while (addr < max_physmem_end);
+       memblock_set_bottom_up(false);
+       if (!max_physmem_end)
+               max_physmem_end = memblock_end_of_DRAM();
 }
index 27c50f4d90cb32ce97db6004ce450096b807655c..a90d45e9dfb0cbb7b1dce5fb8441a249dc0556c3 100644 (file)
@@ -12,8 +12,6 @@
 #include <linux/mm.h>
 #include <linux/gfp.h>
 #include <linux/init.h>
-#include <asm/setup.h>
-#include <asm/ipl.h>
 
 #define ESSA_SET_STABLE                1
 #define ESSA_SET_UNUSED                2
@@ -43,14 +41,6 @@ void __init cmma_init(void)
 
        if (!cmma_flag)
                return;
-       /*
-        * Disable CMM for dump, otherwise  the tprot based memory
-        * detection can fail because of unstable pages.
-        */
-       if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) {
-               cmma_flag = 0;
-               return;
-       }
        asm volatile(
                "       .insn rrf,0xb9ab0000,%1,%1,0,0\n"
                "0:     la      %0,0\n"
index d7cfd57815fbe484283819a98745f7e26e6d1d47..7881d4eb8b6bdf0891a89fa94b67bfebaab0a875 100644 (file)
@@ -53,8 +53,10 @@ static void __crst_table_upgrade(void *arg)
 {
        struct mm_struct *mm = arg;
 
-       if (current->active_mm == mm)
-               update_user_asce(mm, 1);
+       if (current->active_mm == mm) {
+               clear_user_asce();
+               set_user_asce(mm);
+       }
        __tlb_flush_local();
 }
 
@@ -108,7 +110,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
        pgd_t *pgd;
 
        if (current->active_mm == mm) {
-               clear_user_asce(mm, 1);
+               clear_user_asce();
                __tlb_flush_mm(mm);
        }
        while (mm->context.asce_limit > limit) {
@@ -134,7 +136,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
                crst_table_free(mm, (unsigned long *) pgd);
        }
        if (current->active_mm == mm)
-               update_user_asce(mm, 1);
+               set_user_asce(mm);
 }
 #endif
 
index 72b04de182838f0e7e1dcc5315b9c9b4260778d6..fe9012a49aa5abf0454bf4fa8f7d421c676ded26 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/list.h>
 #include <linux/hugetlb.h>
 #include <linux/slab.h>
+#include <linux/memblock.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
@@ -66,7 +67,8 @@ static pte_t __ref *vmem_pte_alloc(unsigned long address)
        if (slab_is_available())
                pte = (pte_t *) page_table_alloc(&init_mm, address);
        else
-               pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t));
+               pte = alloc_bootmem_align(PTRS_PER_PTE * sizeof(pte_t),
+                                         PTRS_PER_PTE * sizeof(pte_t));
        if (!pte)
                return NULL;
        clear_table((unsigned long *) pte, _PAGE_INVALID,
@@ -371,16 +373,14 @@ out:
 void __init vmem_map_init(void)
 {
        unsigned long ro_start, ro_end;
-       unsigned long start, end;
-       int i;
+       struct memblock_region *reg;
+       phys_addr_t start, end;
 
        ro_start = PFN_ALIGN((unsigned long)&_stext);
        ro_end = (unsigned long)&_eshared & PAGE_MASK;
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               if (!memory_chunk[i].size)
-                       continue;
-               start = memory_chunk[i].addr;
-               end = memory_chunk[i].addr + memory_chunk[i].size;
+       for_each_memblock(memory, reg) {
+               start = reg->base;
+               end = reg->base + reg->size - 1;
                if (start >= ro_end || end <= ro_start)
                        vmem_add_mem(start, end - start, 0);
                else if (start >= ro_start && end <= ro_end)
@@ -400,23 +400,21 @@ void __init vmem_map_init(void)
 }
 
 /*
- * Convert memory chunk array to a memory segment list so there is a single
- * list that contains both r/w memory and shared memory segments.
+ * Convert memblock.memory  to a memory segment list so there is a single
+ * list that contains all memory segments.
  */
 static int __init vmem_convert_memory_chunk(void)
 {
+       struct memblock_region *reg;
        struct memory_segment *seg;
-       int i;
 
        mutex_lock(&vmem_mutex);
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               if (!memory_chunk[i].size)
-                       continue;
+       for_each_memblock(memory, reg) {
                seg = kzalloc(sizeof(*seg), GFP_KERNEL);
                if (!seg)
                        panic("Out of memory...\n");
-               seg->start = memory_chunk[i].addr;
-               seg->size = memory_chunk[i].size;
+               seg->start = reg->base;
+               seg->size = reg->size;
                insert_memory_segment(seg);
        }
        mutex_unlock(&vmem_mutex);
index 9c36dc398f9070afb4d6151d214623d1cbcf9f4a..452d3ebd9d0fba3b513a6978b096bd22b27c1b46 100644 (file)
@@ -276,7 +276,6 @@ static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
        case BPF_S_LD_W_IND:
        case BPF_S_LD_H_IND:
        case BPF_S_LD_B_IND:
-       case BPF_S_LDX_B_MSH:
        case BPF_S_LD_IMM:
        case BPF_S_LD_MEM:
        case BPF_S_MISC_TXA:
index 1df1d29ac81d3710caafad1f7ce0094f530d721d..bdf02570d1dfab0c81146b4b609cbe45c9b445d7 100644 (file)
@@ -530,11 +530,6 @@ static void zpci_unmap_resources(struct zpci_dev *zdev)
        }
 }
 
-int pcibios_add_platform_entries(struct pci_dev *pdev)
-{
-       return zpci_sysfs_add_device(&pdev->dev);
-}
-
 static int __init zpci_irq_init(void)
 {
        int rc;
@@ -671,6 +666,7 @@ int pcibios_add_device(struct pci_dev *pdev)
        int i;
 
        zdev->pdev = pdev;
+       pdev->dev.groups = zpci_attr_groups;
        zpci_map_resources(zdev);
 
        for (i = 0; i < PCI_BAR_COUNT; i++) {
index c747394029eec181dbe521775296c701e9054a62..96545d7659fd0d30060a96a7dbb5e2e368aa9eba 100644 (file)
@@ -114,6 +114,16 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev,
        zdev->end_dma = response->edma;
        zdev->pchid = response->pchid;
        zdev->pfgid = response->pfgid;
+       zdev->pft = response->pft;
+       zdev->vfn = response->vfn;
+       zdev->uid = response->uid;
+
+       memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip));
+       if (response->util_str_avail) {
+               memcpy(zdev->util_str, response->util_str,
+                      sizeof(zdev->util_str));
+       }
+
        return 0;
 }
 
index 01e251b1da0cb82c6ecc263fcd5474c19c34d28d..6d7f5a3016ca170b134dd9c5e3e40be8d9f4b2bc 100644 (file)
@@ -76,7 +76,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 
        switch (ccdf->pec) {
        case 0x0301: /* Standby -> Configured */
-               if (!zdev || zdev->state == ZPCI_FN_STATE_CONFIGURED)
+               if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY)
                        break;
                zdev->state = ZPCI_FN_STATE_CONFIGURED;
                zdev->fh = ccdf->fh;
@@ -86,7 +86,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                pci_rescan_bus(zdev->bus);
                break;
        case 0x0302: /* Reserved -> Standby */
-               clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
+               if (!zdev)
+                       clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
                break;
        case 0x0303: /* Deconfiguration requested */
                if (pdev)
index ab4a91393005a920b876c610ed5d3d8605af5037..9190214b8702f95230d3b7b982eb18e5a325c423 100644 (file)
 #include <linux/stat.h>
 #include <linux/pci.h>
 
-static ssize_t show_fid(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
-
-       return sprintf(buf, "0x%08x\n", zdev->fid);
-}
-static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL);
-
-static ssize_t show_fh(struct device *dev, struct device_attribute *attr,
-                      char *buf)
-{
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
-
-       return sprintf(buf, "0x%08x\n", zdev->fh);
-}
-static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL);
-
-static ssize_t show_pchid(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
-
-       return sprintf(buf, "0x%04x\n", zdev->pchid);
-}
-static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL);
-
-static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
-
-       return sprintf(buf, "0x%02x\n", zdev->pfgid);
-}
-static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL);
-
-static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
+#define zpci_attr(name, fmt, member)                                   \
+static ssize_t name##_show(struct device *dev,                         \
+                          struct device_attribute *attr, char *buf)    \
+{                                                                      \
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));              \
+                                                                       \
+       return sprintf(buf, fmt, zdev->member);                         \
+}                                                                      \
+static DEVICE_ATTR_RO(name)
+
+zpci_attr(function_id, "0x%08x\n", fid);
+zpci_attr(function_handle, "0x%08x\n", fh);
+zpci_attr(pchid, "0x%04x\n", pchid);
+zpci_attr(pfgid, "0x%02x\n", pfgid);
+zpci_attr(vfn, "0x%04x\n", vfn);
+zpci_attr(pft, "0x%02x\n", pft);
+zpci_attr(uid, "0x%x\n", uid);
+zpci_attr(segment0, "0x%02x\n", pfip[0]);
+zpci_attr(segment1, "0x%02x\n", pfip[1]);
+zpci_attr(segment2, "0x%02x\n", pfip[2]);
+zpci_attr(segment3, "0x%02x\n", pfip[3]);
+
+static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -70,38 +56,55 @@ static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
        pci_rescan_bus(zdev->bus);
        return count;
 }
-static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover);
+static DEVICE_ATTR_WO(recover);
 
-static struct device_attribute *zpci_dev_attrs[] = {
-       &dev_attr_function_id,
-       &dev_attr_function_handle,
-       &dev_attr_pchid,
-       &dev_attr_pfgid,
-       &dev_attr_recover,
-       NULL,
-};
-
-int zpci_sysfs_add_device(struct device *dev)
+static ssize_t util_string_read(struct file *filp, struct kobject *kobj,
+                               struct bin_attribute *attr, char *buf,
+                               loff_t off, size_t count)
 {
-       int i, rc = 0;
-
-       for (i = 0; zpci_dev_attrs[i]; i++) {
-               rc = device_create_file(dev, zpci_dev_attrs[i]);
-               if (rc)
-                       goto error;
-       }
-       return 0;
+       struct device *dev = kobj_to_dev(kobj);
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
 
-error:
-       while (--i >= 0)
-               device_remove_file(dev, zpci_dev_attrs[i]);
-       return rc;
+       return memory_read_from_buffer(buf, count, &off, zdev->util_str,
+                                      sizeof(zdev->util_str));
 }
+static BIN_ATTR_RO(util_string, CLP_UTIL_STR_LEN);
+static struct bin_attribute *zpci_bin_attrs[] = {
+       &bin_attr_util_string,
+       NULL,
+};
 
-void zpci_sysfs_remove_device(struct device *dev)
-{
-       int i;
+static struct attribute *zpci_dev_attrs[] = {
+       &dev_attr_function_id.attr,
+       &dev_attr_function_handle.attr,
+       &dev_attr_pchid.attr,
+       &dev_attr_pfgid.attr,
+       &dev_attr_pft.attr,
+       &dev_attr_vfn.attr,
+       &dev_attr_uid.attr,
+       &dev_attr_recover.attr,
+       NULL,
+};
+static struct attribute_group zpci_attr_group = {
+       .attrs = zpci_dev_attrs,
+       .bin_attrs = zpci_bin_attrs,
+};
 
-       for (i = 0; zpci_dev_attrs[i]; i++)
-               device_remove_file(dev, zpci_dev_attrs[i]);
-}
+static struct attribute *pfip_attrs[] = {
+       &dev_attr_segment0.attr,
+       &dev_attr_segment1.attr,
+       &dev_attr_segment2.attr,
+       &dev_attr_segment3.attr,
+       NULL,
+};
+static struct attribute_group pfip_attr_group = {
+       .name = "pfip",
+       .attrs = pfip_attrs,
+};
+
+const struct attribute_group *zpci_attr_groups[] = {
+       &zpci_attr_group,
+       &pfip_attr_group,
+       NULL,
+};
index 13dc67f03011eae7624c26957cf4f6a5085a4c34..3e09a07b77e9132adb3dbcdc906270453df0f3dd 100644 (file)
@@ -1,5 +1,12 @@
 #ifndef ___ASM_SPARC_AUXIO_H
 #define ___ASM_SPARC_AUXIO_H
+
+#ifndef __ASSEMBLY__
+
+extern void __iomem *auxio_register;
+
+#endif /* ifndef __ASSEMBLY__ */
+
 #if defined(__sparc__) && defined(__arch64__)
 #include <asm/auxio_64.h>
 #else
index f61cd1e3e3957c18ae12129b41e353060cac9f89..7af9766a1c35d46aa887fc9742b0c39f33ae76b3 100644 (file)
@@ -75,8 +75,6 @@
 
 #ifndef __ASSEMBLY__
 
-extern void __iomem *auxio_register;
-
 #define AUXIO_LTE_ON   1
 #define AUXIO_LTE_OFF  0
 
index 6bd9f43cb5a5471bccb1aee3cb14dcf89d2b76b7..a24cbb16d0eb90b8a8f9c7520c6fbb964fe0e9a4 100644 (file)
@@ -20,6 +20,6 @@ extern void do_BUG(const char *file, int line);
 #include <asm-generic/bug.h>
 
 struct pt_regs;
-extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+void __noreturn die_if_kernel(char *str, struct pt_regs *regs);
 
 #endif
index bdbda1453aa9f168339896d6880e3e2acd44182f..04471dc64847269e815a26752ef029cd9206c154 100644 (file)
@@ -238,4 +238,16 @@ static inline __sum16 ip_compute_csum(const void *buff, int len)
        return csum_fold(csum_partial(buff, len, 0));
 }
 
+#define HAVE_ARCH_CSUM_ADD
+static inline __wsum csum_add(__wsum csum, __wsum addend)
+{
+       __asm__ __volatile__(
+               "addcc   %0, %1, %0\n"
+               "addx    %0, %%g0, %0"
+               : "=r" (csum)
+               : "r" (addend), "0" (csum));
+
+       return csum;
+}
+
 #endif /* !(__SPARC_CHECKSUM_H) */
index 019b9615e43c16b81230508109b2484d6313ee62..2ff81ae8f3afa17b0fd25a5a6786131a9e30bc1b 100644 (file)
@@ -164,4 +164,16 @@ static inline __sum16 ip_compute_csum(const void *buff, int len)
        return csum_fold(csum_partial(buff, len, 0));
 }
 
+#define HAVE_ARCH_CSUM_ADD
+static inline __wsum csum_add(__wsum csum, __wsum addend)
+{
+       __asm__ __volatile__(
+               "addcc   %0, %1, %0\n"
+               "addx    %0, %%g0, %0"
+               : "=r" (csum)
+               : "r" (addend), "0" (csum));
+
+       return csum;
+}
+
 #endif /* !(__SPARC64_CHECKSUM_H) */
index b5976de7cacdb32528f576eef418ce4d35685e4e..128b56b08676058700c4b9ee07752b1fa811d197 100644 (file)
@@ -1,5 +1,15 @@
 #ifndef ___ASM_SPARC_CPUDATA_H
 #define ___ASM_SPARC_CPUDATA_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/threads.h>
+#include <linux/percpu.h>
+
+extern const struct seq_operations cpuinfo_op;
+
+#endif /* !(__ASSEMBLY__) */
+
 #if defined(__sparc__) && defined(__arch64__)
 #include <asm/cpudata_64.h>
 #else
index 050ef35b9dcf5224ead325d70a9274f9209ddc84..0e594076912c07f5d5a3114ec87ec14429436288 100644 (file)
@@ -8,9 +8,6 @@
 
 #ifndef __ASSEMBLY__
 
-#include <linux/percpu.h>
-#include <linux/threads.h>
-
 typedef struct {
        /* Dcache line 1 */
        unsigned int    __softirq_pending; /* must be 1st, see rtrap.S */
@@ -35,8 +32,6 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
 #define cpu_data(__cpu)                per_cpu(__cpu_data, (__cpu))
 #define local_cpu_data()       __get_cpu_var(__cpu_data)
 
-extern const struct seq_operations cpuinfo_op;
-
 #endif /* !(__ASSEMBLY__) */
 
 #include <asm/trap_block.h>
index fb3f16954c6946ee8e83b5320ce17f1a3f2ba907..a8af6f00d76da4d1b3bb9b610c4018fc598722de 100644 (file)
@@ -9,11 +9,12 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/idprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
+#include <asm/setup.h>
+#include <asm/page.h>
 #include <asm/irq.h>
 
 /* We don't need no stinkin' I/O port allocation crap. */
@@ -49,7 +50,6 @@ struct sun_flpy_controller {
 
 /* You'll only ever find one controller on a SparcStation anyways. */
 static struct sun_flpy_controller *sun_fdc = NULL;
-extern volatile unsigned char *fdc_status;
 
 struct sun_floppy_ops {
        unsigned char (*fd_inb)(int port);
@@ -212,13 +212,6 @@ static void sun_82077_fd_outb(unsigned char value, int port)
  * underruns.  If non-zero, doing_pdma encodes the direction of
  * the transfer for debugging.  1=read 2=write
  */
-extern char *pdma_vaddr;
-extern unsigned long pdma_size;
-extern volatile int doing_pdma;
-
-/* This is software state */
-extern char *pdma_base;
-extern unsigned long pdma_areasize;
 
 /* Common routines to all controller types on the Sparc. */
 static inline void virtual_dma_init(void)
index c1acbd891cbcce02c1ff1f54d4add3f690a3fb15..383f513be66ac2f55a44365fafd0d2137d39e8ca 100644 (file)
 #define __SPARC_IO_H
 
 #include <linux/kernel.h>
-#include <linux/types.h>
 #include <linux/ioport.h>  /* struct resource */
 
-#include <asm/page.h>      /* IO address mapping routines need this */
-#include <asm-generic/pci_iomap.h>
-
-#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
-
-static inline u32 flip_dword (u32 l)
-{
-       return ((l&0xff)<<24) | (((l>>8)&0xff)<<16) | (((l>>16)&0xff)<<8)| ((l>>24)&0xff);
-}
-
-static inline u16 flip_word (u16 w)
-{
-       return ((w&0xff) << 8) | ((w>>8)&0xff);
-}
-
-#define mmiowb()
-
-/*
- * Memory mapped I/O to PCI
- */
-
-static inline u8 __raw_readb(const volatile void __iomem *addr)
-{
-       return *(__force volatile u8 *)addr;
-}
-
-static inline u16 __raw_readw(const volatile void __iomem *addr)
-{
-       return *(__force volatile u16 *)addr;
-}
-
-static inline u32 __raw_readl(const volatile void __iomem *addr)
-{
-       return *(__force volatile u32 *)addr;
-}
+#define readb_relaxed(__addr)  readb(__addr)
+#define readw_relaxed(__addr)  readw(__addr)
+#define readl_relaxed(__addr)  readl(__addr)
 
-static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
-{
-       *(__force volatile u8 *)addr = b;
-}
+#define IO_SPACE_LIMIT 0xffffffff
 
-static inline void __raw_writew(u16 w, volatile void __iomem *addr)
-{
-       *(__force volatile u16 *)addr = w;
-}
+#define memset_io(d,c,sz)     _memset_io(d,c,sz)
+#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz)
+#define memcpy_toio(d,s,sz)   _memcpy_toio(d,s,sz)
 
-static inline void __raw_writel(u32 l, volatile void __iomem *addr)
-{
-       *(__force volatile u32 *)addr = l;
-}
+#include <asm-generic/io.h>
 
-static inline u8 __readb(const volatile void __iomem *addr)
+static inline void _memset_io(volatile void __iomem *dst,
+                              int c, __kernel_size_t n)
 {
-       return *(__force volatile u8 *)addr;
-}
+       volatile void __iomem *d = dst;
 
-static inline u16 __readw(const volatile void __iomem *addr)
-{
-       return flip_word(*(__force volatile u16 *)addr);
+       while (n--) {
+               writeb(c, d);
+               d++;
+       }
 }
 
-static inline u32 __readl(const volatile void __iomem *addr)
+static inline void _memcpy_fromio(void *dst, const volatile void __iomem *src,
+                                  __kernel_size_t n)
 {
-       return flip_dword(*(__force volatile u32 *)addr);
-}
+       char *d = dst;
 
-static inline void __writeb(u8 b, volatile void __iomem *addr)
-{
-       *(__force volatile u8 *)addr = b;
+       while (n--) {
+               char tmp = readb(src);
+               *d++ = tmp;
+               src++;
+       }
 }
 
-static inline void __writew(u16 w, volatile void __iomem *addr)
+static inline void _memcpy_toio(volatile void __iomem *dst, const void *src,
+                                __kernel_size_t n)
 {
-       *(__force volatile u16 *)addr = flip_word(w);
-}
+       const char *s = src;
+       volatile void __iomem *d = dst;
 
-static inline void __writel(u32 l, volatile void __iomem *addr)
-{
-       *(__force volatile u32 *)addr = flip_dword(l);
+       while (n--) {
+               char tmp = *s++;
+               writeb(tmp, d);
+               d++;
+       }
 }
 
-#define readb(__addr)          __readb(__addr)
-#define readw(__addr)          __readw(__addr)
-#define readl(__addr)          __readl(__addr)
-#define readb_relaxed(__addr)  readb(__addr)
-#define readw_relaxed(__addr)  readw(__addr)
-#define readl_relaxed(__addr)  readl(__addr)
-
-#define writeb(__b, __addr)    __writeb((__b),(__addr))
-#define writew(__w, __addr)    __writew((__w),(__addr))
-#define writel(__l, __addr)    __writel((__l),(__addr))
-
-/*
- * I/O space operations
- *
- * Arrangement on a Sun is somewhat complicated.
- *
- * First of all, we want to use standard Linux drivers
- * for keyboard, PC serial, etc. These drivers think
- * they access I/O space and use inb/outb.
- * On the other hand, EBus bridge accepts PCI *memory*
- * cycles and converts them into ISA *I/O* cycles.
- * Ergo, we want inb & outb to generate PCI memory cycles.
- *
- * If we want to issue PCI *I/O* cycles, we do this
- * with a low 64K fixed window in PCIC. This window gets
- * mapped somewhere into virtual kernel space and we
- * can use inb/outb again.
- */
-#define inb_local(__addr)      __readb((void __iomem *)(unsigned long)(__addr))
-#define inb(__addr)            __readb((void __iomem *)(unsigned long)(__addr))
-#define inw(__addr)            __readw((void __iomem *)(unsigned long)(__addr))
-#define inl(__addr)            __readl((void __iomem *)(unsigned long)(__addr))
-
-#define outb_local(__b, __addr)        __writeb(__b, (void __iomem *)(unsigned long)(__addr))
-#define outb(__b, __addr)      __writeb(__b, (void __iomem *)(unsigned long)(__addr))
-#define outw(__w, __addr)      __writew(__w, (void __iomem *)(unsigned long)(__addr))
-#define outl(__l, __addr)      __writel(__l, (void __iomem *)(unsigned long)(__addr))
-
-#define inb_p(__addr)          inb(__addr)
-#define outb_p(__b, __addr)    outb(__b, __addr)
-#define inw_p(__addr)          inw(__addr)
-#define outw_p(__w, __addr)    outw(__w, __addr)
-#define inl_p(__addr)          inl(__addr)
-#define outl_p(__l, __addr)    outl(__l, __addr)
-
-void outsb(unsigned long addr, const void *src, unsigned long cnt);
-void outsw(unsigned long addr, const void *src, unsigned long cnt);
-void outsl(unsigned long addr, const void *src, unsigned long cnt);
-void insb(unsigned long addr, void *dst, unsigned long count);
-void insw(unsigned long addr, void *dst, unsigned long count);
-void insl(unsigned long addr, void *dst, unsigned long count);
-
-#define IO_SPACE_LIMIT 0xffffffff
-
 /*
  * SBus accessors.
  *
  * SBus has only one, memory mapped, I/O space.
  * We do not need to flip bytes for SBus of course.
  */
-static inline u8 _sbus_readb(const volatile void __iomem *addr)
+static inline u8 sbus_readb(const volatile void __iomem *addr)
 {
        return *(__force volatile u8 *)addr;
 }
 
-static inline u16 _sbus_readw(const volatile void __iomem *addr)
+static inline u16 sbus_readw(const volatile void __iomem *addr)
 {
        return *(__force volatile u16 *)addr;
 }
 
-static inline u32 _sbus_readl(const volatile void __iomem *addr)
+static inline u32 sbus_readl(const volatile void __iomem *addr)
 {
        return *(__force volatile u32 *)addr;
 }
 
-static inline void _sbus_writeb(u8 b, volatile void __iomem *addr)
+static inline void sbus_writeb(u8 b, volatile void __iomem *addr)
 {
        *(__force volatile u8 *)addr = b;
 }
 
-static inline void _sbus_writew(u16 w, volatile void __iomem *addr)
+static inline void sbus_writew(u16 w, volatile void __iomem *addr)
 {
        *(__force volatile u16 *)addr = w;
 }
 
-static inline void _sbus_writel(u32 l, volatile void __iomem *addr)
+static inline void sbus_writel(u32 l, volatile void __iomem *addr)
 {
        *(__force volatile u32 *)addr = l;
 }
 
-/*
- * The only reason for #define's is to hide casts to unsigned long.
- */
-#define sbus_readb(__addr)             _sbus_readb(__addr)
-#define sbus_readw(__addr)             _sbus_readw(__addr)
-#define sbus_readl(__addr)             _sbus_readl(__addr)
-#define sbus_writeb(__b, __addr)       _sbus_writeb(__b, __addr)
-#define sbus_writew(__w, __addr)       _sbus_writew(__w, __addr)
-#define sbus_writel(__l, __addr)       _sbus_writel(__l, __addr)
-
-static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_size_t n)
+static inline void sbus_memset_io(volatile void __iomem *__dst, int c,
+                                  __kernel_size_t n)
 {
        while(n--) {
                sbus_writeb(c, __dst);
@@ -194,22 +97,9 @@ static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_
        }
 }
 
-static inline void
-_memset_io(volatile void __iomem *dst, int c, __kernel_size_t n)
-{
-       volatile void __iomem *d = dst;
-
-       while (n--) {
-               writeb(c, d);
-               d++;
-       }
-}
-
-#define memset_io(d,c,sz)      _memset_io(d,c,sz)
-
-static inline void
-_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src,
-                   __kernel_size_t n)
+static inline void sbus_memcpy_fromio(void *dst,
+                                      const volatile void __iomem *src,
+                                      __kernel_size_t n)
 {
        char *d = dst;
 
@@ -220,25 +110,9 @@ _sbus_memcpy_fromio(void *dst, const volatile void __iomem *src,
        }
 }
 
-#define sbus_memcpy_fromio(d, s, sz)   _sbus_memcpy_fromio(d, s, sz)
-
-static inline void
-_memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
-{
-       char *d = dst;
-
-       while (n--) {
-               char tmp = readb(src);
-               *d++ = tmp;
-               src++;
-       }
-}
-
-#define memcpy_fromio(d,s,sz)  _memcpy_fromio(d,s,sz)
-
-static inline void
-_sbus_memcpy_toio(volatile void __iomem *dst, const void *src,
-                 __kernel_size_t n)
+static inline void sbus_memcpy_toio(volatile void __iomem *dst,
+                                    const void *src,
+                                    __kernel_size_t n)
 {
        const char *s = src;
        volatile void __iomem *d = dst;
@@ -250,23 +124,6 @@ _sbus_memcpy_toio(volatile void __iomem *dst, const void *src,
        }
 }
 
-#define sbus_memcpy_toio(d, s, sz)     _sbus_memcpy_toio(d, s, sz)
-
-static inline void
-_memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
-{
-       const char *s = src;
-       volatile void __iomem *d = dst;
-
-       while (n--) {
-               char tmp = *s++;
-               writeb(tmp, d);
-               d++;
-       }
-}
-
-#define memcpy_toio(d,s,sz)    _memcpy_toio(d,s,sz)
-
 #ifdef __KERNEL__
 
 /*
@@ -278,46 +135,6 @@ extern void __iomem *ioremap(unsigned long offset, unsigned long size);
 #define ioremap_wc(X,Y)                ioremap((X),(Y))
 extern void iounmap(volatile void __iomem *addr);
 
-#define ioread8(X)                     readb(X)
-#define ioread16(X)                    readw(X)
-#define ioread16be(X)                  __raw_readw(X)
-#define ioread32(X)                    readl(X)
-#define ioread32be(X)                  __raw_readl(X)
-#define iowrite8(val,X)                        writeb(val,X)
-#define iowrite16(val,X)               writew(val,X)
-#define iowrite16be(val,X)             __raw_writew(val,X)
-#define iowrite32(val,X)               writel(val,X)
-#define iowrite32be(val,X)             __raw_writel(val,X)
-
-static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
-{
-       insb((unsigned long __force)port, buf, count);
-}
-static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
-{
-       insw((unsigned long __force)port, buf, count);
-}
-
-static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
-{
-       insl((unsigned long __force)port, buf, count);
-}
-
-static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
-{
-       outsb((unsigned long __force)port, buf, count);
-}
-
-static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
-{
-       outsw((unsigned long __force)port, buf, count);
-}
-
-static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
-{
-       outsl((unsigned long __force)port, buf, count);
-}
-
 /* Create a virtual mapping cookie for an IO port range */
 extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
 extern void ioport_unmap(void __iomem *);
@@ -326,6 +143,8 @@ extern void ioport_unmap(void __iomem *);
 struct pci_dev;
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
+
+
 /*
  * At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
  * so rtc_port is static in it. This should not change unless a new
@@ -349,15 +168,5 @@ extern void sbus_set_sbus64(struct device *, int);
 
 #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED         1
 
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)   __va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p)  p
 
 #endif /* !(__SPARC_IO_H) */
index 09b0b88aeb2a422d5674b546768f36d413efc6c0..44845632e983b4ccd3e99350d9363d1fc0e87b79 100644 (file)
@@ -15,7 +15,6 @@
 
 /* BIO layer definitions. */
 extern unsigned long kern_base, kern_size;
-#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 
 static inline u8 _inb(unsigned long addr)
 {
index 2ae3acaeb1b31980d0fa0247de7de7912f4e5389..9277e519468daab7ce55421d8b58adb29257d961 100644 (file)
@@ -17,6 +17,7 @@
 #define irq_canonicalize(irq)  (irq)
 
 extern void __init init_IRQ(void);
+void __init sun4d_init_sbi_irq(void);
 
 #define NO_IRQ         0xffffffff
 
index f21de034902596744ed071a80b0a53147b04460e..1be2fdec626896715402512ca00e8ae1f84085c3 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef ___ASM_SPARC_PAGE_H
 #define ___ASM_SPARC_PAGE_H
+
+#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
+
 #if defined(__sparc__) && defined(__arch64__)
 #include <asm/page_64.h>
 #else
index 9b1c36de0f183f8c91778e6a22ca431fb43dabe5..a3890da9442892e886f55f42ff9d223f75583262 100644 (file)
@@ -14,6 +14,8 @@ struct page;
 void *srmmu_get_nocache(int size, int align);
 void srmmu_free_nocache(void *addr, int size);
 
+extern struct resource sparc_iomap;
+
 #define check_pgt_cache()      do { } while (0)
 
 pgd_t *get_pgd_fast(void);
index 502f632f6cc73e826ded589a87c70e7e80b6d514..16629e7cb09e67f1abb3543df5246f8f4382fb9a 100644 (file)
@@ -27,6 +27,7 @@ struct page;
 
 extern void load_mmu(void);
 extern unsigned long calc_highpages(void);
+unsigned long __init bootmem_init(unsigned long *pages_avail);
 
 #define pte_ERROR(e)   __builtin_trap()
 #define pmd_ERROR(e)   __builtin_trap()
index 5e35e051731887c3e284b2b7e92c254365ac36be..fb54505e008ec22f543e2c6e08355e1d42f8daee 100644 (file)
@@ -4,8 +4,9 @@
 #ifndef _SPARC_SETUP_H
 #define _SPARC_SETUP_H
 
-#include <uapi/asm/setup.h>
+#include <linux/interrupt.h>
 
+#include <uapi/asm/setup.h>
 
 extern char reboot_command[];
 
@@ -22,6 +23,28 @@ static inline int con_is_present(void)
 {
        return serial_console ? 0 : 1;
 }
+
+/* from irq_32.c */
+extern volatile unsigned char *fdc_status;
+extern char *pdma_vaddr;
+extern unsigned long pdma_size;
+extern volatile int doing_pdma;
+
+/* This is software state */
+extern char *pdma_base;
+extern unsigned long pdma_areasize;
+
+int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler);
+
+/* setup_32.c */
+extern unsigned long cmdline_memory_size;
+
+/* devices.c */
+void __init device_scan(void);
+
+/* unaligned_32.c */
+unsigned long safe_compute_effective_address(struct pt_regs *, unsigned int);
+
 #endif
 
 extern void sun_do_break(void);
index 72f40a546de35e73086f7ecb270cd27fdf7f6b7a..93476f8d7fea423a8bedb28f34cba1d9bb0c9cf7 100644 (file)
@@ -32,7 +32,7 @@ static inline unsigned int timer_value(unsigned int value)
        return (value + 1) << TIMER_VALUE_SHIFT;
 }
 
-extern __volatile__ unsigned int *master_l10_counter;
+extern volatile unsigned int __iomem *master_l10_counter;
 
 extern irqreturn_t notrace timer_interrupt(int dummy, void *dev_id);
 
index e20cc55fb768f3eab1de428cb7e03930b0adf4b0..c6fc1d451407ce1abf022128b0bcd71735a2ffc9 100644 (file)
@@ -9,12 +9,15 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/export.h>
+
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
 #include <asm/string.h>                /* memset(), Linux has no bzero() */
 #include <asm/cpu_type.h>
 
+#include "kernel.h"
+
 /* Probe and map in the Auxiliary I/O register */
 
 /* auxio_register is not static because it is referenced 
index 5c5125895db86e4dacd9de9dee91b508628b30c2..82a3a71c451e437248534d939834ae933dc2bdf4 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/cpudata.h>
 
 #include "kernel.h"
+#include "entry.h"
 
 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 EXPORT_PER_CPU_SYMBOL(__cpu_data);
index 3d465e87f7e247db101d757fff4abbfeac9b3719..6f39916dc6e8697149a7206721d21ec4b27c98ac 100644 (file)
@@ -19,8 +19,9 @@
 #include <asm/smp.h>
 #include <asm/cpudata.h>
 #include <asm/cpu_type.h>
+#include <asm/setup.h>
 
-extern void clock_stop_probe(void); /* tadpole.c */
+#include "kernel.h"
 
 static char *cpu_mid_prop(void)
 {
@@ -131,11 +132,7 @@ void __init device_scan(void)
        }
 #endif /* !CONFIG_SMP */
 
-       {
-               extern void auxio_probe(void);
-               extern void auxio_power_probe(void);
-               auxio_probe();
-               auxio_power_probe();
-       }
+       auxio_probe();
+       auxio_power_probe();
        clock_stop_probe();
 }
index e7e215dfa86668750c9490331d94b288ab78857c..7f08ec8a7c682338dec59ff51c15740ee59cdc45 100644 (file)
@@ -186,7 +186,7 @@ static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
 
        if (name == NULL) name = "???";
 
-       if ((xres = xres_alloc()) != 0) {
+       if ((xres = xres_alloc()) != NULL) {
                tack = xres->xname;
                res = &xres->xres;
        } else {
@@ -400,7 +400,7 @@ static void sbus_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
        BUG();
 }
 
-struct dma_map_ops sbus_dma_ops = {
+static struct dma_map_ops sbus_dma_ops = {
        .alloc                  = sbus_alloc_coherent,
        .free                   = sbus_free_coherent,
        .map_page               = sbus_map_page,
@@ -681,7 +681,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v)
        const char *nm;
 
        for (r = root->child; r != NULL; r = r->sibling) {
-               if ((nm = r->name) == 0) nm = "???";
+               if ((nm = r->name) == NULL) nm = "???";
                seq_printf(m, "%016llx-%016llx: %s\n",
                                (unsigned long long)r->start,
                                (unsigned long long)r->end, nm);
index b66b6aad1d6d7f1444b6e482a5ad89afce107473..7c7540a62362680c4e7bb0a9d7e752251c9ee804 100644 (file)
@@ -82,6 +82,15 @@ void handler_irq(unsigned int pil, struct pt_regs *regs);
 
 unsigned long leon_get_irqmask(unsigned int irq);
 
+/* irq_32.c */
+void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs);
+
+/* sun4m_irq.c */
+void sun4m_nmi(struct pt_regs *regs);
+
+/* sun4d_irq.c */
+void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs);
+
 #ifdef CONFIG_SMP
 
 /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
index c145f6fd123b88814c9d650e781dd391ea0e73f7..a979e99f8751cd60393c1ee18c0a958ceddb34cf 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/cpudata.h>
+#include <asm/setup.h>
 #include <asm/pcic.h>
 #include <asm/leon.h>
 
index a702d9ab019c23e13bfdaa681ebf40f625adb6c1..de9ac1aa25e83cdfc859d4c3f4b42631af780d00 100644 (file)
@@ -51,6 +51,11 @@ extern void sun4m_clear_profile_irq(int cpu);
 /* sun4m_smp.c */
 void sun4m_cpu_pre_starting(void *arg);
 void sun4m_cpu_pre_online(void *arg);
+void __init smp4m_boot_cpus(void);
+int smp4m_boot_one_cpu(int i, struct task_struct *idle);
+void __init smp4m_smp_done(void);
+void smp4m_cross_call_irq(void);
+void smp4m_percpu_timer_interrupt(struct pt_regs *regs);
 
 /* sun4d_irq.c */
 extern spinlock_t sun4d_imsk_lock;
@@ -67,10 +72,17 @@ extern void sun4d_free_irq(unsigned int irq, void *dev_id);
 /* sun4d_smp.c */
 void sun4d_cpu_pre_starting(void *arg);
 void sun4d_cpu_pre_online(void *arg);
+void __init smp4d_boot_cpus(void);
+int smp4d_boot_one_cpu(int i, struct task_struct *idle);
+void __init smp4d_smp_done(void);
+void smp4d_cross_call_irq(void);
+void smp4d_percpu_timer_interrupt(struct pt_regs *regs);
 
 /* leon_smp.c */
 void leon_cpu_pre_starting(void *arg);
 void leon_cpu_pre_online(void *arg);
+void leonsmp_ipi_interrupt(void);
+void leon_cross_call_irq(void);
 
 /* head_32.S */
 extern unsigned int t_nmi[];
@@ -95,6 +107,38 @@ extern void floppy_hardint(void);
 extern unsigned long sun4m_cpu_startup;
 extern unsigned long sun4d_cpu_startup;
 
+/* process_32.c */
+asmlinkage int sparc_do_fork(unsigned long clone_flags,
+                             unsigned long stack_start,
+                             struct pt_regs *regs,
+                             unsigned long stack_size);
+
+/* signal_32.c */
+asmlinkage void do_sigreturn(struct pt_regs *regs);
+asmlinkage void do_rt_sigreturn(struct pt_regs *regs);
+void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
+                      unsigned long thread_info_flags);
+asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr,
+                               struct sigstack __user *ossptr,
+                               unsigned long sp);
+
+/* ptrace_32.c */
+asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+
+/* unaligned_32.c */
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn);
+asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn);
+
+/* windows.c */
+void try_to_clear_window_buffer(struct pt_regs *regs, int who);
+
+/* tadpole.c */
+void __init clock_stop_probe(void);
+
+/* auxio_32.c */
+void __init auxio_probe(void);
+void __init auxio_power_probe(void);
+
 #else /* CONFIG_SPARC32 */
 #endif /* CONFIG_SPARC32 */
 #endif /* !(__SPARC_KERNEL_H) */
index b7c68976cbc7568360dfde49044f70a4aac9ffb7..d9397088893ac108fbb26b90409862693ce2958e 100644 (file)
@@ -32,12 +32,12 @@ struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base addr
 
 int leondebug_irq_disable;
 int leon_debug_irqout;
-static int dummy_master_l10_counter;
+static volatile unsigned int dummy_master_l10_counter;
 unsigned long amba_system_id;
 static DEFINE_SPINLOCK(leon_irq_lock);
 
+static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
 unsigned long leon3_gptimer_irq; /* interrupt controller irq number */
-unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
 unsigned int sparc_leon_eirq;
 #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
 #define LEON_IACK (&leon3_irqctrl_regs->iclear)
@@ -65,7 +65,7 @@ static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc)
 }
 
 /* The extended IRQ controller has been found, this function registers it */
-void leon_eirq_setup(unsigned int eirq)
+static void leon_eirq_setup(unsigned int eirq)
 {
        unsigned long mask, oldmask;
        unsigned int veirq;
@@ -270,7 +270,7 @@ static u32 leon_cycles_offset(void)
 #ifdef CONFIG_SMP
 
 /* smp clockevent irq */
-irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
+static irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
 {
        struct clock_event_device *ce;
        int cpu = smp_processor_id();
@@ -313,7 +313,8 @@ void __init leon_init_timers(void)
 
        leondebug_irq_disable = 0;
        leon_debug_irqout = 0;
-       master_l10_counter = (unsigned int *)&dummy_master_l10_counter;
+       master_l10_counter =
+               (unsigned int __iomem *)&dummy_master_l10_counter;
        dummy_master_l10_counter = 0;
 
        rootnp = of_find_node_by_path("/ambapp0");
index e16c4157e1ae1a504c754838caf499404894a6ce..899b7203a4e4a27545b1dc6a41728015dab33e5a 100644 (file)
@@ -98,82 +98,3 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 {
        return res->start;
 }
-
-/* in/out routines taken from pcic.c
- *
- * This probably belongs here rather than ioport.c because
- * we do not want this crud linked into SBus kernels.
- * Also, think for a moment about likes of floppy.c that
- * include architecture specific parts. They may want to redefine ins/outs.
- *
- * We do not use horrible macros here because we want to
- * advance pointer by sizeof(size).
- */
-void outsb(unsigned long addr, const void *src, unsigned long count)
-{
-       while (count) {
-               count -= 1;
-               outb(*(const char *)src, addr);
-               src += 1;
-               /* addr += 1; */
-       }
-}
-EXPORT_SYMBOL(outsb);
-
-void outsw(unsigned long addr, const void *src, unsigned long count)
-{
-       while (count) {
-               count -= 2;
-               outw(*(const short *)src, addr);
-               src += 2;
-               /* addr += 2; */
-       }
-}
-EXPORT_SYMBOL(outsw);
-
-void outsl(unsigned long addr, const void *src, unsigned long count)
-{
-       while (count) {
-               count -= 4;
-               outl(*(const long *)src, addr);
-               src += 4;
-               /* addr += 4; */
-       }
-}
-EXPORT_SYMBOL(outsl);
-
-void insb(unsigned long addr, void *dst, unsigned long count)
-{
-       while (count) {
-               count -= 1;
-               *(unsigned char *)dst = inb(addr);
-               dst += 1;
-               /* addr += 1; */
-       }
-}
-EXPORT_SYMBOL(insb);
-
-void insw(unsigned long addr, void *dst, unsigned long count)
-{
-       while (count) {
-               count -= 2;
-               *(unsigned short *)dst = inw(addr);
-               dst += 2;
-               /* addr += 2; */
-       }
-}
-EXPORT_SYMBOL(insw);
-
-void insl(unsigned long addr, void *dst, unsigned long count)
-{
-       while (count) {
-               count -= 4;
-               /*
-                * XXX I am sure we are in for an unaligned trap here.
-                */
-               *(unsigned long *)dst = inl(addr);
-               dst += 4;
-               /* addr += 4; */
-       }
-}
-EXPORT_SYMBOL(insl);
index 6df26e37f8790c700c21a6b5651c4c84cf2ad874..c8bf26edfa7cf578ce4ce4eac513697371abc8b7 100644 (file)
@@ -80,7 +80,7 @@ struct grpci1_regs {
 
 struct grpci1_priv {
        struct leon_pci_info    info; /* must be on top of this structure */
-       struct grpci1_regs      *regs;          /* GRPCI register map */
+       struct grpci1_regs __iomem *regs;               /* GRPCI register map */
        struct device           *dev;
        int                     pci_err_mask;   /* STATUS register error mask */
        int                     irq;            /* LEON irqctrl GRPCI IRQ */
@@ -101,7 +101,7 @@ static struct grpci1_priv *grpci1priv;
 static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus,
                                unsigned int devfn, int where, u32 val);
 
-int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct grpci1_priv *priv = dev->bus->sysdata;
        int irq_group;
@@ -144,7 +144,7 @@ static int grpci1_cfg_r32(struct grpci1_priv *priv, unsigned int bus,
                grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, tmp);
        } else {
                /* Bus always little endian (unaffected by byte-swapping) */
-               *val = flip_dword(tmp);
+               *val = swab32(tmp);
        }
 
        return 0;
@@ -197,7 +197,7 @@ static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus,
 
        pci_conf = (unsigned int *) (priv->pci_conf |
                                                (devfn << 8) | (where & 0xfc));
-       LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val));
+       LEON3_BYPASS_STORE_PA(pci_conf, swab32(val));
 
        return 0;
 }
@@ -417,10 +417,10 @@ out:
  *  BAR1: peripheral DMA to host's memory (size at least 256MByte)
  *  BAR2..BAR5: not implemented in hardware
  */
-void grpci1_hw_init(struct grpci1_priv *priv)
+static void grpci1_hw_init(struct grpci1_priv *priv)
 {
        u32 ahbadr, bar_sz, data, pciadr;
-       struct grpci1_regs *regs = priv->regs;
+       struct grpci1_regs __iomem *regs = priv->regs;
 
        /* set 1:1 mapping between AHB -> PCI memory space */
        REGSTORE(regs->cfg_stat, priv->pci_area & 0xf0000000);
@@ -509,7 +509,7 @@ static irqreturn_t grpci1_err_interrupt(int irq, void *arg)
 
 static int grpci1_of_probe(struct platform_device *ofdev)
 {
-       struct grpci1_regs *regs;
+       struct grpci1_regs __iomem *regs;
        struct grpci1_priv *priv;
        int err, len;
        const int *tmp;
@@ -690,7 +690,7 @@ err3:
 err2:
        release_resource(&priv->info.mem_space);
 err1:
-       iounmap((void *)priv->pci_io_va);
+       iounmap((void __iomem *)priv->pci_io_va);
        grpci1priv = NULL;
        return err;
 }
index 24d6a44463494e0f4baae2928eaa715ea133ee62..e433a4d69fe0921487985a698dcfecbbd16e4f92 100644 (file)
@@ -191,7 +191,7 @@ struct grpci2_cap_first {
 
 struct grpci2_priv {
        struct leon_pci_info    info; /* must be on top of this structure */
-       struct grpci2_regs      *regs;
+       struct grpci2_regs __iomem *regs;
        char                    irq;
        char                    irq_mode; /* IRQ Mode from CAPSTS REG */
        char                    bt_enabled;
@@ -215,10 +215,10 @@ struct grpci2_priv {
        struct grpci2_barcfg    tgtbars[6];
 };
 
-DEFINE_SPINLOCK(grpci2_dev_lock);
-struct grpci2_priv *grpci2priv;
+static DEFINE_SPINLOCK(grpci2_dev_lock);
+static struct grpci2_priv *grpci2priv;
 
-int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct grpci2_priv *priv = dev->bus->sysdata;
        int irq_group;
@@ -270,7 +270,7 @@ static int grpci2_cfg_r32(struct grpci2_priv *priv, unsigned int bus,
                *val = 0xffffffff;
        } else {
                /* Bus always little endian (unaffected by byte-swapping) */
-               *val = flip_dword(tmp);
+               *val = swab32(tmp);
        }
 
        return 0;
@@ -328,7 +328,7 @@ static int grpci2_cfg_w32(struct grpci2_priv *priv, unsigned int bus,
 
        pci_conf = (unsigned int *) (priv->pci_conf |
                                                (devfn << 8) | (where & 0xfc));
-       LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val));
+       LEON3_BYPASS_STORE_PA(pci_conf, swab32(val));
 
        /* Wait until GRPCI2 signals that CFG access is done, it should be
         * done instantaneously unless a DMA operation is ongoing...
@@ -561,10 +561,10 @@ out:
        return virq;
 }
 
-void grpci2_hw_init(struct grpci2_priv *priv)
+static void grpci2_hw_init(struct grpci2_priv *priv)
 {
        u32 ahbadr, pciadr, bar_sz, capptr, io_map, data;
-       struct grpci2_regs *regs = priv->regs;
+       struct grpci2_regs __iomem *regs = priv->regs;
        int i;
        struct grpci2_barcfg *barcfg = priv->tgtbars;
 
@@ -655,7 +655,7 @@ static irqreturn_t grpci2_jump_interrupt(int irq, void *arg)
 static irqreturn_t grpci2_err_interrupt(int irq, void *arg)
 {
        struct grpci2_priv *priv = arg;
-       struct grpci2_regs *regs = priv->regs;
+       struct grpci2_regs __iomem *regs = priv->regs;
        unsigned int status;
 
        status = REGLOAD(regs->sts_cap);
@@ -682,7 +682,7 @@ static irqreturn_t grpci2_err_interrupt(int irq, void *arg)
 
 static int grpci2_of_probe(struct platform_device *ofdev)
 {
-       struct grpci2_regs *regs;
+       struct grpci2_regs __iomem *regs;
        struct grpci2_priv *priv;
        int err, i, len;
        const int *tmp;
@@ -878,7 +878,7 @@ err4:
        release_resource(&priv->info.mem_space);
 err3:
        err = -ENOMEM;
-       iounmap((void *)priv->pci_io_va);
+       iounmap((void __iomem *)priv->pci_io_va);
 err2:
        kfree(priv);
 err1:
index b0b3967a2dd2d1e6ca46571d635a43b02e38fa75..ddcf950282ed67a7ce7590b7d16ed2a796f93607 100644 (file)
 #include <asm/processor.h>
 
 /* List of Systems that need fixup instructions around power-down instruction */
-unsigned int pmc_leon_fixup_ids[] = {
+static unsigned int pmc_leon_fixup_ids[] = {
        AEROFLEX_UT699,
        GAISLER_GR712RC,
        LEON4_NEXTREME1,
        0
 };
 
-int pmc_leon_need_fixup(void)
+static int pmc_leon_need_fixup(void)
 {
        unsigned int systemid = amba_system_id >> 16;
        unsigned int *id;
@@ -38,7 +38,7 @@ int pmc_leon_need_fixup(void)
  * CPU idle callback function for systems that need some extra handling
  * See .../arch/sparc/kernel/process.c
  */
-void pmc_leon_idle_fixup(void)
+static void pmc_leon_idle_fixup(void)
 {
        /* Prepare an address to a non-cachable region. APB is always
         * none-cachable. One instruction is executed after the Sleep
@@ -62,7 +62,7 @@ void pmc_leon_idle_fixup(void)
  * CPU idle callback function
  * See .../arch/sparc/kernel/process.c
  */
-void pmc_leon_idle(void)
+static void pmc_leon_idle(void)
 {
        /* Interrupts need to be enabled to not hang the CPU */
        local_irq_enable();
index 6edf955f987caabd6427eb3bd80b8c7603b02563..018ef11f57df7060a1bd83d7db6a35a82bfc7391 100644 (file)
@@ -130,7 +130,7 @@ void leon_configure_cache_smp(void)
        local_ops->tlb_all();
 }
 
-void leon_smp_setbroadcast(unsigned int mask)
+static void leon_smp_setbroadcast(unsigned int mask)
 {
        int broadcast =
            ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
@@ -148,13 +148,6 @@ void leon_smp_setbroadcast(unsigned int mask)
        LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpbroadcast), mask);
 }
 
-unsigned int leon_smp_getbroadcast(void)
-{
-       unsigned int mask;
-       mask = LEON_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpbroadcast));
-       return mask;
-}
-
 int leon_smp_nrcpus(void)
 {
        int nrcpu =
@@ -266,10 +259,6 @@ void __init leon_smp_done(void)
 
 }
 
-void leon_irq_rotate(int cpu)
-{
-}
-
 struct leon_ipi_work {
        int single;
        int msk;
index 6479256fd5a4b650a2f5c3ca3cf5c501033dc9fb..3370945569162dd43ef1252f47c83cf6ad7d87d6 100644 (file)
@@ -68,27 +68,16 @@ EXPORT_SYMBOL(touch_nmi_watchdog);
 
 static void die_nmi(const char *str, struct pt_regs *regs, int do_panic)
 {
+       int this_cpu = smp_processor_id();
+
        if (notify_die(DIE_NMIWATCHDOG, str, regs, 0,
                       pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP)
                return;
 
-       console_verbose();
-       bust_spinlocks(1);
-
-       printk(KERN_EMERG "%s", str);
-       printk(" on CPU%d, ip %08lx, registers:\n",
-              smp_processor_id(), regs->tpc);
-       show_regs(regs);
-       dump_stack();
-
-       bust_spinlocks(0);
-
        if (do_panic || panic_on_oops)
-               panic("Non maskable interrupt");
-
-       nmi_exit();
-       local_irq_enable();
-       do_exit(SIGBUS);
+               panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+       else
+               WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
 }
 
 notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
index 3241f56331c2aced51e918aa9dde9ef936e54e7c..de0ee3971f00ecdda68b4ac3c081878b55df4361 100644 (file)
@@ -5,8 +5,10 @@
 #include <linux/mod_devicetable.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
-#include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
 
 #include "of_device_common.h"
 
index 09f4fdd8d8080fd45f8795a193b9b308c5d748cc..aabfcab94325244eca339c050063c616f51bd83f 100644 (file)
@@ -783,7 +783,7 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
 void pcic_nmi(unsigned int pend, struct pt_regs *regs)
 {
 
-       pend = flip_dword(pend);
+       pend = swab32(pend);
 
        if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) {
                /*
@@ -875,82 +875,4 @@ void __init sun4m_pci_init_IRQ(void)
        sparc_config.load_profile_irq = pcic_load_profile_irq;
 }
 
-/*
- * This probably belongs here rather than ioport.c because
- * we do not want this crud linked into SBus kernels.
- * Also, think for a moment about likes of floppy.c that
- * include architecture specific parts. They may want to redefine ins/outs.
- *
- * We do not use horrible macros here because we want to
- * advance pointer by sizeof(size).
- */
-void outsb(unsigned long addr, const void *src, unsigned long count)
-{
-       while (count) {
-               count -= 1;
-               outb(*(const char *)src, addr);
-               src += 1;
-               /* addr += 1; */
-       }
-}
-EXPORT_SYMBOL(outsb);
-
-void outsw(unsigned long addr, const void *src, unsigned long count)
-{
-       while (count) {
-               count -= 2;
-               outw(*(const short *)src, addr);
-               src += 2;
-               /* addr += 2; */
-       }
-}
-EXPORT_SYMBOL(outsw);
-
-void outsl(unsigned long addr, const void *src, unsigned long count)
-{
-       while (count) {
-               count -= 4;
-               outl(*(const long *)src, addr);
-               src += 4;
-               /* addr += 4; */
-       }
-}
-EXPORT_SYMBOL(outsl);
-
-void insb(unsigned long addr, void *dst, unsigned long count)
-{
-       while (count) {
-               count -= 1;
-               *(unsigned char *)dst = inb(addr);
-               dst += 1;
-               /* addr += 1; */
-       }
-}
-EXPORT_SYMBOL(insb);
-
-void insw(unsigned long addr, void *dst, unsigned long count)
-{
-       while (count) {
-               count -= 2;
-               *(unsigned short *)dst = inw(addr);
-               dst += 2;
-               /* addr += 2; */
-       }
-}
-EXPORT_SYMBOL(insw);
-
-void insl(unsigned long addr, void *dst, unsigned long count)
-{
-       while (count) {
-               count -= 4;
-               /*
-                * XXX I am sure we are in for an unaligned trap here.
-                */
-               *(unsigned long *)dst = inl(addr);
-               dst += 4;
-               /* addr += 4; */
-       }
-}
-EXPORT_SYMBOL(insl);
-
 subsys_initcall(pcic_init);
index 510baec1b69b2ca79d3f9e8687520e1b0b541b91..61f810b0a9d92c95bd1e1bf71f42b280040ae5e8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <stdarg.h>
 
+#include <linux/elfcore.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -23,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
 
 #include <asm/auxio.h>
 #include <asm/oplib.h>
@@ -38,6 +40,8 @@
 #include <asm/unistd.h>
 #include <asm/setup.h>
 
+#include "kernel.h"
+
 /* 
  * Power management idle function 
  * Set in pm platform drivers (apc.c and pmc.c)
index 896ba7c5cd8eb9c6433d6b51966b93b474542e9b..a331fdc11a2cc04748251d7b69d491791d9e210e 100644 (file)
@@ -26,6 +26,8 @@
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 
+#include "kernel.h"
+
 /* #define ALLOW_INIT_TRACING */
 
 /*
index 1434526970a6bf446a495d275eab9f46073a4172..baef495c06bdb081c0744a33f0e9564bd125a1eb 100644 (file)
@@ -267,7 +267,7 @@ static __init void leon_patch(void)
 }
 
 struct tt_entry *sparc_ttable;
-struct pt_regs fake_swapper_regs;
+static struct pt_regs fake_swapper_regs;
 
 /* Called from head_32.S - before we have setup anything
  * in the kernel. Be very careful with what you do here.
@@ -365,7 +365,7 @@ void __init setup_arch(char **cmdline_p)
 
        prom_setsync(prom_sync_me);
 
-       if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
+       if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) &&
           ((*(short *)linux_dbvec) != -1)) {
                printk("Booted under KADB. Syncing trap table.\n");
                (*(linux_dbvec->teach_debugger))();
index 7d5d8e1f841569e02b02a8ddf303b47770cb694f..9ee72fc8e0e49636f1db8f97e645883d4e69b2ce 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/switch_to.h>
 
 #include "sigutil.h"
+#include "kernel.h"
 
 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
                   void *fpqueue, unsigned long *fpqdepth);
@@ -341,7 +342,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs,
        err |= __put_user(0, &sf->extra_size);
 
        if (psr & PSR_EF) {
-               __siginfo_fpu_t *fp = tail;
+               __siginfo_fpu_t __user *fp = tail;
                tail += sizeof(*fp);
                err |= save_fpu_state(regs, fp);
                err |= __put_user(fp, &sf->fpu_save);
@@ -349,7 +350,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs,
                err |= __put_user(0, &sf->fpu_save);
        }
        if (wsaved) {
-               __siginfo_rwin_t *rwp = tail;
+               __siginfo_rwin_t __user *rwp = tail;
                tail += sizeof(*rwp);
                err |= save_rwin_state(wsaved, rwp);
                err |= __put_user(rwp, &sf->rwin_save);
@@ -517,9 +518,9 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
        }
 }
 
-asmlinkage int
-do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
-               unsigned long sp)
+asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr,
+                               struct sigstack __user *ossptr,
+                               unsigned long sp)
 {
        int ret = -EFAULT;
 
index a102bfba6ea866e2495e52647b845b4333d32e98..9d3297d8d7308a23fa9e0674d764f30916e9fa4d 100644 (file)
@@ -75,8 +75,6 @@ void smp_store_cpu_info(int id)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
-       extern void smp4m_smp_done(void);
-       extern void smp4d_smp_done(void);
        unsigned long bogosum = 0;
        int cpu, num = 0;
 
@@ -183,8 +181,6 @@ int setup_profiling_timer(unsigned int multiplier)
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       extern void __init smp4m_boot_cpus(void);
-       extern void __init smp4d_boot_cpus(void);
        int i, cpuid, extra;
 
        printk("Entering SMP Mode...\n");
@@ -261,8 +257,6 @@ void __init smp_prepare_boot_cpu(void)
 
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
-       extern int smp4m_boot_one_cpu(int, struct task_struct *);
-       extern int smp4d_boot_one_cpu(int, struct task_struct *);
        int ret=0;
 
        switch(sparc_cpu_model) {
@@ -297,7 +291,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        return ret;
 }
 
-void arch_cpu_pre_starting(void *arg)
+static void arch_cpu_pre_starting(void *arg)
 {
        local_ops->cache_all();
        local_ops->tlb_all();
@@ -317,7 +311,7 @@ void arch_cpu_pre_starting(void *arg)
        }
 }
 
-void arch_cpu_pre_online(void *arg)
+static void arch_cpu_pre_online(void *arg)
 {
        unsigned int cpuid = hard_smp_processor_id();
 
@@ -344,7 +338,7 @@ void arch_cpu_pre_online(void *arg)
        }
 }
 
-void sparc_start_secondary(void *arg)
+static void sparc_start_secondary(void *arg)
 {
        unsigned int cpu;
 
index 9781048161ab8865a3ce203074d4067312989b95..745a3633ce148208554a71a38c829d6a8c78e025 100644 (file)
@@ -149,7 +149,7 @@ void cpu_panic(void)
 #define NUM_ROUNDS     64      /* magic value */
 #define NUM_ITERS      5       /* likewise */
 
-static DEFINE_SPINLOCK(itc_sync_lock);
+static DEFINE_RAW_SPINLOCK(itc_sync_lock);
 static unsigned long go[SLAVE + 1];
 
 #define DEBUG_TICK_SYNC        0
@@ -257,7 +257,7 @@ static void smp_synchronize_one_tick(int cpu)
        go[MASTER] = 0;
        membar_safe("#StoreLoad");
 
-       spin_lock_irqsave(&itc_sync_lock, flags);
+       raw_spin_lock_irqsave(&itc_sync_lock, flags);
        {
                for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
                        while (!go[MASTER])
@@ -268,7 +268,7 @@ static void smp_synchronize_one_tick(int cpu)
                        membar_safe("#StoreLoad");
                }
        }
-       spin_unlock_irqrestore(&itc_sync_lock, flags);
+       raw_spin_unlock_irqrestore(&itc_sync_lock, flags);
 }
 
 #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
index f8933be3ca8b211ae5c459adcecf0d80af6439f5..a1bb2675b2801ac44891f3acf50320613e35a025 100644 (file)
@@ -143,7 +143,7 @@ static void sun4d_sbus_handler_irq(int sbusl)
        }
 }
 
-void sun4d_handler_irq(int pil, struct pt_regs *regs)
+void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs)
 {
        struct pt_regs *old_regs;
        /* SBUS IRQ level (1 - 7) */
@@ -236,7 +236,7 @@ static void sun4d_shutdown_irq(struct irq_data *data)
        irq_unlink(data->irq);
 }
 
-struct irq_chip sun4d_irq = {
+static struct irq_chip sun4d_irq = {
        .name           = "sun4d",
        .irq_startup    = sun4d_startup_irq,
        .irq_shutdown   = sun4d_shutdown_irq,
@@ -285,9 +285,9 @@ static void __init sun4d_load_profile_irqs(void)
        }
 }
 
-unsigned int _sun4d_build_device_irq(unsigned int real_irq,
-                                     unsigned int pil,
-                                     unsigned int board)
+static unsigned int _sun4d_build_device_irq(unsigned int real_irq,
+                                            unsigned int pil,
+                                            unsigned int board)
 {
        struct sun4d_handler_data *handler_data;
        unsigned int irq;
@@ -320,8 +320,8 @@ err_out:
 
 
 
-unsigned int sun4d_build_device_irq(struct platform_device *op,
-                                    unsigned int real_irq)
+static unsigned int sun4d_build_device_irq(struct platform_device *op,
+                                           unsigned int real_irq)
 {
        struct device_node *dp = op->dev.of_node;
        struct device_node *board_parent, *bus = dp->parent;
@@ -383,7 +383,8 @@ err_out:
        return irq;
 }
 
-unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
+static unsigned int sun4d_build_timer_irq(unsigned int board,
+                                          unsigned int real_irq)
 {
        return _sun4d_build_device_irq(real_irq, real_irq, board);
 }
index f7c72b6efc27556cd2e2de7a74539b1ba21831ce..d066eb18650c1598f898f7a4314bdd7ed5b606a7 100644 (file)
@@ -44,7 +44,7 @@ SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)
 SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
 SIGN1(sys32_mq_open, compat_sys_mq_open, %o1)
 SIGN1(sys32_select, compat_sys_select, %o0)
-SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5)
+SIGN1(sys32_futex, compat_sys_futex, %o1)
 SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0)
 SIGN1(sys32_recvmsg, compat_sys_recvmsg, %o0)
 SIGN1(sys32_sendmsg, compat_sys_sendmsg, %o0)
index 9aba8bd5a78b56a94c22d9387588d84bf85a97d3..4bbfe4e2676de094dc5513123fdbafce9e0eea7c 100644 (file)
 #include <asm/oplib.h>
 #include <asm/io.h>
 
+#include "kernel.h"
+
 #define MACIO_SCSI_CSR_ADDR    0x78400000
 #define MACIO_EN_DMA           0x00000200
 #define CLOCK_INIT_DONE                1
 
 static int clk_state;
 static volatile unsigned char *clk_ctrl;
-void (*cpu_pwr_save)(void);
+
+/* TODO - cpu_pwr_save is only assigned - cleanup potential. */
+static void (*cpu_pwr_save)(void);
 
 static inline unsigned int ldphys(unsigned int addr)
 {
index c4c27b0f9063d74f2a2d6dd8963b3753354976ba..772b37986a9cc45af7d058c31a18eaee77c8ad44 100644 (file)
@@ -83,7 +83,7 @@ unsigned long profile_pc(struct pt_regs *regs)
 
 EXPORT_SYMBOL(profile_pc);
 
-__volatile__ unsigned int *master_l10_counter;
+volatile unsigned int __iomem *master_l10_counter;
 
 int update_persistent_clock(struct timespec now)
 {
index 662982946a89184916f32137b4b422b3044af3e7..a655e5bf92a70796a2b5724ec406ac2d38a1637e 100644 (file)
@@ -44,7 +44,7 @@ static void instruction_dump(unsigned long *pc)
 #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
 #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
 
-void die_if_kernel(char *str, struct pt_regs *regs)
+void __noreturn die_if_kernel(char *str, struct pt_regs *regs)
 {
        static int die_counter;
        int count = 0;
index c0ec897861934f3457f73237f533cfe65f630adf..c5c61b3c6b56f30d40165179e1e851d8859f6bd3 100644 (file)
 #include <linux/smp.h>
 #include <linux/perf_event.h>
 
+#include <asm/setup.h>
+
+#include "kernel.h"
+
 enum direction {
        load,    /* ld, ldd, ldh, ldsh */
        store,   /* st, std, sth, stsh */
index 3107381e576d6f78431d0ccde6c73114ae387944..87bab0a3857a528bf7e90bf72a1d83fad2513b99 100644 (file)
 #include <linux/mm.h>
 #include <linux/smp.h>
 
+#include <asm/cacheflush.h>
 #include <asm/uaccess.h>
 
+#include "kernel.h"
+
 /* Do save's until all user register windows are out of the cpu. */
 void flush_user_windows(void)
 {
index dbe119b63b48ba968a503ee3bd40d3dceaa8ac13..3269b0234093bfdbd6b6dcd22388cdc65a627d0a 100644 (file)
@@ -41,7 +41,7 @@ lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
 lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
 lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
 
-obj-y                 += iomap.o
+obj-$(CONFIG_SPARC64) += iomap.o
 obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o
 obj-y                 += ksyms.o
 obj-$(CONFIG_SPARC64) += PeeCeeI.o
index 59dbd46457250b050ce84a48370a4f96afa3746d..908e8c17c902bef419877cd1bedcc896b9627636 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/setup.h>
 #include <asm/smp.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
 
-int show_unhandled_signals = 1;
+#include "mm_32.h"
 
-static void unhandled_fault(unsigned long, struct task_struct *,
-               struct pt_regs *) __attribute__ ((noreturn));
+int show_unhandled_signals = 1;
 
 static void __noreturn unhandled_fault(unsigned long address,
                                       struct task_struct *tsk,
@@ -141,9 +141,6 @@ static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs,
        force_sig_info (sig, &info, current);
 }
 
-extern unsigned long safe_compute_effective_address(struct pt_regs *,
-                                                   unsigned int);
-
 static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
 {
        unsigned int insn;
index db69870828058db51e07699472cc9d9bcd3f7e34..eb828715527971b050faa9e40693218c7e25db27 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/vaddrs.h>
 #include <asm/pgalloc.h>       /* bug in asm-generic/tlb.h: check_pgt_cache */
+#include <asm/setup.h>
 #include <asm/tlb.h>
 #include <asm/prom.h>
 #include <asm/leon.h>
 
+#include "mm_32.h"
+
 unsigned long *sparc_valid_addr_bitmap;
 EXPORT_SYMBOL(sparc_valid_addr_bitmap);
 
@@ -63,7 +66,6 @@ void show_mem(unsigned int filter)
 }
 
 
-extern unsigned long cmdline_memory_size;
 unsigned long last_valid_pfn;
 
 unsigned long calc_highpages(void)
@@ -246,9 +248,6 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
  * init routine based upon the Sun model type on the Sparc.
  *
  */
-extern void srmmu_paging_init(void);
-extern void device_scan(void);
-
 void __init paging_init(void)
 {
        srmmu_paging_init();
index 28f96f27c7683e1201d5ca6e53409e391594aff4..35384cb60b210108f19d1536827de71ccd8b56e6 100644 (file)
@@ -27,6 +27,8 @@
 #include <asm/iommu.h>
 #include <asm/dma.h>
 
+#include "mm_32.h"
+
 /*
  * This can be sized dynamically, but we will do this
  * only when we have a guidance about actual I/O pressures.
@@ -37,9 +39,6 @@
 #define IOMMU_NPTES    (IOMMU_WINSIZE/PAGE_SIZE)       /* 64K PTEs, 256KB */
 #define IOMMU_ORDER    6                               /* 4096 * (1<<6) */
 
-/* srmmu.c */
-extern int viking_mxcc_present;
-extern int flush_page_for_dma_global;
 static int viking_flush;
 /* viking.S */
 extern void viking_flush_page(unsigned long page);
index 5bed085a2c17984a5c33fc5ea509005e3db679cb..3b17b6f7895ac405853844fd6133c7d06caf2189 100644 (file)
 #include <asm/leon.h>
 #include <asm/tlbflush.h>
 
-#include "srmmu.h"
+#include "mm_32.h"
 
 int leon_flush_during_switch = 1;
-int srmmu_swprobe_trace;
+static int srmmu_swprobe_trace;
 
 static inline unsigned long leon_get_ctable_ptr(void)
 {
diff --git a/arch/sparc/mm/mm_32.h b/arch/sparc/mm/mm_32.h
new file mode 100644 (file)
index 0000000..a6c27ca
--- /dev/null
@@ -0,0 +1,24 @@
+/* fault_32.c - visible as they are called from assembler */
+asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
+                            unsigned long address);
+asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
+                               unsigned long address);
+
+void window_overflow_fault(void);
+void window_underflow_fault(unsigned long sp);
+void window_ret_fault(struct pt_regs *regs);
+
+/* srmmu.c */
+extern char *srmmu_name;
+extern int viking_mxcc_present;
+extern int flush_page_for_dma_global;
+
+extern void (*poke_srmmu)(void);
+
+void __init srmmu_paging_init(void);
+
+/* iommu.c */
+void ld_mmu_iommu(void);
+
+/* io-unit.c */
+void ld_mmu_iounit(void);
index cfbe53c17b0dbb61b25f8ae48c0f3017f307cc6f..be65f035d18a11bbfeb40ded7f7ae8854889db58 100644 (file)
@@ -49,7 +49,7 @@
 #include <asm/mxcc.h>
 #include <asm/ross.h>
 
-#include "srmmu.h"
+#include "mm_32.h"
 
 enum mbus_module srmmu_modtype;
 static unsigned int hwbug_bitmask;
@@ -100,7 +100,6 @@ static unsigned long srmmu_nocache_end;
 #define SRMMU_NOCACHE_ALIGN_MAX (sizeof(ctxd_t)*SRMMU_MAX_CONTEXTS)
 
 void *srmmu_nocache_pool;
-void *srmmu_nocache_bitmap;
 static struct bit_map srmmu_nocache_map;
 
 static inline int srmmu_pmd_none(pmd_t pmd)
@@ -173,7 +172,7 @@ static void *__srmmu_get_nocache(int size, int align)
                printk(KERN_ERR "srmmu: out of nocache %d: %d/%d\n",
                       size, (int) srmmu_nocache_size,
                       srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT);
-               return 0;
+               return NULL;
        }
 
        addr = SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT);
@@ -269,6 +268,7 @@ static void __init srmmu_nocache_calcsize(void)
 
 static void __init srmmu_nocache_init(void)
 {
+       void *srmmu_nocache_bitmap;
        unsigned int bitmap_bits;
        pgd_t *pgd;
        pmd_t *pmd;
@@ -728,7 +728,7 @@ static inline unsigned long srmmu_probe(unsigned long vaddr)
                                     "=r" (retval) :
                                     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
        } else {
-               retval = leon_swprobe(vaddr, 0);
+               retval = leon_swprobe(vaddr, NULL);
        }
        return retval;
 }
@@ -865,8 +865,6 @@ static void __init map_kernel(void)
 
 void (*poke_srmmu)(void) = NULL;
 
-extern unsigned long bootmem_init(unsigned long *pages_avail);
-
 void __init srmmu_paging_init(void)
 {
        int i;
@@ -1771,9 +1769,6 @@ static struct sparc32_cachetlb_ops smp_cachetlb_ops = {
 /* Load up routines and constants for sun4m and sun4d mmu */
 void __init load_mmu(void)
 {
-       extern void ld_mmu_iommu(void);
-       extern void ld_mmu_iounit(void);
-
        /* Functions */
        get_srmmu_type();
 
diff --git a/arch/sparc/mm/srmmu.h b/arch/sparc/mm/srmmu.h
deleted file mode 100644 (file)
index 5703274..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/* srmmu.c */
-extern char *srmmu_name;
-
-extern void (*poke_srmmu)(void);
index 74c91729a62a9290e12bb31ea96ab7ad240aebc2..00732474fb55694e3f1e7fac7a7db7b53b86f6ed 100644 (file)
@@ -691,7 +691,7 @@ static void __init setup_bootmem_allocator(void)
        /* Reserve any memory excluded by "memmap" arguments. */
        for (i = 0; i < memmap_nr; ++i) {
                struct memmap_entry *m = &memmap_map[i];
-               reserve_bootmem(m->addr, m->size, 0);
+               reserve_bootmem(m->addr, m->size, BOOTMEM_DEFAULT);
        }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -715,7 +715,8 @@ static void __init setup_bootmem_allocator(void)
 
 #ifdef CONFIG_KEXEC
        if (crashk_res.start != crashk_res.end)
-               reserve_bootmem(crashk_res.start, resource_size(&crashk_res), 0);
+               reserve_bootmem(crashk_res.start, resource_size(&crashk_res),
+                               BOOTMEM_DEFAULT);
 #endif
 }
 
index 08eec0b691b061ade61d8f9df7258ea4bee49f42..d824528f6f62fb8ebbd6710c292f2ed3f3d8bfd5 100644 (file)
@@ -174,7 +174,6 @@ extern unsigned long long os_makedev(unsigned major, unsigned minor);
 
 /* start_up.c */
 extern void os_early_checks(void);
-extern void can_do_skas(void);
 extern void os_check_bugs(void);
 extern void check_host_supports_tls(int *supports_tls, int *tls_min);
 
@@ -187,7 +186,6 @@ extern int os_process_parent(int pid);
 extern void os_stop_process(int pid);
 extern void os_kill_process(int pid, int reap_child);
 extern void os_kill_ptraced_process(int pid, int reap_child);
-extern long os_ptrace_ldt(long pid, long addr, long data);
 
 extern int os_getpid(void);
 extern int os_getpgrp(void);
diff --git a/arch/um/include/shared/skas/proc_mm.h b/arch/um/include/shared/skas/proc_mm.h
deleted file mode 100644 (file)
index 9028092..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_PROC_MM_H
-#define __SKAS_PROC_MM_H
-
-#define MM_MMAP 54
-#define MM_MUNMAP 55
-#define MM_MPROTECT 56
-#define MM_COPY_SEGMENTS 57
-
-struct mm_mmap {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-struct mm_munmap {
-       unsigned long addr;
-       unsigned long len;
-};
-
-struct mm_mprotect {
-       unsigned long addr;
-       unsigned long len;
-       unsigned int prot;
-};
-
-struct proc_mm_op {
-       int op;
-       union {
-               struct mm_mmap mmap;
-               struct mm_munmap munmap;
-               struct mm_mprotect mprotect;
-               int copy_segments;
-       } u;
-};
-
-#endif
index c45df961c874dd157334057370321b8040441c9e..911f3c45ad1f89bd6686443a87a57c4bcaa882f3 100644 (file)
@@ -9,13 +9,10 @@
 #include <sysdep/ptrace.h>
 
 extern int userspace_pid[];
-extern int proc_mm, ptrace_faultinfo, ptrace_ldt;
-extern int skas_needs_stub;
 
 extern int user_thread(unsigned long stack, int flags);
 extern void new_thread_handler(void);
 extern void handle_syscall(struct uml_pt_regs *regs);
-extern int new_mm(unsigned long stack);
 extern long execute_syscall_skas(void *r);
 extern unsigned long current_stub_stack(void);
 
diff --git a/arch/um/include/shared/skas_ptrace.h b/arch/um/include/shared/skas_ptrace.h
deleted file mode 100644 (file)
index 630a9c9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* 
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_PTRACE_H
-#define __SKAS_PTRACE_H
-
-#define PTRACE_FAULTINFO 52
-#define PTRACE_SWITCH_MM 55
-
-#include <sysdep/skas_ptrace.h>
-
-#endif
index 694d551c88996dbee7c974487b9299c9f1efc8fe..8c06a4a7ad187b48e791f9f2fb5f41e280d1ac60 100644 (file)
@@ -8,9 +8,6 @@
 #include <linux/sched.h>
 #include <linux/tracehook.h>
 #include <asm/uaccess.h>
-#include <skas_ptrace.h>
-
-
 
 void user_enable_single_step(struct task_struct *child)
 {
@@ -104,35 +101,6 @@ long arch_ptrace(struct task_struct *child, long request,
                ret = ptrace_set_thread_area(child, addr, vp);
                break;
 
-       case PTRACE_FAULTINFO: {
-               /*
-                * Take the info from thread->arch->faultinfo,
-                * but transfer max. sizeof(struct ptrace_faultinfo).
-                * On i386, ptrace_faultinfo is smaller!
-                */
-               ret = copy_to_user(p, &child->thread.arch.faultinfo,
-                                  sizeof(struct ptrace_faultinfo)) ?
-                       -EIO : 0;
-               break;
-       }
-
-#ifdef PTRACE_LDT
-       case PTRACE_LDT: {
-               struct ptrace_ldt ldt;
-
-               if (copy_from_user(&ldt, p, sizeof(ldt))) {
-                       ret = -EIO;
-                       break;
-               }
-
-               /*
-                * This one is confusing, so just punt and return -EIO for
-                * now
-                */
-               ret = -EIO;
-               break;
-       }
-#endif
        default:
                ret = ptrace_request(child, request, addr, data);
                if (ret == -EIO)
index ced8903921aeb61a255edde5f69cb86a98a2b70e..9bdf67a092a53bc9b9f68939abce7cc872e2a8b6 100644 (file)
@@ -15,28 +15,21 @@ void (*pm_power_off)(void);
 
 static void kill_off_processes(void)
 {
-       if (proc_mm)
-               /*
-                * FIXME: need to loop over userspace_pids
-                */
-               os_kill_ptraced_process(userspace_pid[0], 1);
-       else {
-               struct task_struct *p;
-               int pid;
-
-               read_lock(&tasklist_lock);
-               for_each_process(p) {
-                       struct task_struct *t;
-
-                       t = find_lock_task_mm(p);
-                       if (!t)
-                               continue;
-                       pid = t->mm->context.id.u.pid;
-                       task_unlock(t);
-                       os_kill_ptraced_process(pid, 1);
-               }
-               read_unlock(&tasklist_lock);
+       struct task_struct *p;
+       int pid;
+
+       read_lock(&tasklist_lock);
+       for_each_process(p) {
+               struct task_struct *t;
+
+               t = find_lock_task_mm(p);
+               if (!t)
+                       continue;
+               pid = t->mm->context.id.u.pid;
+               task_unlock(t);
+               os_kill_ptraced_process(pid, 1);
        }
+       read_unlock(&tasklist_lock);
 }
 
 void uml_cleanup(void)
index 007d5503f49b79bfccbfbe842bbe630fbc625ac1..94abdcc1d6ad19c7de8683b34db17331fa2ec926 100644 (file)
@@ -54,35 +54,22 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
        unsigned long stack = 0;
        int ret = -ENOMEM;
 
-       if (skas_needs_stub) {
-               stack = get_zeroed_page(GFP_KERNEL);
-               if (stack == 0)
-                       goto out;
-       }
+       stack = get_zeroed_page(GFP_KERNEL);
+       if (stack == 0)
+               goto out;
 
        to_mm->id.stack = stack;
        if (current->mm != NULL && current->mm != &init_mm)
                from_mm = &current->mm->context;
 
-       if (proc_mm) {
-               ret = new_mm(stack);
-               if (ret < 0) {
-                       printk(KERN_ERR "init_new_context_skas - "
-                              "new_mm failed, errno = %d\n", ret);
-                       goto out_free;
-               }
-               to_mm->id.u.mm_fd = ret;
-       }
-       else {
-               if (from_mm)
-                       to_mm->id.u.pid = copy_context_skas0(stack,
-                                                            from_mm->id.u.pid);
-               else to_mm->id.u.pid = start_userspace(stack);
-
-               if (to_mm->id.u.pid < 0) {
-                       ret = to_mm->id.u.pid;
-                       goto out_free;
-               }
+       if (from_mm)
+               to_mm->id.u.pid = copy_context_skas0(stack,
+                                                    from_mm->id.u.pid);
+       else to_mm->id.u.pid = start_userspace(stack);
+
+       if (to_mm->id.u.pid < 0) {
+               ret = to_mm->id.u.pid;
+               goto out_free;
        }
 
        ret = init_new_ldt(to_mm, from_mm);
@@ -105,9 +92,6 @@ void uml_setup_stubs(struct mm_struct *mm)
 {
        int err, ret;
 
-       if (!skas_needs_stub)
-               return;
-
        ret = init_stub_pte(mm, STUB_CODE,
                            (unsigned long) &__syscall_stub_start);
        if (ret)
@@ -154,25 +138,19 @@ void destroy_context(struct mm_struct *mm)
 {
        struct mm_context *mmu = &mm->context;
 
-       if (proc_mm)
-               os_close_file(mmu->id.u.mm_fd);
-       else {
-               /*
-                * If init_new_context wasn't called, this will be
-                * zero, resulting in a kill(0), which will result in the
-                * whole UML suddenly dying.  Also, cover negative and
-                * 1 cases, since they shouldn't happen either.
-                */
-               if (mmu->id.u.pid < 2) {
-                       printk(KERN_ERR "corrupt mm_context - pid = %d\n",
-                              mmu->id.u.pid);
-                       return;
-               }
-               os_kill_ptraced_process(mmu->id.u.pid, 1);
+       /*
+        * If init_new_context wasn't called, this will be
+        * zero, resulting in a kill(0), which will result in the
+        * whole UML suddenly dying.  Also, cover negative and
+        * 1 cases, since they shouldn't happen either.
+        */
+       if (mmu->id.u.pid < 2) {
+               printk(KERN_ERR "corrupt mm_context - pid = %d\n",
+                      mmu->id.u.pid);
+               return;
        }
+       os_kill_ptraced_process(mmu->id.u.pid, 1);
 
-       if (skas_needs_stub)
-               free_page(mmu->id.stack);
-
+       free_page(mmu->id.stack);
        free_ldt(mmu);
 }
index 4da11b3c8ddbc31af5b4a360f487769d84fcf60a..082955d694f38b0834681b333851180ea97b18a1 100644 (file)
 #include <os.h>
 #include <skas.h>
 
-int new_mm(unsigned long stack)
-{
-       int fd, err;
-
-       fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
-       if (fd < 0)
-               return fd;
-
-       if (skas_needs_stub) {
-               err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
-               if (err) {
-                       os_close_file(fd);
-                       return err;
-               }
-       }
-
-       return fd;
-}
-
 extern void start_kernel(void);
 
 static int __init start_kernel_proc(void *unused)
@@ -55,14 +36,6 @@ int __init start_uml(void)
 {
        stack_protections((unsigned long) &cpu0_irqstack);
        set_sigstack(cpu0_irqstack, THREAD_SIZE);
-       if (proc_mm) {
-               userspace_pid[0] = start_userspace(0);
-               if (userspace_pid[0] < 0) {
-                       printf("start_uml - start_userspace returned %d\n",
-                              userspace_pid[0]);
-                       exit(1);
-               }
-       }
 
        init_new_thread_signals();
 
index 974b87474a9900f1909f845d449eba90dc9b8338..4a6235b758e671825fbfc78eb432bcd1814a5e04 100644 (file)
@@ -218,7 +218,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
                panic("Segfault with no mm");
        }
 
-       if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
+       if (SEGV_IS_FIXABLE(&fi))
                err = handle_page_fault(address, ip, is_write, is_user,
                                        &si.si_code);
        else {
index 016adf0985d522ccfb5f22e6d287bb60dfdb4e61..6043c767d3785257462e030c1477a2f75086b6a6 100644 (file)
@@ -268,7 +268,6 @@ int __init linux_main(int argc, char **argv)
        unsigned long stack;
        unsigned int i;
        int add;
-       char * mode;
 
        for (i = 1; i < argc; i++) {
                if ((i == 1) && (argv[i][0] == ' '))
@@ -291,15 +290,6 @@ int __init linux_main(int argc, char **argv)
        /* OS sanity checks that need to happen before the kernel runs */
        os_early_checks();
 
-       can_do_skas();
-
-       if (proc_mm && ptrace_faultinfo)
-               mode = "SKAS3";
-       else
-               mode = "SKAS0";
-
-       printf("UML running in %s mode\n", mode);
-
        brk_start = (unsigned long) sbrk(0);
 
        /*
index 33496fe2bb52f428bc8229749dc6b224ab60242a..8408aba915b29f7e603233fc5c27e80abd081864 100644 (file)
@@ -16,7 +16,6 @@
 #include <init.h>
 #include <longjmp.h>
 #include <os.h>
-#include <skas_ptrace.h>
 
 #define ARBITRARY_ADDR -1
 #define FAILURE_PID    -1
@@ -102,21 +101,6 @@ void os_kill_process(int pid, int reap_child)
                CATCH_EINTR(waitpid(pid, NULL, __WALL));
 }
 
-/* This is here uniquely to have access to the userspace errno, i.e. the one
- * used by ptrace in case of error.
- */
-
-long os_ptrace_ldt(long pid, long addr, long data)
-{
-       int ret;
-
-       ret = ptrace(PTRACE_LDT, pid, addr, data);
-
-       if (ret < 0)
-               return -errno;
-       return ret;
-}
-
 /* Kill off a ptraced child by all means available.  kill it normally first,
  * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
  * which it can't exit directly.
index 689b18db798ffb89ac5c6f5bae839aae4567c201..e7f8c945a573ac220dd2c9ed40d7b6594b010f30 100644 (file)
@@ -12,7 +12,6 @@
 #include <as-layout.h>
 #include <mm_id.h>
 #include <os.h>
-#include <proc_mm.h>
 #include <ptrace_user.h>
 #include <registers.h>
 #include <skas.h>
@@ -46,8 +45,6 @@ static int __init init_syscall_regs(void)
 
 __initcall(init_syscall_regs);
 
-extern int proc_mm;
-
 static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
 {
        int n, i;
@@ -56,10 +53,6 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
        unsigned long * syscall;
        int err, pid = mm_idp->u.pid;
 
-       if (proc_mm)
-               /* FIXME: Need to look up userspace_pid by cpu */
-               pid = userspace_pid[0];
-
        n = ptrace_setregs(pid, syscall_regs);
        if (n < 0) {
                printk(UM_KERN_ERR "Registers - \n");
@@ -178,38 +171,12 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot,
        int phys_fd, unsigned long long offset, int done, void **data)
 {
        int ret;
+       unsigned long args[] = { virt, len, prot,
+                                MAP_SHARED | MAP_FIXED, phys_fd,
+                                MMAP_OFFSET(offset) };
 
-       if (proc_mm) {
-               struct proc_mm_op map;
-               int fd = mm_idp->u.mm_fd;
-
-               map = ((struct proc_mm_op) { .op        = MM_MMAP,
-                                      .u               =
-                                      { .mmap  =
-                                        { .addr        = virt,
-                                          .len = len,
-                                          .prot        = prot,
-                                          .flags       = MAP_SHARED |
-                                          MAP_FIXED,
-                                          .fd  = phys_fd,
-                                          .offset= offset
-                                        } } } );
-               CATCH_EINTR(ret = write(fd, &map, sizeof(map)));
-               if (ret != sizeof(map)) {
-                       ret = -errno;
-                       printk(UM_KERN_ERR "map : /proc/mm map failed, "
-                              "err = %d\n", -ret);
-               }
-               else ret = 0;
-       }
-       else {
-               unsigned long args[] = { virt, len, prot,
-                                        MAP_SHARED | MAP_FIXED, phys_fd,
-                                        MMAP_OFFSET(offset) };
-
-               ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
-                                      data, done);
-       }
+       ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
+                              data, done);
 
        return ret;
 }
@@ -218,32 +185,11 @@ int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
          int done, void **data)
 {
        int ret;
+       unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+                                0 };
 
-       if (proc_mm) {
-               struct proc_mm_op unmap;
-               int fd = mm_idp->u.mm_fd;
-
-               unmap = ((struct proc_mm_op) { .op      = MM_MUNMAP,
-                                        .u     =
-                                        { .munmap      =
-                                          { .addr      =
-                                            (unsigned long) addr,
-                                            .len               = len } } } );
-               CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap)));
-               if (ret != sizeof(unmap)) {
-                       ret = -errno;
-                       printk(UM_KERN_ERR "unmap - proc_mm write returned "
-                              "%d\n", ret);
-               }
-               else ret = 0;
-       }
-       else {
-               unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
-                                        0 };
-
-               ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
-                                      data, done);
-       }
+       ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
+                              data, done);
 
        return ret;
 }
@@ -251,33 +197,11 @@ int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
 int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
            unsigned int prot, int done, void **data)
 {
-       struct proc_mm_op protect;
        int ret;
+       unsigned long args[] = { addr, len, prot, 0, 0, 0 };
 
-       if (proc_mm) {
-               int fd = mm_idp->u.mm_fd;
-
-               protect = ((struct proc_mm_op) { .op    = MM_MPROTECT,
-                                          .u   =
-                                          { .mprotect  =
-                                            { .addr    =
-                                              (unsigned long) addr,
-                                              .len     = len,
-                                              .prot    = prot } } } );
-
-               CATCH_EINTR(ret = write(fd, &protect, sizeof(protect)));
-               if (ret != sizeof(protect)) {
-                       ret = -errno;
-                       printk(UM_KERN_ERR "protect failed, err = %d", -ret);
-               }
-               else ret = 0;
-       }
-       else {
-               unsigned long args[] = { addr, len, prot, 0, 0, 0 };
-
-               ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
-                                      data, done);
-       }
+       ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
+                              data, done);
 
        return ret;
 }
index d531879a4617695e02df3c1550922cfede7ea4e3..452c214d86bf39f5aed3a5ab58678c9fb383617f 100644 (file)
 #include <kern_util.h>
 #include <mem.h>
 #include <os.h>
-#include <proc_mm.h>
 #include <ptrace_user.h>
 #include <registers.h>
 #include <skas.h>
-#include <skas_ptrace.h>
 #include <sysdep/stub.h>
 
 int is_skas_winch(int pid, int fd, void *data)
@@ -96,50 +94,33 @@ extern unsigned long current_stub_stack(void);
 static void get_skas_faultinfo(int pid, struct faultinfo *fi)
 {
        int err;
+       unsigned long fpregs[FP_SIZE];
 
-       if (ptrace_faultinfo) {
-               err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
-               if (err) {
-                       printk(UM_KERN_ERR "get_skas_faultinfo - "
-                              "PTRACE_FAULTINFO failed, errno = %d\n", errno);
-                       fatal_sigsegv();
-               }
-
-               /* Special handling for i386, which has different structs */
-               if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
-                       memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
-                              sizeof(struct faultinfo) -
-                              sizeof(struct ptrace_faultinfo));
+       err = get_fp_registers(pid, fpregs);
+       if (err < 0) {
+               printk(UM_KERN_ERR "save_fp_registers returned %d\n",
+                      err);
+               fatal_sigsegv();
        }
-       else {
-               unsigned long fpregs[FP_SIZE];
-
-               err = get_fp_registers(pid, fpregs);
-               if (err < 0) {
-                       printk(UM_KERN_ERR "save_fp_registers returned %d\n",
-                              err);
-                       fatal_sigsegv();
-               }
-               err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
-               if (err) {
-                       printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
-                              "errno = %d\n", pid, errno);
-                       fatal_sigsegv();
-               }
-               wait_stub_done(pid);
+       err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
+       if (err) {
+               printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
+                      "errno = %d\n", pid, errno);
+               fatal_sigsegv();
+       }
+       wait_stub_done(pid);
 
-               /*
-                * faultinfo is prepared by the stub-segv-handler at start of
-                * the stub stack page. We just have to copy it.
-                */
-               memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+       /*
+        * faultinfo is prepared by the stub-segv-handler at start of
+        * the stub stack page. We just have to copy it.
+        */
+       memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
 
-               err = put_fp_registers(pid, fpregs);
-               if (err < 0) {
-                       printk(UM_KERN_ERR "put_fp_registers returned %d\n",
-                              err);
-                       fatal_sigsegv();
-               }
+       err = put_fp_registers(pid, fpregs);
+       if (err < 0) {
+               printk(UM_KERN_ERR "put_fp_registers returned %d\n",
+                      err);
+               fatal_sigsegv();
        }
 }
 
@@ -203,7 +184,8 @@ extern int __syscall_stub_start;
 static int userspace_tramp(void *stack)
 {
        void *addr;
-       int err;
+       int err, fd;
+       unsigned long long offset;
 
        ptrace(PTRACE_TRACEME, 0, 0, 0);
 
@@ -216,36 +198,32 @@ static int userspace_tramp(void *stack)
                exit(1);
        }
 
-       if (!proc_mm) {
-               /*
-                * This has a pte, but it can't be mapped in with the usual
-                * tlb_flush mechanism because this is part of that mechanism
-                */
-               int fd;
-               unsigned long long offset;
-               fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
-               addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
-                             PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+       /*
+        * This has a pte, but it can't be mapped in with the usual
+        * tlb_flush mechanism because this is part of that mechanism
+        */
+       fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+       addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
+                     PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+       if (addr == MAP_FAILED) {
+               printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, "
+                      "errno = %d\n", STUB_CODE, errno);
+               exit(1);
+       }
+
+       if (stack != NULL) {
+               fd = phys_mapping(to_phys(stack), &offset);
+               addr = mmap((void *) STUB_DATA,
+                           UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
+                           MAP_FIXED | MAP_SHARED, fd, offset);
                if (addr == MAP_FAILED) {
-                       printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, "
-                              "errno = %d\n", STUB_CODE, errno);
+                       printk(UM_KERN_ERR "mapping segfault stack "
+                              "at 0x%lx failed, errno = %d\n",
+                              STUB_DATA, errno);
                        exit(1);
                }
-
-               if (stack != NULL) {
-                       fd = phys_mapping(to_phys(stack), &offset);
-                       addr = mmap((void *) STUB_DATA,
-                                   UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
-                                   MAP_FIXED | MAP_SHARED, fd, offset);
-                       if (addr == MAP_FAILED) {
-                               printk(UM_KERN_ERR "mapping segfault stack "
-                                      "at 0x%lx failed, errno = %d\n",
-                                      STUB_DATA, errno);
-                               exit(1);
-                       }
-               }
        }
-       if (!ptrace_faultinfo && (stack != NULL)) {
+       if (stack != NULL) {
                struct sigaction sa;
 
                unsigned long v = STUB_CODE +
@@ -291,11 +269,7 @@ int start_userspace(unsigned long stub_stack)
 
        sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
 
-       flags = CLONE_FILES;
-       if (proc_mm)
-               flags |= CLONE_VM;
-       else
-               flags |= SIGCHLD;
+       flags = CLONE_FILES | SIGCHLD;
 
        pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
        if (pid < 0) {
@@ -418,8 +392,7 @@ void userspace(struct uml_pt_regs *regs)
 
                        switch (sig) {
                        case SIGSEGV:
-                               if (PTRACE_FULL_FAULTINFO ||
-                                   !ptrace_faultinfo) {
+                               if (PTRACE_FULL_FAULTINFO) {
                                        get_skas_faultinfo(pid,
                                                           &regs->faultinfo);
                                        (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
@@ -576,67 +549,6 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        return err;
 }
 
-/*
- * This is used only, if stub pages are needed, while proc_mm is
- * available. Opening /proc/mm creates a new mm_context, which lacks
- * the stub-pages. Thus, we map them using /proc/mm-fd
- */
-int map_stub_pages(int fd, unsigned long code, unsigned long data,
-                  unsigned long stack)
-{
-       struct proc_mm_op mmop;
-       int n;
-       unsigned long long code_offset;
-       int code_fd = phys_mapping(to_phys((void *) &__syscall_stub_start),
-                                  &code_offset);
-
-       mmop = ((struct proc_mm_op) { .op        = MM_MMAP,
-                                     .u         =
-                                     { .mmap    =
-                                       { .addr    = code,
-                                         .len     = UM_KERN_PAGE_SIZE,
-                                         .prot    = PROT_EXEC,
-                                         .flags   = MAP_FIXED | MAP_PRIVATE,
-                                         .fd      = code_fd,
-                                         .offset  = code_offset
-       } } });
-       CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
-       if (n != sizeof(mmop)) {
-               n = errno;
-               printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, "
-                      "offset = %llx\n", code, code_fd,
-                      (unsigned long long) code_offset);
-               printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code "
-                      "failed, err = %d\n", n);
-               return -n;
-       }
-
-       if (stack) {
-               unsigned long long map_offset;
-               int map_fd = phys_mapping(to_phys((void *)stack), &map_offset);
-               mmop = ((struct proc_mm_op)
-                               { .op        = MM_MMAP,
-                                 .u         =
-                                 { .mmap    =
-                                   { .addr    = data,
-                                     .len     = UM_KERN_PAGE_SIZE,
-                                     .prot    = PROT_READ | PROT_WRITE,
-                                     .flags   = MAP_FIXED | MAP_SHARED,
-                                     .fd      = map_fd,
-                                     .offset  = map_offset
-               } } });
-               CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
-               if (n != sizeof(mmop)) {
-                       n = errno;
-                       printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for "
-                              "data failed, err = %d\n", n);
-                       return -n;
-               }
-       }
-
-       return 0;
-}
-
 void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
 {
        (*buf)[0].JB_IP = (unsigned long) handler;
@@ -733,17 +645,5 @@ void reboot_skas(void)
 
 void __switch_mm(struct mm_id *mm_idp)
 {
-       int err;
-
-       /* FIXME: need cpu pid in __switch_mm */
-       if (proc_mm) {
-               err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
-                            mm_idp->u.mm_fd);
-               if (err) {
-                       printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM "
-                              "failed, errno = %d\n", errno);
-                       fatal_sigsegv();
-               }
-       }
-       else userspace_pid[0] = mm_idp->u.pid;
+       userspace_pid[0] = mm_idp->u.pid;
 }
index 337518c5042a5cb4895e389202e6a4c5bc9654b2..47f1ff056a54fdc36657728cc3fe99dc5a7f9be0 100644 (file)
@@ -24,7 +24,6 @@
 #include <ptrace_user.h>
 #include <registers.h>
 #include <skas.h>
-#include <skas_ptrace.h>
 
 static void ptrace_child(void)
 {
@@ -142,44 +141,6 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit)
        return ret;
 }
 
-/* Changed only during early boot */
-int ptrace_faultinfo;
-static int disable_ptrace_faultinfo;
-
-int ptrace_ldt;
-static int disable_ptrace_ldt;
-
-int proc_mm;
-static int disable_proc_mm;
-
-int have_switch_mm;
-static int disable_switch_mm;
-
-int skas_needs_stub;
-
-static int __init skas0_cmd_param(char *str, int* add)
-{
-       disable_ptrace_faultinfo = 1;
-       disable_ptrace_ldt = 1;
-       disable_proc_mm = 1;
-       disable_switch_mm = 1;
-
-       return 0;
-}
-
-/* The two __uml_setup would conflict, without this stupid alias. */
-
-static int __init mode_skas0_cmd_param(char *str, int* add)
-       __attribute__((alias("skas0_cmd_param")));
-
-__uml_setup("skas0", skas0_cmd_param,
-"skas0\n"
-"    Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n");
-
-__uml_setup("mode=skas0", mode_skas0_cmd_param,
-"mode=skas0\n"
-"    Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n");
-
 /* Changed only during early boot */
 static int force_sysemu_disabled = 0;
 
@@ -376,121 +337,6 @@ void __init os_early_checks(void)
        stop_ptraced_child(pid, 1, 1);
 }
 
-static int __init noprocmm_cmd_param(char *str, int* add)
-{
-       disable_proc_mm = 1;
-       return 0;
-}
-
-__uml_setup("noprocmm", noprocmm_cmd_param,
-"noprocmm\n"
-"    Turns off usage of /proc/mm, even if host supports it.\n"
-"    To support /proc/mm, the host needs to be patched using\n"
-"    the current skas3 patch.\n\n");
-
-static int __init noptracefaultinfo_cmd_param(char *str, int* add)
-{
-       disable_ptrace_faultinfo = 1;
-       return 0;
-}
-
-__uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param,
-"noptracefaultinfo\n"
-"    Turns off usage of PTRACE_FAULTINFO, even if host supports\n"
-"    it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
-"    using the current skas3 patch.\n\n");
-
-static int __init noptraceldt_cmd_param(char *str, int* add)
-{
-       disable_ptrace_ldt = 1;
-       return 0;
-}
-
-__uml_setup("noptraceldt", noptraceldt_cmd_param,
-"noptraceldt\n"
-"    Turns off usage of PTRACE_LDT, even if host supports it.\n"
-"    To support PTRACE_LDT, the host needs to be patched using\n"
-"    the current skas3 patch.\n\n");
-
-static inline void check_skas3_ptrace_faultinfo(void)
-{
-       struct ptrace_faultinfo fi;
-       int pid, n;
-
-       non_fatal("  - PTRACE_FAULTINFO...");
-       pid = start_ptraced_child();
-
-       n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
-       if (n < 0) {
-               if (errno == EIO)
-                       non_fatal("not found\n");
-               else
-                       perror("not found");
-       } else if (disable_ptrace_faultinfo)
-               non_fatal("found but disabled on command line\n");
-       else {
-               ptrace_faultinfo = 1;
-               non_fatal("found\n");
-       }
-
-       stop_ptraced_child(pid, 1, 1);
-}
-
-static inline void check_skas3_ptrace_ldt(void)
-{
-#ifdef PTRACE_LDT
-       int pid, n;
-       unsigned char ldtbuf[40];
-       struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
-               .func = 2, /* read default ldt */
-               .ptr = ldtbuf,
-               .bytecount = sizeof(ldtbuf)};
-
-       non_fatal("  - PTRACE_LDT...");
-       pid = start_ptraced_child();
-
-       n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op);
-       if (n < 0) {
-               if (errno == EIO)
-                       non_fatal("not found\n");
-               else
-                       perror("not found");
-       } else if (disable_ptrace_ldt)
-               non_fatal("found, but use is disabled\n");
-       else {
-               ptrace_ldt = 1;
-               non_fatal("found\n");
-       }
-
-       stop_ptraced_child(pid, 1, 1);
-#endif
-}
-
-static inline void check_skas3_proc_mm(void)
-{
-       non_fatal("  - /proc/mm...");
-       if (access("/proc/mm", W_OK) < 0)
-               perror("not found");
-       else if (disable_proc_mm)
-               non_fatal("found but disabled on command line\n");
-       else {
-               proc_mm = 1;
-               non_fatal("found\n");
-       }
-}
-
-void can_do_skas(void)
-{
-       non_fatal("Checking for the skas3 patch in the host:\n");
-
-       check_skas3_proc_mm();
-       check_skas3_ptrace_faultinfo();
-       check_skas3_ptrace_ldt();
-
-       if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt)
-               skas_needs_stub = 1;
-}
-
 int __init parse_iomem(char *str, int *add)
 {
        struct iomem_region *new;
diff --git a/arch/um/sys-ia64/sysdep/skas_ptrace.h b/arch/um/sys-ia64/sysdep/skas_ptrace.h
deleted file mode 100644 (file)
index 25a38e7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SYSDEP_IA64_SKAS_PTRACE_H
-#define __SYSDEP_IA64_SKAS_PTRACE_H
-
-struct ptrace_faultinfo {
-        int is_write;
-        unsigned long addr;
-};
-
-struct ptrace_ldt {
-        int func;
-        void *ptr;
-        unsigned long bytecount;
-};
-
-#define PTRACE_LDT 54
-
-#endif
diff --git a/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h b/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h
deleted file mode 100644 (file)
index d9fbbac..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SYSDEP_PPC_SKAS_PTRACE_H
-#define __SYSDEP_PPC_SKAS_PTRACE_H
-
-struct ptrace_faultinfo {
-        int is_write;
-        unsigned long addr;
-};
-
-struct ptrace_ldt {
-        int func;
-        void *ptr;
-        unsigned long bytecount;
-};
-
-#define PTRACE_LDT 54
-
-#endif
index 25d2c6f7325e8d64133100d651661af713f6563a..895560b1fd246972ed23db2b30657413a29db4fe 100644 (file)
@@ -533,7 +533,7 @@ config X86_32_IRIS
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
-       prompt "Single-depth WCHAN output"
+       prompt "Single-depth WCHAN output" if !LTO && !FRAME_POINTER
        depends on X86
        ---help---
          Calculate simpler /proc/<PID>/wchan values. If this option
index d1b7c377a234e900b0af97d7a784e5cfeedd64f0..ce6ad7e6a7d7c7ba743884bbee2bcf77262f814d 100644 (file)
@@ -83,7 +83,9 @@ else
         KBUILD_CFLAGS += -m64
 
         # Don't autogenerate traditional x87, MMX or SSE instructions
-        KBUILD_CFLAGS += -mno-mmx -mno-sse -mno-80387 -mno-fp-ret-in-387
+        KBUILD_CFLAGS += -mno-mmx -mno-sse
+        KBUILD_CFLAGS += $(call cc-option,-mno-80387)
+        KBUILD_CFLAGS += $(call cc-option,-mno-fp-ret-in-387)
 
        # Use -mpreferred-stack-boundary=3 if supported.
        KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
index 185fad49d86f0c114411f4f4bc879bdbd9102874..5d1e0075ac24fa5eae975930647f6fc14c5b256d 100644 (file)
@@ -92,7 +92,7 @@ __clmul_gf128mul_ble:
        ret
 ENDPROC(__clmul_gf128mul_ble)
 
-/* void clmul_ghash_mul(char *dst, const be128 *shash) */
+/* void clmul_ghash_mul(char *dst, const u128 *shash) */
 ENTRY(clmul_ghash_mul)
        movups (%rdi), DATA
        movups (%rsi), SHASH
@@ -106,7 +106,7 @@ ENDPROC(clmul_ghash_mul)
 
 /*
  * void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
- *                        const be128 *shash);
+ *                        const u128 *shash);
  */
 ENTRY(clmul_ghash_update)
        cmp $16, %rdx
index d785cf2c529c720ae2bdfce7a592aae643aa71cf..88bb7ba8b1753e56b59c5a755e3cde4fefe5e78e 100644 (file)
 #define GHASH_BLOCK_SIZE       16
 #define GHASH_DIGEST_SIZE      16
 
-void clmul_ghash_mul(char *dst, const be128 *shash);
+void clmul_ghash_mul(char *dst, const u128 *shash);
 
 void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
-                       const be128 *shash);
+                       const u128 *shash);
 
 struct ghash_async_ctx {
        struct cryptd_ahash *cryptd_tfm;
 };
 
 struct ghash_ctx {
-       be128 shash;
+       u128 shash;
 };
 
 struct ghash_desc_ctx {
@@ -68,11 +68,11 @@ static int ghash_setkey(struct crypto_shash *tfm,
        a = be64_to_cpu(x->a);
        b = be64_to_cpu(x->b);
 
-       ctx->shash.a = (__be64)((b << 1) | (a >> 63));
-       ctx->shash.b = (__be64)((a << 1) | (b >> 63));
+       ctx->shash.a = (b << 1) | (a >> 63);
+       ctx->shash.b = (a << 1) | (b >> 63);
 
        if (a >> 63)
-               ctx->shash.b ^= cpu_to_be64(0xc2);
+               ctx->shash.b ^= ((u64)0xc2) << 56;
 
        return 0;
 }
index e6fd8a026c7be574e28d49d321d552d53c72b7cb..cd00e17744914c5b2e1d7d16da887a2809ebb5b5 100644 (file)
@@ -184,8 +184,15 @@ static inline unsigned add32_with_carry(unsigned a, unsigned b)
        asm("addl %2,%0\n\t"
            "adcl $0,%0"
            : "=r" (a)
-           : "0" (a), "r" (b));
+           : "0" (a), "rm" (b));
        return a;
 }
 
+#define HAVE_ARCH_CSUM_ADD
+static inline __wsum csum_add(__wsum csum, __wsum addend)
+{
+       return (__force __wsum)add32_with_carry((__force unsigned)csum,
+                                               (__force unsigned)addend);
+}
+
 #endif /* _ASM_X86_CHECKSUM_64_H */
index 6ad4658de7056e02f104b505f35910587ec712f3..d23aa82e7a7bc25c702be004f804a0c9d02c15f7 100644 (file)
@@ -3425,6 +3425,11 @@ int get_nr_irqs_gsi(void)
        return nr_irqs_gsi;
 }
 
+unsigned int arch_dynirq_lower_bound(unsigned int from)
+{
+       return from < nr_irqs_gsi ? nr_irqs_gsi : from;
+}
+
 int __init arch_probe_nr_irqs(void)
 {
        int nr;
index 7c87424d4140ee488eab90f8c4828a893a7744f6..619f7699487aa1ec60f5a2687bede8e19d0a2c7a 100644 (file)
@@ -543,7 +543,8 @@ static int rapl_cpu_prepare(int cpu)
        if (phys_id < 0)
                return -1;
 
-       if (!rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits))
+       /* protect rdmsrl() to handle virtualization */
+       if (rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits))
                return -1;
 
        pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
index f6584a90aba346566d38b6df763a9b0669fd733f..5edc34b5b9514df1f63af487a314ab4053d197a2 100644 (file)
@@ -26,6 +26,9 @@
 
 #define TOPOLOGY_REGISTER_OFFSET 0x10
 
+/* Flag below is initialized once during vSMP PCI initialization. */
+static int irq_routing_comply = 1;
+
 #if defined CONFIG_PCI && defined CONFIG_PARAVIRT
 /*
  * Interrupt control on vSMPowered systems:
@@ -101,6 +104,10 @@ static void __init set_vsmp_pv_ops(void)
 #ifdef CONFIG_SMP
        if (cap & ctl & BIT(8)) {
                ctl &= ~BIT(8);
+
+               /* Interrupt routing set to ignore */
+               irq_routing_comply = 0;
+
 #ifdef CONFIG_PROC_FS
                /* Don't let users change irq affinity via procfs */
                no_irq_affinity = 1;
@@ -218,7 +225,9 @@ static void vsmp_apic_post_init(void)
 {
        /* need to update phys_pkg_id */
        apic->phys_pkg_id = apicid_phys_pkg_id;
-       apic->vector_allocation_domain = fill_vector_allocation_domain;
+
+       if (!irq_routing_comply)
+               apic->vector_allocation_domain = fill_vector_allocation_domain;
 }
 
 void __init vsmp_init(void)
index 1f68c5831924d15dd741032cde2fafc46aae50ab..33e8c028842fb4b0b59bc269a973b195a104cdf8 100644 (file)
@@ -503,7 +503,7 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
                                [number##_HIGH] = VMCS12_OFFSET(name)+4
 
 
-static const unsigned long shadow_read_only_fields[] = {
+static unsigned long shadow_read_only_fields[] = {
        /*
         * We do NOT shadow fields that are modified when L0
         * traps and emulates any vmx instruction (e.g. VMPTRLD,
@@ -526,10 +526,10 @@ static const unsigned long shadow_read_only_fields[] = {
        GUEST_LINEAR_ADDRESS,
        GUEST_PHYSICAL_ADDRESS
 };
-static const int max_shadow_read_only_fields =
+static int max_shadow_read_only_fields =
        ARRAY_SIZE(shadow_read_only_fields);
 
-static const unsigned long shadow_read_write_fields[] = {
+static unsigned long shadow_read_write_fields[] = {
        GUEST_RIP,
        GUEST_RSP,
        GUEST_CR0,
@@ -558,7 +558,7 @@ static const unsigned long shadow_read_write_fields[] = {
        HOST_FS_SELECTOR,
        HOST_GS_SELECTOR
 };
-static const int max_shadow_read_write_fields =
+static int max_shadow_read_write_fields =
        ARRAY_SIZE(shadow_read_write_fields);
 
 static const unsigned short vmcs_field_to_offset_table[] = {
@@ -3009,6 +3009,41 @@ static void free_kvm_area(void)
        }
 }
 
+static void init_vmcs_shadow_fields(void)
+{
+       int i, j;
+
+       /* No checks for read only fields yet */
+
+       for (i = j = 0; i < max_shadow_read_write_fields; i++) {
+               switch (shadow_read_write_fields[i]) {
+               case GUEST_BNDCFGS:
+                       if (!vmx_mpx_supported())
+                               continue;
+                       break;
+               default:
+                       break;
+               }
+
+               if (j < i)
+                       shadow_read_write_fields[j] =
+                               shadow_read_write_fields[i];
+               j++;
+       }
+       max_shadow_read_write_fields = j;
+
+       /* shadowed fields guest access without vmexit */
+       for (i = 0; i < max_shadow_read_write_fields; i++) {
+               clear_bit(shadow_read_write_fields[i],
+                         vmx_vmwrite_bitmap);
+               clear_bit(shadow_read_write_fields[i],
+                         vmx_vmread_bitmap);
+       }
+       for (i = 0; i < max_shadow_read_only_fields; i++)
+               clear_bit(shadow_read_only_fields[i],
+                         vmx_vmread_bitmap);
+}
+
 static __init int alloc_kvm_area(void)
 {
        int cpu;
@@ -3039,6 +3074,8 @@ static __init int hardware_setup(void)
                enable_vpid = 0;
        if (!cpu_has_vmx_shadow_vmcs())
                enable_shadow_vmcs = 0;
+       if (enable_shadow_vmcs)
+               init_vmcs_shadow_fields();
 
        if (!cpu_has_vmx_ept() ||
            !cpu_has_vmx_ept_4levels()) {
@@ -8803,14 +8840,6 @@ static int __init vmx_init(void)
 
        memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
        memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
-       /* shadowed read/write fields */
-       for (i = 0; i < max_shadow_read_write_fields; i++) {
-               clear_bit(shadow_read_write_fields[i], vmx_vmwrite_bitmap);
-               clear_bit(shadow_read_write_fields[i], vmx_vmread_bitmap);
-       }
-       /* shadowed read only fields */
-       for (i = 0; i < max_shadow_read_only_fields; i++)
-               clear_bit(shadow_read_only_fields[i], vmx_vmread_bitmap);
 
        /*
         * Allow direct access to the PC debug port (it is often used for I/O
index 8e08176f0bcbeabf7ffc67403f3f73543b61d2a3..5c0b711d2433d3bb2f67e1f744917bc272bf37c9 100644 (file)
@@ -8,9 +8,7 @@
 #include <linux/slab.h>
 #include <asm/unistd.h>
 #include <os.h>
-#include <proc_mm.h>
 #include <skas.h>
-#include <skas_ptrace.h>
 #include <sysdep/tls.h>
 
 extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
@@ -19,105 +17,20 @@ static long write_ldt_entry(struct mm_id *mm_idp, int func,
                     struct user_desc *desc, void **addr, int done)
 {
        long res;
-
-       if (proc_mm) {
-               /*
-                * This is a special handling for the case, that the mm to
-                * modify isn't current->active_mm.
-                * If this is called directly by modify_ldt,
-                *     (current->active_mm->context.skas.u == mm_idp)
-                * will be true. So no call to __switch_mm(mm_idp) is done.
-                * If this is called in case of init_new_ldt or PTRACE_LDT,
-                * mm_idp won't belong to current->active_mm, but child->mm.
-                * So we need to switch child's mm into our userspace, then
-                * later switch back.
-                *
-                * Note: I'm unsure: should interrupts be disabled here?
-                */
-               if (!current->active_mm || current->active_mm == &init_mm ||
-                   mm_idp != &current->active_mm->context.id)
-                       __switch_mm(mm_idp);
-       }
-
-       if (ptrace_ldt) {
-               struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
-                       .func = func,
-                       .ptr = desc,
-                       .bytecount = sizeof(*desc)};
-               u32 cpu;
-               int pid;
-
-               if (!proc_mm)
-                       pid = mm_idp->u.pid;
-               else {
-                       cpu = get_cpu();
-                       pid = userspace_pid[cpu];
-               }
-
-               res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op);
-
-               if (proc_mm)
-                       put_cpu();
-       }
-       else {
-               void *stub_addr;
-               res = syscall_stub_data(mm_idp, (unsigned long *)desc,
-                                       (sizeof(*desc) + sizeof(long) - 1) &
-                                           ~(sizeof(long) - 1),
-                                       addr, &stub_addr);
-               if (!res) {
-                       unsigned long args[] = { func,
-                                                (unsigned long)stub_addr,
-                                                sizeof(*desc),
-                                                0, 0, 0 };
-                       res = run_syscall_stub(mm_idp, __NR_modify_ldt, args,
-                                              0, addr, done);
-               }
+       void *stub_addr;
+       res = syscall_stub_data(mm_idp, (unsigned long *)desc,
+                               (sizeof(*desc) + sizeof(long) - 1) &
+                                   ~(sizeof(long) - 1),
+                               addr, &stub_addr);
+       if (!res) {
+               unsigned long args[] = { func,
+                                        (unsigned long)stub_addr,
+                                        sizeof(*desc),
+                                        0, 0, 0 };
+               res = run_syscall_stub(mm_idp, __NR_modify_ldt, args,
+                                      0, addr, done);
        }
 
-       if (proc_mm) {
-               /*
-                * This is the second part of special handling, that makes
-                * PTRACE_LDT possible to implement.
-                */
-               if (current->active_mm && current->active_mm != &init_mm &&
-                   mm_idp != &current->active_mm->context.id)
-                       __switch_mm(&current->active_mm->context.id);
-       }
-
-       return res;
-}
-
-static long read_ldt_from_host(void __user * ptr, unsigned long bytecount)
-{
-       int res, n;
-       struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) {
-                       .func = 0,
-                       .bytecount = bytecount,
-                       .ptr = kmalloc(bytecount, GFP_KERNEL)};
-       u32 cpu;
-
-       if (ptrace_ldt.ptr == NULL)
-               return -ENOMEM;
-
-       /*
-        * This is called from sys_modify_ldt only, so userspace_pid gives
-        * us the right number
-        */
-
-       cpu = get_cpu();
-       res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt);
-       put_cpu();
-       if (res < 0)
-               goto out;
-
-       n = copy_to_user(ptr, ptrace_ldt.ptr, res);
-       if (n != 0)
-               res = -EFAULT;
-
-  out:
-       kfree(ptrace_ldt.ptr);
-
        return res;
 }
 
@@ -145,9 +58,6 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
                bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
        err = bytecount;
 
-       if (ptrace_ldt)
-               return read_ldt_from_host(ptr, bytecount);
-
        mutex_lock(&ldt->lock);
        if (ldt->entry_count <= LDT_DIRECT_ENTRIES) {
                size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES;
@@ -229,17 +139,11 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
                        goto out;
        }
 
-       if (!ptrace_ldt)
-               mutex_lock(&ldt->lock);
+       mutex_lock(&ldt->lock);
 
        err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1);
        if (err)
                goto out_unlock;
-       else if (ptrace_ldt) {
-               /* With PTRACE_LDT available, this is used as a flag only */
-               ldt->entry_count = 1;
-               goto out;
-       }
 
        if (ldt_info.entry_number >= ldt->entry_count &&
            ldt_info.entry_number >= LDT_DIRECT_ENTRIES) {
@@ -393,91 +297,56 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
        int i;
        long page, err=0;
        void *addr = NULL;
-       struct proc_mm_op copy;
 
 
-       if (!ptrace_ldt)
-               mutex_init(&new_mm->arch.ldt.lock);
+       mutex_init(&new_mm->arch.ldt.lock);
 
        if (!from_mm) {
                memset(&desc, 0, sizeof(desc));
                /*
-                * We have to initialize a clean ldt.
+                * Now we try to retrieve info about the ldt, we
+                * inherited from the host. All ldt-entries found
+                * will be reset in the following loop
                 */
-               if (proc_mm) {
-                       /*
-                        * If the new mm was created using proc_mm, host's
-                        * default-ldt currently is assigned, which normally
-                        * contains the call-gates for lcall7 and lcall27.
-                        * To remove these gates, we simply write an empty
-                        * entry as number 0 to the host.
-                        */
-                       err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1);
-               }
-               else{
-                       /*
-                        * Now we try to retrieve info about the ldt, we
-                        * inherited from the host. All ldt-entries found
-                        * will be reset in the following loop
-                        */
-                       ldt_get_host_info();
-                       for (num_p=host_ldt_entries; *num_p != -1; num_p++) {
-                               desc.entry_number = *num_p;
-                               err = write_ldt_entry(&new_mm->id, 1, &desc,
-                                                     &addr, *(num_p + 1) == -1);
-                               if (err)
-                                       break;
-                       }
+               ldt_get_host_info();
+               for (num_p=host_ldt_entries; *num_p != -1; num_p++) {
+                       desc.entry_number = *num_p;
+                       err = write_ldt_entry(&new_mm->id, 1, &desc,
+                                             &addr, *(num_p + 1) == -1);
+                       if (err)
+                               break;
                }
                new_mm->arch.ldt.entry_count = 0;
 
                goto out;
        }
 
-       if (proc_mm) {
-               /*
-                * We have a valid from_mm, so we now have to copy the LDT of
-                * from_mm to new_mm, because using proc_mm an new mm with
-                * an empty/default LDT was created in new_mm()
-                */
-               copy = ((struct proc_mm_op) { .op       = MM_COPY_SEGMENTS,
-                                             .u        =
-                                             { .copy_segments =
-                                                       from_mm->id.u.mm_fd } } );
-               i = os_write_file(new_mm->id.u.mm_fd, &copy, sizeof(copy));
-               if (i != sizeof(copy))
-                       printk(KERN_ERR "new_mm : /proc/mm copy_segments "
-                              "failed, err = %d\n", -i);
-       }
-
-       if (!ptrace_ldt) {
-               /*
-                * Our local LDT is used to supply the data for
-                * modify_ldt(READLDT), if PTRACE_LDT isn't available,
-                * i.e., we have to use the stub for modify_ldt, which
-                * can't handle the big read buffer of up to 64kB.
-                */
-               mutex_lock(&from_mm->arch.ldt.lock);
-               if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES)
-                       memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries,
-                              sizeof(new_mm->arch.ldt.u.entries));
-               else {
-                       i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE;
-                       while (i-->0) {
-                               page = __get_free_page(GFP_KERNEL|__GFP_ZERO);
-                               if (!page) {
-                                       err = -ENOMEM;
-                                       break;
-                               }
-                               new_mm->arch.ldt.u.pages[i] =
-                                       (struct ldt_entry *) page;
-                               memcpy(new_mm->arch.ldt.u.pages[i],
-                                      from_mm->arch.ldt.u.pages[i], PAGE_SIZE);
+       /*
+        * Our local LDT is used to supply the data for
+        * modify_ldt(READLDT), if PTRACE_LDT isn't available,
+        * i.e., we have to use the stub for modify_ldt, which
+        * can't handle the big read buffer of up to 64kB.
+        */
+       mutex_lock(&from_mm->arch.ldt.lock);
+       if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES)
+               memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries,
+                      sizeof(new_mm->arch.ldt.u.entries));
+       else {
+               i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE;
+               while (i-->0) {
+                       page = __get_free_page(GFP_KERNEL|__GFP_ZERO);
+                       if (!page) {
+                               err = -ENOMEM;
+                               break;
                        }
+                       new_mm->arch.ldt.u.pages[i] =
+                               (struct ldt_entry *) page;
+                       memcpy(new_mm->arch.ldt.u.pages[i],
+                              from_mm->arch.ldt.u.pages[i], PAGE_SIZE);
                }
-               new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count;
-               mutex_unlock(&from_mm->arch.ldt.lock);
        }
+       new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count;
+       mutex_unlock(&from_mm->arch.ldt.lock);
 
     out:
        return err;
@@ -488,7 +357,7 @@ void free_ldt(struct mm_context *mm)
 {
        int i;
 
-       if (!ptrace_ldt && mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) {
+       if (mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) {
                i = mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE;
                while (i-- > 0)
                        free_page((long) mm->arch.ldt.u.pages[i]);
index a26086b8a800223003cd30e9fe9df372470bfc7d..b6f2437ec29c7a882ca42bdb8bdc723cd445ef8c 100644 (file)
@@ -27,9 +27,6 @@ struct faultinfo {
 /* This is Page Fault */
 #define SEGV_IS_FIXABLE(fi)    ((fi)->trap_no == 14)
 
-/* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */
-#define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo)
-
 #define PTRACE_FULL_FAULTINFO 0
 
 #endif
index f811cbe15d623bdf287e7031737ee2a76dfc0538..ee88f88974ea0fffe13d1a4a0ab42c391e788a20 100644 (file)
@@ -27,9 +27,6 @@ struct faultinfo {
 /* This is Page Fault */
 #define SEGV_IS_FIXABLE(fi)    ((fi)->trap_no == 14)
 
-/* No broken SKAS API, which doesn't pass trap_no, here. */
-#define SEGV_MAYBE_FIXABLE(fi) 0
-
 #define PTRACE_FULL_FAULTINFO 1
 
 #endif
diff --git a/arch/x86/um/shared/sysdep/skas_ptrace.h b/arch/x86/um/shared/sysdep/skas_ptrace.h
deleted file mode 100644 (file)
index 453febe..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SYSDEP_X86_SKAS_PTRACE_H
-#define __SYSDEP_X86_SKAS_PTRACE_H
-
-struct ptrace_faultinfo {
-        int is_write;
-        unsigned long addr;
-};
-
-struct ptrace_ldt {
-        int func;
-        void *ptr;
-        unsigned long bytecount;
-};
-
-#define PTRACE_LDT 54
-
-#endif
index 02d6d29a63c13716168c0a68b4bdfe55c71ef9b0..3a617af60d465196bb894cebdc4042ccd4e4a92f 100644 (file)
@@ -14,6 +14,7 @@ config XTENSA
        select GENERIC_PCI_IOMAP
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
        select IRQ_DOMAIN
        select HAVE_OPROFILE
@@ -189,6 +190,24 @@ config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
 
          If in doubt, say Y.
 
+config HIGHMEM
+       bool "High Memory Support"
+       help
+         Linux can use the full amount of RAM in the system by
+         default. However, the default MMUv2 setup only maps the
+         lowermost 128 MB of memory linearly to the areas starting
+         at 0xd0000000 (cached) and 0xd8000000 (uncached).
+         When there are more than 128 MB memory in the system not
+         all of it can be "permanently mapped" by the kernel.
+         The physical memory that's not permanently mapped is called
+         "high memory".
+
+         If you are compiling a kernel which will never run on a
+         machine with more than 128 MB total physical RAM, answer
+         N here.
+
+         If unsure, say Y.
+
 endmenu
 
 config XTENSA_CALIBRATE_CCOUNT
@@ -224,7 +243,6 @@ choice
 
 config XTENSA_PLATFORM_ISS
        bool "ISS"
-       depends on TTY
        select XTENSA_CALIBRATE_CCOUNT
        select SERIAL_CONSOLE
        help
diff --git a/arch/xtensa/boot/dts/kc705.dts b/arch/xtensa/boot/dts/kc705.dts
new file mode 100644 (file)
index 0000000..742a347
--- /dev/null
@@ -0,0 +1,11 @@
+/dts-v1/;
+/include/ "xtfpga.dtsi"
+/include/ "xtfpga-flash-128m.dtsi"
+
+/ {
+       compatible = "cdns,xtensa-kc705";
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;
+       };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi
new file mode 100644 (file)
index 0000000..d3a88e0
--- /dev/null
@@ -0,0 +1,28 @@
+/ {
+       soc {
+               flash: flash@00000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x00000000 0x08000000>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       partition@0x0 {
+                               label = "data";
+                               reg = <0x00000000 0x06000000>;
+                       };
+                       partition@0x6000000 {
+                               label = "boot loader area";
+                               reg = <0x06000000 0x00800000>;
+                       };
+                       partition@0x6800000 {
+                               label = "kernel image";
+                               reg = <0x06800000 0x017e0000>;
+                       };
+                       partition@0x7fe0000 {
+                               label = "boot environment";
+                               reg = <0x07fe0000 0x00020000>;
+                       };
+               };
+        };
+};
index e5703c7beeb6dad04d2006929984b0fd8a7c3289..1d97203c18e7f787b5696b4468e4901c9b88fcbb 100644 (file)
@@ -1,26 +1,28 @@
 / {
-       flash: flash@f8000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "cfi-flash";
-               reg = <0xf8000000 0x01000000>;
-               bank-width = <2>;
-               device-width = <2>;
-               partition@0x0 {
-                       label = "boot loader area";
-                       reg = <0x00000000 0x00400000>;
+       soc {
+               flash: flash@08000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x08000000 0x01000000>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       partition@0x0 {
+                               label = "boot loader area";
+                               reg = <0x00000000 0x00400000>;
+                       };
+                       partition@0x400000 {
+                               label = "kernel image";
+                               reg = <0x00400000 0x00600000>;
+                       };
+                       partition@0xa00000 {
+                               label = "data";
+                               reg = <0x00a00000 0x005e0000>;
+                       };
+                       partition@0xfe0000 {
+                               label = "boot environment";
+                               reg = <0x00fe0000 0x00020000>;
+                       };
                };
-               partition@0x400000 {
-                       label = "kernel image";
-                       reg = <0x00400000 0x00600000>;
-               };
-               partition@0xa00000 {
-                       label = "data";
-                       reg = <0x00a00000 0x005e0000>;
-               };
-               partition@0xfe0000 {
-                       label = "boot environment";
-                       reg = <0x00fe0000 0x00020000>;
-               };
-        };
+       };
 };
index 6f9c10d6b689a9696d17296025a21a1167322fbc..d1c621ca8be10cba5565fa9ce1e7b82cabaef973 100644 (file)
@@ -1,18 +1,20 @@
 / {
-       flash: flash@f8000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "cfi-flash";
-               reg = <0xf8000000 0x00400000>;
-               bank-width = <2>;
-               device-width = <2>;
-               partition@0x0 {
-                       label = "boot loader area";
-                       reg = <0x00000000 0x003f0000>;
+       soc {
+               flash: flash@08000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x08000000 0x00400000>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       partition@0x0 {
+                               label = "boot loader area";
+                               reg = <0x00000000 0x003f0000>;
+                       };
+                       partition@0x3f0000 {
+                               label = "boot environment";
+                               reg = <0x003f0000 0x00010000>;
+                       };
                };
-               partition@0x3f0000 {
-                       label = "boot environment";
-                       reg = <0x003f0000 0x00010000>;
-               };
-        };
+       };
 };
index e7370b11348e8d06c113d420704664740dbdec9b..dec9178840f695f0bcdd1de3cd5b17339fce8627 100644 (file)
                };
        };
 
-       serial0: serial@fd050020 {
-               device_type = "serial";
-               compatible = "ns16550a";
-               no-loopback-test;
-               reg = <0xfd050020 0x20>;
-               reg-shift = <2>;
-               interrupts = <0 1>; /* external irq 0 */
-               clocks = <&osc>;
-       };
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               ranges = <0x00000000 0xf0000000 0x10000000>;
 
-       enet0: ethoc@fd030000 {
-               compatible = "opencores,ethoc";
-               reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
-               interrupts = <1 1>; /* external irq 1 */
-               local-mac-address = [00 50 c2 13 6f 00];
-               clocks = <&osc>;
+               serial0: serial@0d050020 {
+                       device_type = "serial";
+                       compatible = "ns16550a";
+                       no-loopback-test;
+                       reg = <0x0d050020 0x20>;
+                       reg-shift = <2>;
+                       interrupts = <0 1>; /* external irq 0 */
+                       clocks = <&osc>;
+               };
+
+               enet0: ethoc@0d030000 {
+                       compatible = "opencores,ethoc";
+                       reg = <0x0d030000 0x4000 0x0d800000 0x4000>;
+                       interrupts = <1 1>; /* external irq 1 */
+                       local-mac-address = [00 50 c2 13 6f 00];
+                       clocks = <&osc>;
+               };
        };
 };
index 23392c5630ce9939b04bae3ff6de4fd67417852a..892aab399ac873c885953e24430a3bc741aca6ed 100644 (file)
@@ -37,23 +37,14 @@ typedef struct bp_tag {
        unsigned long data[0];  /* data */
 } bp_tag_t;
 
-typedef struct meminfo {
+struct bp_meminfo {
        unsigned long type;
        unsigned long start;
        unsigned long end;
-} meminfo_t;
-
-#define SYSMEM_BANKS_MAX 5
+};
 
 #define MEMORY_TYPE_CONVENTIONAL       0x1000
 #define MEMORY_TYPE_NONE               0x2000
 
-typedef struct sysmem_info {
-       int nr_banks;
-       meminfo_t bank[SYSMEM_BANKS_MAX];
-} sysmem_info_t;
-
-extern sysmem_info_t sysmem;
-
 #endif
 #endif
diff --git a/arch/xtensa/include/asm/fixmap.h b/arch/xtensa/include/asm/fixmap.h
new file mode 100644 (file)
index 0000000..9f6c33d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * 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) 1998 Ingo Molnar
+ *
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#include <asm/pgtable.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special  addresses
+ * from the end of the consistent memory region backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * higher than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ */
+enum fixed_addresses {
+#ifdef CONFIG_HIGHMEM
+       /* reserved pte's for temporary kernel mappings */
+       FIX_KMAP_BEGIN,
+       FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
+#endif
+       __end_of_fixed_addresses
+};
+
+#define FIXADDR_TOP     (VMALLOC_START - PAGE_SIZE)
+#define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START  ((FIXADDR_TOP - FIXADDR_SIZE) & PMD_MASK)
+
+#include <asm-generic/fixmap.h>
+
+#define kmap_get_fixmap_pte(vaddr) \
+       pte_offset_kernel( \
+               pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), \
+               (vaddr) \
+       )
+
+#endif
index 80be15124697d8e85a23859a466e97f178936010..2653ef5d55f1c9ed92d35d50f91136732334ec1b 100644 (file)
@@ -6,11 +6,54 @@
  * this archive for more details.
  *
  * Copyright (C) 2003 - 2005 Tensilica Inc.
+ * Copyright (C) 2014 Cadence Design Systems Inc.
  */
 
 #ifndef _XTENSA_HIGHMEM_H
 #define _XTENSA_HIGHMEM_H
 
-extern void flush_cache_kmaps(void);
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+#include <asm/kmap_types.h>
+#include <asm/pgtable.h>
+
+#define PKMAP_BASE             (FIXADDR_START - PMD_SIZE)
+#define LAST_PKMAP             PTRS_PER_PTE
+#define LAST_PKMAP_MASK                (LAST_PKMAP - 1)
+#define PKMAP_NR(virt)         (((virt) - PKMAP_BASE) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr)         (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+
+#define kmap_prot              PAGE_KERNEL
+
+extern pte_t *pkmap_page_table;
+
+void *kmap_high(struct page *page);
+void kunmap_high(struct page *page);
+
+static inline void *kmap(struct page *page)
+{
+       BUG_ON(in_interrupt());
+       if (!PageHighMem(page))
+               return page_address(page);
+       return kmap_high(page);
+}
+
+static inline void kunmap(struct page *page)
+{
+       BUG_ON(in_interrupt());
+       if (!PageHighMem(page))
+               return;
+       kunmap_high(page);
+}
+
+static inline void flush_cache_kmaps(void)
+{
+       flush_cache_all();
+}
+
+void *kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+
+void kmap_init(void);
 
 #endif
index 216446295ada686ccb4b454319b2b45e85d96720..4b0ca35a93b1a731bf0ce2c1db32f9fabb890fef 100644 (file)
@@ -310,6 +310,10 @@ set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval)
        update_pte(ptep, pteval);
 }
 
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+       update_pte(ptep, pteval);
+}
 
 static inline void
 set_pmd(pmd_t *pmdp, pmd_t pmdval)
diff --git a/arch/xtensa/include/asm/sysmem.h b/arch/xtensa/include/asm/sysmem.h
new file mode 100644 (file)
index 0000000..c015c5c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * sysmem-related prototypes.
+ *
+ * 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) 2014 Cadence Design Systems Inc.
+ */
+
+#ifndef _XTENSA_SYSMEM_H
+#define _XTENSA_SYSMEM_H
+
+#define SYSMEM_BANKS_MAX 31
+
+struct meminfo {
+       unsigned long start;
+       unsigned long end;
+};
+
+/*
+ * Bank array is sorted by .start.
+ * Banks don't overlap and there's at least one page gap
+ * between adjacent bank entries.
+ */
+struct sysmem_info {
+       int nr_banks;
+       struct meminfo bank[SYSMEM_BANKS_MAX];
+};
+
+extern struct sysmem_info sysmem;
+
+int add_sysmem_bank(unsigned long start, unsigned long end);
+int mem_reserve(unsigned long, unsigned long, int);
+void bootmem_init(void);
+void zones_init(void);
+
+#endif /* _XTENSA_SYSMEM_H */
index fc34274ce41bc81b3ddaa167fe887179f04c8ad7..06875feb27c28ebb870820706dc286cd9740f1ce 100644 (file)
@@ -36,6 +36,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma,
                unsigned long page);
 void local_flush_tlb_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end);
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
 #ifdef CONFIG_SMP
 
@@ -44,12 +45,7 @@ void flush_tlb_mm(struct mm_struct *);
 void flush_tlb_page(struct vm_area_struct *, unsigned long);
 void flush_tlb_range(struct vm_area_struct *, unsigned long,
                unsigned long);
-
-static inline void flush_tlb_kernel_range(unsigned long start,
-               unsigned long end)
-{
-       flush_tlb_all();
-}
+void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
 #else /* !CONFIG_SMP */
 
@@ -58,7 +54,8 @@ static inline void flush_tlb_kernel_range(unsigned long start,
 #define flush_tlb_page(vma, page)         local_flush_tlb_page(vma, page)
 #define flush_tlb_range(vma, vmaddr, end)  local_flush_tlb_range(vma, vmaddr, \
                                                                 end)
-#define flush_tlb_kernel_range(start, end) local_flush_tlb_all()
+#define flush_tlb_kernel_range(start, end) local_flush_tlb_kernel_range(start, \
+                                                                       end)
 
 #endif /* CONFIG_SMP */
 
index 84fe931bb60e1f012417d202d002813b12cf68aa..9757bb74e53296f66372dd08506d94163e8801cc 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/param.h>
 #include <asm/traps.h>
 #include <asm/smp.h>
+#include <asm/sysmem.h>
 
 #include <platform/hardware.h>
 
@@ -88,12 +89,6 @@ static char __initdata command_line[COMMAND_LINE_SIZE];
 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
 #endif
 
-sysmem_info_t __initdata sysmem;
-
-extern int mem_reserve(unsigned long, unsigned long, int);
-extern void bootmem_init(void);
-extern void zones_init(void);
-
 /*
  * Boot parameter parsing.
  *
@@ -113,31 +108,14 @@ typedef struct tagtable {
 
 /* parse current tag */
 
-static int __init add_sysmem_bank(unsigned long type, unsigned long start,
-               unsigned long end)
-{
-       if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
-               printk(KERN_WARNING
-                               "Ignoring memory bank 0x%08lx size %ldKB\n",
-                               start, end - start);
-               return -EINVAL;
-       }
-       sysmem.bank[sysmem.nr_banks].type  = type;
-       sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
-       sysmem.bank[sysmem.nr_banks].end   = end & PAGE_MASK;
-       sysmem.nr_banks++;
-
-       return 0;
-}
-
 static int __init parse_tag_mem(const bp_tag_t *tag)
 {
-       meminfo_t *mi = (meminfo_t *)(tag->data);
+       struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data);
 
        if (mi->type != MEMORY_TYPE_CONVENTIONAL)
                return -1;
 
-       return add_sysmem_bank(mi->type, mi->start, mi->end);
+       return add_sysmem_bank(mi->start, mi->end);
 }
 
 __tagtable(BP_TAG_MEMORY, parse_tag_mem);
@@ -146,8 +124,8 @@ __tagtable(BP_TAG_MEMORY, parse_tag_mem);
 
 static int __init parse_tag_initrd(const bp_tag_t* tag)
 {
-       meminfo_t* mi;
-       mi = (meminfo_t*)(tag->data);
+       struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data);
+
        initrd_start = (unsigned long)__va(mi->start);
        initrd_end = (unsigned long)__va(mi->end);
 
@@ -255,7 +233,7 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
                return;
 
        size &= PAGE_MASK;
-       add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
+       add_sysmem_bank(base, base + size);
 }
 
 void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
@@ -292,8 +270,6 @@ device_initcall(xtensa_device_probe);
 
 void __init init_arch(bp_tag_t *bp_start)
 {
-       sysmem.nr_banks = 0;
-
        /* Parse boot parameters */
 
        if (bp_start)
@@ -304,10 +280,9 @@ void __init init_arch(bp_tag_t *bp_start)
 #endif
 
        if (sysmem.nr_banks == 0) {
-               sysmem.nr_banks = 1;
-               sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
-               sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
-                                    + PLATFORM_DEFAULT_MEM_SIZE;
+               add_sysmem_bank(PLATFORM_DEFAULT_MEM_START,
+                               PLATFORM_DEFAULT_MEM_START +
+                               PLATFORM_DEFAULT_MEM_SIZE);
        }
 
 #ifdef CONFIG_CMDLINE_BOOL
@@ -487,7 +462,7 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start < initrd_end) {
                initrd_is_mapped = mem_reserve(__pa(initrd_start),
-                                              __pa(initrd_end), 0);
+                                              __pa(initrd_end), 0) == 0;
                initrd_below_start_ok = 1;
        } else {
                initrd_start = 0;
@@ -532,6 +507,7 @@ void __init setup_arch(char **cmdline_p)
                    __pa(&_Level6InterruptVector_text_end), 0);
 #endif
 
+       parse_early_param();
        bootmem_init();
 
        unflatten_and_copy_device_tree();
index aa8bd8717927185bd5b422316885ddaa98d889f7..40b5a3771fb063fb02ffaa7fe07a426a3a684677 100644 (file)
@@ -496,6 +496,21 @@ void flush_tlb_range(struct vm_area_struct *vma,
        on_each_cpu(ipi_flush_tlb_range, &fd, 1);
 }
 
+static void ipi_flush_tlb_kernel_range(void *arg)
+{
+       struct flush_data *fd = arg;
+       local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       struct flush_data fd = {
+               .addr1 = start,
+               .addr2 = end,
+       };
+       on_each_cpu(ipi_flush_tlb_kernel_range, &fd, 1);
+}
+
 /* Cache flush functions */
 
 static void ipi_flush_cache_all(void *arg)
index 80b33ed51f31174fd41a53bebd957c140517d8f9..4d2872fd9bb5ebf89bb15127841e5ae28e8d9b58 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/in6.h>
 
 #include <asm/uaccess.h>
+#include <asm/cacheflush.h>
 #include <asm/checksum.h>
 #include <asm/dma.h>
 #include <asm/io.h>
@@ -105,6 +106,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
  * Architecture-specific symbols
  */
 EXPORT_SYMBOL(__xtensa_copy_user);
+EXPORT_SYMBOL(__invalidate_icache_range);
 
 /*
  * Kernel hacking ...
@@ -127,3 +129,8 @@ EXPORT_SYMBOL(common_exception_return);
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
 #endif
+
+EXPORT_SYMBOL(__invalidate_dcache_range);
+#if XCHAL_DCACHE_IS_WRITEBACK
+EXPORT_SYMBOL(__flush_dcache_range);
+#endif
index f0b646d2f843feb5945601dbe65966a4a71cfec9..f54f78e24d7b5e72733f23da806272a4cba6b882 100644 (file)
@@ -4,3 +4,4 @@
 
 obj-y                  := init.o cache.o misc.o
 obj-$(CONFIG_MMU)      += fault.o mmu.o tlb.o
+obj-$(CONFIG_HIGHMEM)  += highmem.o
index ba4c47f291b17843047a410549b09cb59ba52967..63cbb867dadd64d8907176f1bd60420f8a41217a 100644 (file)
  *
  */
 
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && defined(CONFIG_HIGHMEM)
+#error "HIGHMEM is not supported on cores with aliasing cache."
+#endif
+
 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
 
 /*
@@ -179,10 +183,11 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 #else
        if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
            && (vma->vm_flags & VM_EXEC) != 0) {
-               unsigned long paddr = (unsigned long) page_address(page);
+               unsigned long paddr = (unsigned long)kmap_atomic(page);
                __flush_dcache_page(paddr);
                __invalidate_icache_page(paddr);
                set_bit(PG_arch_1, &page->flags);
+               kunmap_atomic((void *)paddr);
        }
 #endif
 }
diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c
new file mode 100644 (file)
index 0000000..17a8c0d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * High memory support for Xtensa architecture
+ *
+ * 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) 2014 Cadence Design Systems Inc.
+ */
+
+#include <linux/export.h>
+#include <linux/highmem.h>
+#include <asm/tlbflush.h>
+
+static pte_t *kmap_pte;
+
+void *kmap_atomic(struct page *page)
+{
+       enum fixed_addresses idx;
+       unsigned long vaddr;
+       int type;
+
+       pagefault_disable();
+       if (!PageHighMem(page))
+               return page_address(page);
+
+       type = kmap_atomic_idx_push();
+       idx = type + KM_TYPE_NR * smp_processor_id();
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+       BUG_ON(!pte_none(*(kmap_pte - idx)));
+#endif
+       set_pte(kmap_pte - idx, mk_pte(page, PAGE_KERNEL_EXEC));
+
+       return (void *)vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic);
+
+void __kunmap_atomic(void *kvaddr)
+{
+       int idx, type;
+
+       if (kvaddr >= (void *)FIXADDR_START &&
+           kvaddr < (void *)FIXADDR_TOP) {
+               type = kmap_atomic_idx();
+               idx = type + KM_TYPE_NR * smp_processor_id();
+
+               /*
+                * Force other mappings to Oops if they'll try to access this
+                * pte without first remap it.  Keeping stale mappings around
+                * is a bad idea also, in case the page changes cacheability
+                * attributes or becomes a protected page in a hypervisor.
+                */
+               pte_clear(&init_mm, kvaddr, kmap_pte - idx);
+               local_flush_tlb_kernel_range((unsigned long)kvaddr,
+                                            (unsigned long)kvaddr + PAGE_SIZE);
+
+               kmap_atomic_idx_pop();
+       }
+
+       pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
+
+void __init kmap_init(void)
+{
+       unsigned long kmap_vstart;
+
+       /* cache the first kmap pte */
+       kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+       kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+}
index aff108df92d3a301e8ba0ccaf7e13a5fb26c9038..4224256bb215f17c52d91662f186ecb250dee361 100644 (file)
@@ -8,6 +8,7 @@
  * for more details.
  *
  * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2014 Cadence Design Systems Inc.
  *
  * Chris Zankel        <chris@zankel.net>
  * Joe Taylor  <joe@tensilica.com, joetylr@yahoo.com>
@@ -19,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/bootmem.h>
 #include <linux/gfp.h>
+#include <linux/highmem.h>
 #include <linux/swap.h>
 #include <linux/mman.h>
 #include <linux/nodemask.h>
 #include <asm/bootparam.h>
 #include <asm/page.h>
 #include <asm/sections.h>
+#include <asm/sysmem.h>
+
+struct sysmem_info sysmem __initdata;
+
+static void __init sysmem_dump(void)
+{
+       unsigned i;
+
+       pr_debug("Sysmem:\n");
+       for (i = 0; i < sysmem.nr_banks; ++i)
+               pr_debug("  0x%08lx - 0x%08lx (%ldK)\n",
+                        sysmem.bank[i].start, sysmem.bank[i].end,
+                        (sysmem.bank[i].end - sysmem.bank[i].start) >> 10);
+}
+
+/*
+ * Find bank with maximal .start such that bank.start <= start
+ */
+static inline struct meminfo * __init find_bank(unsigned long start)
+{
+       unsigned i;
+       struct meminfo *it = NULL;
+
+       for (i = 0; i < sysmem.nr_banks; ++i)
+               if (sysmem.bank[i].start <= start)
+                       it = sysmem.bank + i;
+               else
+                       break;
+       return it;
+}
+
+/*
+ * Move all memory banks starting at 'from' to a new place at 'to',
+ * adjust nr_banks accordingly.
+ * Both 'from' and 'to' must be inside the sysmem.bank.
+ *
+ * Returns: 0 (success), -ENOMEM (not enough space in the sysmem.bank).
+ */
+static int __init move_banks(struct meminfo *to, struct meminfo *from)
+{
+       unsigned n = sysmem.nr_banks - (from - sysmem.bank);
+
+       if (to > from && to - from + sysmem.nr_banks > SYSMEM_BANKS_MAX)
+               return -ENOMEM;
+       if (to != from)
+               memmove(to, from, n * sizeof(struct meminfo));
+       sysmem.nr_banks += to - from;
+       return 0;
+}
+
+/*
+ * Add new bank to sysmem. Resulting sysmem is the union of bytes of the
+ * original sysmem and the new bank.
+ *
+ * Returns: 0 (success), < 0 (error)
+ */
+int __init add_sysmem_bank(unsigned long start, unsigned long end)
+{
+       unsigned i;
+       struct meminfo *it = NULL;
+       unsigned long sz;
+       unsigned long bank_sz = 0;
+
+       if (start == end ||
+           (start < end) != (PAGE_ALIGN(start) < (end & PAGE_MASK))) {
+               pr_warn("Ignoring small memory bank 0x%08lx size: %ld bytes\n",
+                       start, end - start);
+               return -EINVAL;
+       }
+
+       start = PAGE_ALIGN(start);
+       end &= PAGE_MASK;
+       sz = end - start;
+
+       it = find_bank(start);
+
+       if (it)
+               bank_sz = it->end - it->start;
+
+       if (it && bank_sz >= start - it->start) {
+               if (end - it->start > bank_sz)
+                       it->end = end;
+               else
+                       return 0;
+       } else {
+               if (!it)
+                       it = sysmem.bank;
+               else
+                       ++it;
+
+               if (it - sysmem.bank < sysmem.nr_banks &&
+                   it->start - start <= sz) {
+                       it->start = start;
+                       if (it->end - it->start < sz)
+                               it->end = end;
+                       else
+                               return 0;
+               } else {
+                       if (move_banks(it + 1, it) < 0) {
+                               pr_warn("Ignoring memory bank 0x%08lx size %ld bytes\n",
+                                       start, end - start);
+                               return -EINVAL;
+                       }
+                       it->start = start;
+                       it->end = end;
+                       return 0;
+               }
+       }
+       sz = it->end - it->start;
+       for (i = it + 1 - sysmem.bank; i < sysmem.nr_banks; ++i)
+               if (sysmem.bank[i].start - it->start <= sz) {
+                       if (sz < sysmem.bank[i].end - it->start)
+                               it->end = sysmem.bank[i].end;
+               } else {
+                       break;
+               }
+
+       move_banks(it + 1, sysmem.bank + i);
+       return 0;
+}
 
 /*
  * mem_reserve(start, end, must_exist)
  *
  * Reserve some memory from the memory pool.
+ * If must_exist is set and a part of the region being reserved does not exist
+ * memory map is not altered.
  *
  * Parameters:
  *  start      Start of region,
  *  must_exist Must exist in memory pool.
  *
  * Returns:
- *  0 (memory area couldn't be mapped)
- * -1 (success)
+ *  0 (success)
+ *  < 0 (error)
  */
 
 int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
 {
-       int i;
-
-       if (start == end)
-               return 0;
+       struct meminfo *it;
+       struct meminfo *rm = NULL;
+       unsigned long sz;
+       unsigned long bank_sz = 0;
 
        start = start & PAGE_MASK;
        end = PAGE_ALIGN(end);
+       sz = end - start;
+       if (!sz)
+               return -EINVAL;
 
-       for (i = 0; i < sysmem.nr_banks; i++)
-               if (start < sysmem.bank[i].end
-                   && end >= sysmem.bank[i].start)
-                       break;
+       it = find_bank(start);
+
+       if (it)
+               bank_sz = it->end - it->start;
 
-       if (i == sysmem.nr_banks) {
-               if (must_exist)
-                       printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) "
-                               "not in any region!\n", start, end);
-               return 0;
+       if ((!it || end - it->start > bank_sz) && must_exist) {
+               pr_warn("mem_reserve: [0x%0lx, 0x%0lx) not in any region!\n",
+                       start, end);
+               return -EINVAL;
        }
 
-       if (start > sysmem.bank[i].start) {
-               if (end < sysmem.bank[i].end) {
-                       /* split entry */
-                       if (sysmem.nr_banks >= SYSMEM_BANKS_MAX)
-                               panic("meminfo overflow\n");
-                       sysmem.bank[sysmem.nr_banks].start = end;
-                       sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end;
-                       sysmem.nr_banks++;
+       if (it && start - it->start < bank_sz) {
+               if (start == it->start) {
+                       if (end - it->start < bank_sz) {
+                               it->start = end;
+                               return 0;
+                       } else {
+                               rm = it;
+                       }
+               } else {
+                       it->end = start;
+                       if (end - it->start < bank_sz)
+                               return add_sysmem_bank(end,
+                                                      it->start + bank_sz);
+                       ++it;
                }
-               sysmem.bank[i].end = start;
+       }
 
-       } else if (end < sysmem.bank[i].end) {
-               sysmem.bank[i].start = end;
+       if (!it)
+               it = sysmem.bank;
 
-       } else {
-               /* remove entry */
-               sysmem.nr_banks--;
-               sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
-               sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
+       for (; it < sysmem.bank + sysmem.nr_banks; ++it) {
+               if (it->end - start <= sz) {
+                       if (!rm)
+                               rm = it;
+               } else {
+                       if (it->start - start < sz)
+                               it->start = end;
+                       break;
+               }
        }
-       return -1;
+
+       if (rm)
+               move_banks(rm, it);
+
+       return 0;
 }
 
 
@@ -99,6 +239,7 @@ void __init bootmem_init(void)
        unsigned long bootmap_start, bootmap_size;
        int i;
 
+       sysmem_dump();
        max_low_pfn = max_pfn = 0;
        min_low_pfn = ~0;
 
@@ -156,19 +297,13 @@ void __init bootmem_init(void)
 
 void __init zones_init(void)
 {
-       unsigned long zones_size[MAX_NR_ZONES];
-       int i;
-
        /* All pages are DMA-able, so we put them all in the DMA zone. */
-
-       zones_size[ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET;
-       for (i = 1; i < MAX_NR_ZONES; i++)
-               zones_size[i] = 0;
-
+       unsigned long zones_size[MAX_NR_ZONES] = {
+               [ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET,
 #ifdef CONFIG_HIGHMEM
-       zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
+               [ZONE_HIGHMEM] = max_pfn - max_low_pfn,
 #endif
-
+       };
        free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
 }
 
@@ -178,16 +313,38 @@ void __init zones_init(void)
 
 void __init mem_init(void)
 {
-       max_mapnr = max_low_pfn - ARCH_PFN_OFFSET;
-       high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-
 #ifdef CONFIG_HIGHMEM
-#error HIGHGMEM not implemented in init.c
+       unsigned long tmp;
+
+       reset_all_zones_managed_pages();
+       for (tmp = max_low_pfn; tmp < max_pfn; tmp++)
+               free_highmem_page(pfn_to_page(tmp));
 #endif
 
+       max_mapnr = max_pfn - ARCH_PFN_OFFSET;
+       high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
+
        free_all_bootmem();
 
        mem_init_print_info(NULL);
+       pr_info("virtual kernel memory layout:\n"
+#ifdef CONFIG_HIGHMEM
+               "    pkmap   : 0x%08lx - 0x%08lx  (%5lu kB)\n"
+               "    fixmap  : 0x%08lx - 0x%08lx  (%5lu kB)\n"
+#endif
+               "    vmalloc : 0x%08x - 0x%08x  (%5u MB)\n"
+               "    lowmem  : 0x%08x - 0x%08lx  (%5lu MB)\n",
+#ifdef CONFIG_HIGHMEM
+               PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE,
+               (LAST_PKMAP*PAGE_SIZE) >> 10,
+               FIXADDR_START, FIXADDR_TOP,
+               (FIXADDR_TOP - FIXADDR_START) >> 10,
+#endif
+               VMALLOC_START, VMALLOC_END,
+               (VMALLOC_END - VMALLOC_START) >> 20,
+               PAGE_OFFSET, PAGE_OFFSET +
+               (max_low_pfn - min_low_pfn) * PAGE_SIZE,
+               ((max_low_pfn - min_low_pfn) * PAGE_SIZE) >> 20);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -204,3 +361,53 @@ void free_initmem(void)
 {
        free_initmem_default(-1);
 }
+
+static void __init parse_memmap_one(char *p)
+{
+       char *oldp;
+       unsigned long start_at, mem_size;
+
+       if (!p)
+               return;
+
+       oldp = p;
+       mem_size = memparse(p, &p);
+       if (p == oldp)
+               return;
+
+       switch (*p) {
+       case '@':
+               start_at = memparse(p + 1, &p);
+               add_sysmem_bank(start_at, start_at + mem_size);
+               break;
+
+       case '$':
+               start_at = memparse(p + 1, &p);
+               mem_reserve(start_at, start_at + mem_size, 0);
+               break;
+
+       case 0:
+               mem_reserve(mem_size, 0, 0);
+               break;
+
+       default:
+               pr_warn("Unrecognized memmap syntax: %s\n", p);
+               break;
+       }
+}
+
+static int __init parse_memmap_opt(char *str)
+{
+       while (str) {
+               char *k = strchr(str, ',');
+
+               if (k)
+                       *k++ = 0;
+
+               parse_memmap_one(str);
+               str = k;
+       }
+
+       return 0;
+}
+early_param("memmap", parse_memmap_opt);
index 861203e958da828deb140122752e95b47ddbf35f..3429b483d9f85cd2495e01c8c0a11d05bc22e16c 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Extracted from init.c
  */
+#include <linux/bootmem.h>
 #include <linux/percpu.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <asm/initialize_mmu.h>
 #include <asm/io.h>
 
+#if defined(CONFIG_HIGHMEM)
+static void * __init init_pmd(unsigned long vaddr)
+{
+       pgd_t *pgd = pgd_offset_k(vaddr);
+       pmd_t *pmd = pmd_offset(pgd, vaddr);
+
+       if (pmd_none(*pmd)) {
+               unsigned i;
+               pte_t *pte = alloc_bootmem_low_pages(PAGE_SIZE);
+
+               for (i = 0; i < 1024; i++)
+                       pte_clear(NULL, 0, pte + i);
+
+               set_pmd(pmd, __pmd(((unsigned long)pte) & PAGE_MASK));
+               BUG_ON(pte != pte_offset_kernel(pmd, 0));
+               pr_debug("%s: vaddr: 0x%08lx, pmd: 0x%p, pte: 0x%p\n",
+                        __func__, vaddr, pmd, pte);
+               return pte;
+       } else {
+               return pte_offset_kernel(pmd, 0);
+       }
+}
+
+static void __init fixedrange_init(void)
+{
+       BUILD_BUG_ON(FIXADDR_SIZE > PMD_SIZE);
+       init_pmd(__fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK);
+}
+#endif
+
 void __init paging_init(void)
 {
        memset(swapper_pg_dir, 0, PAGE_SIZE);
+#ifdef CONFIG_HIGHMEM
+       fixedrange_init();
+       pkmap_page_table = init_pmd(PKMAP_BASE);
+       kmap_init();
+#endif
 }
 
 /*
index ade623826788b387f150cfae5a90821f07f6b028..5ece856c5725c7cc72d0a0175bf9229330fabec5 100644 (file)
@@ -149,6 +149,21 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        local_irq_restore(flags);
 }
 
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       if (end > start && start >= TASK_SIZE && end <= PAGE_OFFSET &&
+           end - start < _TLB_ENTRIES << PAGE_SHIFT) {
+               start &= PAGE_MASK;
+               while (start < end) {
+                       invalidate_itlb_mapping(start);
+                       invalidate_dtlb_mapping(start);
+                       start += PAGE_SIZE;
+               }
+       } else {
+               local_flush_tlb_all();
+       }
+}
+
 #ifdef CONFIG_DEBUG_TLB_SANITY
 
 static unsigned get_pte_for_vaddr(unsigned vaddr)
index d2369b799c5077f7b9240135cba96d74acfcc7cf..b3e89291cfbafcb35a1eb07f7f584c35ef7f2d81 100644 (file)
@@ -4,6 +4,7 @@
 # "prom monitor" library routines under Linux.
 #
 
-obj-y                  = console.o setup.o
+obj-y                  = setup.o
+obj-$(CONFIG_TTY)      += console.o
 obj-$(CONFIG_NET)      += network.o
 obj-$(CONFIG_BLK_DEV_SIMDISK) += simdisk.o
index f9bc8796629089a540c892109a46a9fe19f68568..b90555cb80890135fee12f7cc3ec361127106836 100644 (file)
@@ -92,18 +92,8 @@ void __init platform_setup(char** cmdline)
 
 /* early initialization */
 
-extern sysmem_info_t __initdata sysmem;
-
-void platform_init(bp_tag_t* first)
+void __init platform_init(bp_tag_t *first)
 {
-       /* Set default memory block if not provided by the bootloader. */
-
-       if (sysmem.nr_banks == 0) {
-               sysmem.nr_banks = 1;
-               sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
-               sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
-                                    + PLATFORM_DEFAULT_MEM_SIZE;
-       }
 }
 
 /* Heartbeat. Let the LED blink. */
index a0e3096c4bb53a48c129d3df0337ad66731c417a..c4269701cb4f796a6f48147c943f579621606cd5 100644 (file)
@@ -146,8 +146,8 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
        printk(KERN_INFO "  sector %llu, nr/cnr %u/%u\n",
               (unsigned long long)blk_rq_pos(rq),
               blk_rq_sectors(rq), blk_rq_cur_sectors(rq));
-       printk(KERN_INFO "  bio %p, biotail %p, buffer %p, len %u\n",
-              rq->bio, rq->biotail, rq->buffer, blk_rq_bytes(rq));
+       printk(KERN_INFO "  bio %p, biotail %p, len %u\n",
+              rq->bio, rq->biotail, blk_rq_bytes(rq));
 
        if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
                printk(KERN_INFO "  cdb: ");
@@ -251,8 +251,10 @@ void blk_sync_queue(struct request_queue *q)
                struct blk_mq_hw_ctx *hctx;
                int i;
 
-               queue_for_each_hw_ctx(q, hctx, i)
-                       cancel_delayed_work_sync(&hctx->delayed_work);
+               queue_for_each_hw_ctx(q, hctx, i) {
+                       cancel_delayed_work_sync(&hctx->run_work);
+                       cancel_delayed_work_sync(&hctx->delay_work);
+               }
        } else {
                cancel_delayed_work_sync(&q->delay_work);
        }
@@ -1360,7 +1362,6 @@ void blk_add_request_payload(struct request *rq, struct page *page,
 
        rq->__data_len = rq->resid_len = len;
        rq->nr_phys_segments = 1;
-       rq->buffer = bio_data(bio);
 }
 EXPORT_SYMBOL_GPL(blk_add_request_payload);
 
@@ -1402,12 +1403,6 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
        bio->bi_next = req->bio;
        req->bio = bio;
 
-       /*
-        * may not be valid. if the low level driver said
-        * it didn't need a bounce buffer then it better
-        * not touch req->buffer either...
-        */
-       req->buffer = bio_data(bio);
        req->__sector = bio->bi_iter.bi_sector;
        req->__data_len += bio->bi_iter.bi_size;
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
@@ -1654,7 +1649,7 @@ static int __init fail_make_request_debugfs(void)
        struct dentry *dir = fault_create_debugfs_attr("fail_make_request",
                                                NULL, &fail_make_request);
 
-       return IS_ERR(dir) ? PTR_ERR(dir) : 0;
+       return PTR_ERR_OR_ZERO(dir);
 }
 
 late_initcall(fail_make_request_debugfs);
@@ -2434,7 +2429,6 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
        }
 
        req->__data_len -= total_bytes;
-       req->buffer = bio_data(req->bio);
 
        /* update sector only for requests with clear definition of sector */
        if (req->cmd_type == REQ_TYPE_FS)
@@ -2503,7 +2497,7 @@ EXPORT_SYMBOL_GPL(blk_unprep_request);
 /*
  * queue lock must be held
  */
-static void blk_finish_request(struct request *req, int error)
+void blk_finish_request(struct request *req, int error)
 {
        if (blk_rq_tagged(req))
                blk_queue_end_tag(req->q, req);
@@ -2529,6 +2523,7 @@ static void blk_finish_request(struct request *req, int error)
                __blk_put_request(req->q, req);
        }
 }
+EXPORT_SYMBOL(blk_finish_request);
 
 /**
  * blk_end_bidi_request - Complete a bidi request
@@ -2752,10 +2747,9 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
        /* Bit 0 (R/W) is identical in rq->cmd_flags and bio->bi_rw */
        rq->cmd_flags |= bio->bi_rw & REQ_WRITE;
 
-       if (bio_has_data(bio)) {
+       if (bio_has_data(bio))
                rq->nr_phys_segments = bio_phys_segments(q, bio);
-               rq->buffer = bio_data(bio);
-       }
+
        rq->__data_len = bio->bi_iter.bi_size;
        rq->bio = rq->biotail = bio;
 
@@ -2831,7 +2825,7 @@ EXPORT_SYMBOL_GPL(blk_rq_unprep_clone);
 
 /*
  * Copy attributes of the original request to the clone request.
- * The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied.
+ * The actual data parts (e.g. ->cmd, ->sense) are not copied.
  */
 static void __blk_rq_prep_clone(struct request *dst, struct request *src)
 {
@@ -2857,7 +2851,7 @@ static void __blk_rq_prep_clone(struct request *dst, struct request *src)
  *
  * Description:
  *     Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq.
- *     The actual data parts of @rq_src (e.g. ->cmd, ->buffer, ->sense)
+ *     The actual data parts of @rq_src (e.g. ->cmd, ->sense)
  *     are not copied, and copying such parts is the caller's responsibility.
  *     Also, pages which the original bios are pointing to are not copied
  *     and the cloned bios just point same pages.
@@ -2904,19 +2898,26 @@ free_and_out:
 }
 EXPORT_SYMBOL_GPL(blk_rq_prep_clone);
 
-int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
+int kblockd_schedule_work(struct work_struct *work)
 {
        return queue_work(kblockd_workqueue, work);
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-int kblockd_schedule_delayed_work(struct request_queue *q,
-                       struct delayed_work *dwork, unsigned long delay)
+int kblockd_schedule_delayed_work(struct delayed_work *dwork,
+                                 unsigned long delay)
 {
        return queue_delayed_work(kblockd_workqueue, dwork, delay);
 }
 EXPORT_SYMBOL(kblockd_schedule_delayed_work);
 
+int kblockd_schedule_delayed_work_on(int cpu, struct delayed_work *dwork,
+                                    unsigned long delay)
+{
+       return queue_delayed_work_on(cpu, kblockd_workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(kblockd_schedule_delayed_work_on);
+
 #define PLUG_MAGIC     0x91827364
 
 /**
index 43e6b4755e9a7e74e05479a83d42fbd88762e9f4..ec7a224d67335085186ad5ea09399d5c80014fb6 100644 (file)
@@ -134,7 +134,7 @@ static void mq_flush_run(struct work_struct *work)
 {
        struct request *rq;
 
-       rq = container_of(work, struct request, mq_flush_work);
+       rq = container_of(work, struct request, requeue_work);
 
        memset(&rq->csd, 0, sizeof(rq->csd));
        blk_mq_insert_request(rq, false, true, false);
@@ -143,8 +143,8 @@ static void mq_flush_run(struct work_struct *work)
 static bool blk_flush_queue_rq(struct request *rq, bool add_front)
 {
        if (rq->q->mq_ops) {
-               INIT_WORK(&rq->mq_flush_work, mq_flush_run);
-               kblockd_schedule_work(rq->q, &rq->mq_flush_work);
+               INIT_WORK(&rq->requeue_work, mq_flush_run);
+               kblockd_schedule_work(&rq->requeue_work);
                return false;
        } else {
                if (add_front)
@@ -306,23 +306,9 @@ static bool blk_kick_flush(struct request_queue *q)
         */
        q->flush_pending_idx ^= 1;
 
-       if (q->mq_ops) {
-               struct blk_mq_ctx *ctx = first_rq->mq_ctx;
-               struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
-               blk_mq_rq_init(hctx, q->flush_rq);
-               q->flush_rq->mq_ctx = ctx;
-
-               /*
-                * Reuse the tag value from the fist waiting request,
-                * with blk-mq the tag is generated during request
-                * allocation and drivers can rely on it being inside
-                * the range they asked for.
-                */
-               q->flush_rq->tag = first_rq->tag;
-       } else {
-               blk_rq_init(q, q->flush_rq);
-       }
+       blk_rq_init(q, q->flush_rq);
+       if (q->mq_ops)
+               blk_mq_clone_flush_request(q->flush_rq, first_rq);
 
        q->flush_rq->cmd_type = REQ_TYPE_FS;
        q->flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
index c11d24e379e2a4b89caf1936d4433773caef1bdc..d828b44a404b4f5abc35d7760346870a3902a911 100644 (file)
@@ -64,12 +64,12 @@ EXPORT_SYMBOL(__blk_iopoll_complete);
  *     iopoll handler will not be invoked again before blk_iopoll_sched_prep()
  *     is called.
  **/
-void blk_iopoll_complete(struct blk_iopoll *iopoll)
+void blk_iopoll_complete(struct blk_iopoll *iop)
 {
        unsigned long flags;
 
        local_irq_save(flags);
-       __blk_iopoll_complete(iopoll);
+       __blk_iopoll_complete(iop);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(blk_iopoll_complete);
index f7b22bc215180d4b7f467135faeaf52975a77013..f890d4345b0cb63f9faa88e70d466a3cec3e6b3f 100644 (file)
@@ -155,7 +155,6 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
        if (!bio_flagged(bio, BIO_USER_MAPPED))
                rq->cmd_flags |= REQ_COPY_USER;
 
-       rq->buffer = NULL;
        return 0;
 unmap_rq:
        blk_rq_unmap_user(bio);
@@ -238,7 +237,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        blk_queue_bounce(q, &bio);
        bio_get(bio);
        blk_rq_bio_prep(q, rq, bio);
-       rq->buffer = NULL;
        return 0;
 }
 EXPORT_SYMBOL(blk_rq_map_user_iov);
@@ -325,7 +323,6 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        }
 
        blk_queue_bounce(q, &rq->bio);
-       rq->buffer = NULL;
        return 0;
 }
 EXPORT_SYMBOL(blk_rq_map_kern);
index 09792132961991e8168c2dee283a7b0cb0b967d0..5d0f93cf358cdef9b782fdc4dbf442daf11781bf 100644 (file)
@@ -80,17 +80,17 @@ int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues)
        return 0;
 }
 
-unsigned int *blk_mq_make_queue_map(struct blk_mq_reg *reg)
+unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set)
 {
        unsigned int *map;
 
        /* If cpus are offline, map them to first hctx */
        map = kzalloc_node(sizeof(*map) * num_possible_cpus(), GFP_KERNEL,
-                               reg->numa_node);
+                               set->numa_node);
        if (!map)
                return NULL;
 
-       if (!blk_mq_update_queue_map(map, reg->nr_hw_queues))
+       if (!blk_mq_update_queue_map(map, set->nr_hw_queues))
                return map;
 
        kfree(map);
index b0ba264b05225ca2432a9a86878cf9501efa2265..8145b5b25b4b302419cadee9a61def400188c09d 100644 (file)
@@ -203,42 +203,6 @@ static ssize_t blk_mq_hw_sysfs_rq_list_show(struct blk_mq_hw_ctx *hctx,
        return ret;
 }
 
-static ssize_t blk_mq_hw_sysfs_ipi_show(struct blk_mq_hw_ctx *hctx, char *page)
-{
-       ssize_t ret;
-
-       spin_lock(&hctx->lock);
-       ret = sprintf(page, "%u\n", !!(hctx->flags & BLK_MQ_F_SHOULD_IPI));
-       spin_unlock(&hctx->lock);
-
-       return ret;
-}
-
-static ssize_t blk_mq_hw_sysfs_ipi_store(struct blk_mq_hw_ctx *hctx,
-                                        const char *page, size_t len)
-{
-       struct blk_mq_ctx *ctx;
-       unsigned long ret;
-       unsigned int i;
-
-       if (kstrtoul(page, 10, &ret)) {
-               pr_err("blk-mq-sysfs: invalid input '%s'\n", page);
-               return -EINVAL;
-       }
-
-       spin_lock(&hctx->lock);
-       if (ret)
-               hctx->flags |= BLK_MQ_F_SHOULD_IPI;
-       else
-               hctx->flags &= ~BLK_MQ_F_SHOULD_IPI;
-       spin_unlock(&hctx->lock);
-
-       hctx_for_each_ctx(hctx, ctx, i)
-               ctx->ipi_redirect = !!ret;
-
-       return len;
-}
-
 static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page)
 {
        return blk_mq_tag_sysfs_show(hctx->tags, page);
@@ -246,16 +210,12 @@ static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page)
 
 static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
 {
-       unsigned int i, queue_num, first = 1;
+       unsigned int i, first = 1;
        ssize_t ret = 0;
 
        blk_mq_disable_hotplug();
 
-       for_each_online_cpu(i) {
-               queue_num = hctx->queue->mq_map[i];
-               if (queue_num != hctx->queue_num)
-                       continue;
-
+       for_each_cpu(i, hctx->cpumask) {
                if (first)
                        ret += sprintf(ret + page, "%u", i);
                else
@@ -311,11 +271,6 @@ static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_pending = {
        .attr = {.name = "pending", .mode = S_IRUGO },
        .show = blk_mq_hw_sysfs_rq_list_show,
 };
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_ipi = {
-       .attr = {.name = "ipi_redirect", .mode = S_IRUGO | S_IWUSR},
-       .show = blk_mq_hw_sysfs_ipi_show,
-       .store = blk_mq_hw_sysfs_ipi_store,
-};
 static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_tags = {
        .attr = {.name = "tags", .mode = S_IRUGO },
        .show = blk_mq_hw_sysfs_tags_show,
@@ -330,7 +285,6 @@ static struct attribute *default_hw_ctx_attrs[] = {
        &blk_mq_hw_sysfs_run.attr,
        &blk_mq_hw_sysfs_dispatched.attr,
        &blk_mq_hw_sysfs_pending.attr,
-       &blk_mq_hw_sysfs_ipi.attr,
        &blk_mq_hw_sysfs_tags.attr,
        &blk_mq_hw_sysfs_cpus.attr,
        NULL,
index 83ae96c51a2762cf7386f096e348eace58525e37..1f43d6ee956fbdab557bb5bab70938e0155499e0 100644 (file)
@@ -1,28 +1,14 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/percpu_ida.h>
 
 #include <linux/blk-mq.h>
 #include "blk.h"
 #include "blk-mq.h"
 #include "blk-mq-tag.h"
 
-/*
- * Per tagged queue (tag address space) map
- */
-struct blk_mq_tags {
-       unsigned int nr_tags;
-       unsigned int nr_reserved_tags;
-       unsigned int nr_batch_move;
-       unsigned int nr_max_cache;
-
-       struct percpu_ida free_tags;
-       struct percpu_ida reserved_tags;
-};
-
-void blk_mq_wait_for_tags(struct blk_mq_tags *tags)
+void blk_mq_wait_for_tags(struct blk_mq_tags *tags, bool reserved)
 {
-       int tag = blk_mq_get_tag(tags, __GFP_WAIT, false);
+       int tag = blk_mq_get_tag(tags, __GFP_WAIT, reserved);
        blk_mq_put_tag(tags, tag);
 }
 
index 947ba2c6148e0b24e53ecaf9eceb7efff15472d0..c8e0645ea331c74775cb211b876188f2c808af39 100644 (file)
@@ -1,13 +1,30 @@
 #ifndef INT_BLK_MQ_TAG_H
 #define INT_BLK_MQ_TAG_H
 
-struct blk_mq_tags;
+#include <linux/percpu_ida.h>
+
+/*
+ * Tag address space map.
+ */
+struct blk_mq_tags {
+       unsigned int nr_tags;
+       unsigned int nr_reserved_tags;
+       unsigned int nr_batch_move;
+       unsigned int nr_max_cache;
+
+       struct percpu_ida free_tags;
+       struct percpu_ida reserved_tags;
+
+       struct request **rqs;
+       struct list_head page_list;
+};
+
 
 extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags, unsigned int reserved_tags, int node);
 extern void blk_mq_free_tags(struct blk_mq_tags *tags);
 
 extern unsigned int blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp, bool reserved);
-extern void blk_mq_wait_for_tags(struct blk_mq_tags *tags);
+extern void blk_mq_wait_for_tags(struct blk_mq_tags *tags, bool reserved);
 extern void blk_mq_put_tag(struct blk_mq_tags *tags, unsigned int tag);
 extern void blk_mq_tag_busy_iter(struct blk_mq_tags *tags, void (*fn)(void *data, unsigned long *), void *data);
 extern bool blk_mq_has_free_tags(struct blk_mq_tags *tags);
index 1d2a9bdbee57f100faacf91ab3a9aef6b7b2a944..0d379830a278130adf4d316e8cae141599dd39b4 100644 (file)
@@ -81,7 +81,8 @@ static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
 
        tag = blk_mq_get_tag(hctx->tags, gfp, reserved);
        if (tag != BLK_MQ_TAG_FAIL) {
-               rq = hctx->rqs[tag];
+               rq = hctx->tags->rqs[tag];
+               blk_rq_init(hctx->queue, rq);
                rq->tag = tag;
 
                return rq;
@@ -209,12 +210,15 @@ static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
                        break;
                }
 
-               blk_mq_put_ctx(ctx);
-               if (!(gfp & __GFP_WAIT))
+               if (gfp & __GFP_WAIT) {
+                       __blk_mq_run_hw_queue(hctx);
+                       blk_mq_put_ctx(ctx);
+               } else {
+                       blk_mq_put_ctx(ctx);
                        break;
+               }
 
-               __blk_mq_run_hw_queue(hctx);
-               blk_mq_wait_for_tags(hctx->tags);
+               blk_mq_wait_for_tags(hctx->tags, reserved);
        } while (1);
 
        return rq;
@@ -248,26 +252,13 @@ struct request *blk_mq_alloc_reserved_request(struct request_queue *q, int rw,
 }
 EXPORT_SYMBOL(blk_mq_alloc_reserved_request);
 
-/*
- * Re-init and set pdu, if we have it
- */
-void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq)
-{
-       blk_rq_init(hctx->queue, rq);
-
-       if (hctx->cmd_size)
-               rq->special = blk_mq_rq_to_pdu(rq);
-}
-
 static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx,
                                  struct blk_mq_ctx *ctx, struct request *rq)
 {
        const int tag = rq->tag;
        struct request_queue *q = rq->q;
 
-       blk_mq_rq_init(hctx, rq);
        blk_mq_put_tag(hctx->tags, tag);
-
        blk_mq_queue_exit(q);
 }
 
@@ -283,20 +274,47 @@ void blk_mq_free_request(struct request *rq)
        __blk_mq_free_request(hctx, ctx, rq);
 }
 
-bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes)
+/*
+ * Clone all relevant state from a request that has been put on hold in
+ * the flush state machine into the preallocated flush request that hangs
+ * off the request queue.
+ *
+ * For a driver the flush request should be invisible, that's why we are
+ * impersonating the original request here.
+ */
+void blk_mq_clone_flush_request(struct request *flush_rq,
+               struct request *orig_rq)
 {
-       if (blk_update_request(rq, error, blk_rq_bytes(rq)))
-               return true;
+       struct blk_mq_hw_ctx *hctx =
+               orig_rq->q->mq_ops->map_queue(orig_rq->q, orig_rq->mq_ctx->cpu);
+
+       flush_rq->mq_ctx = orig_rq->mq_ctx;
+       flush_rq->tag = orig_rq->tag;
+       memcpy(blk_mq_rq_to_pdu(flush_rq), blk_mq_rq_to_pdu(orig_rq),
+               hctx->cmd_size);
+}
 
+inline void __blk_mq_end_io(struct request *rq, int error)
+{
        blk_account_io_done(rq);
 
-       if (rq->end_io)
+       if (rq->end_io) {
                rq->end_io(rq, error);
-       else
+       } else {
+               if (unlikely(blk_bidi_rq(rq)))
+                       blk_mq_free_request(rq->next_rq);
                blk_mq_free_request(rq);
-       return false;
+       }
+}
+EXPORT_SYMBOL(__blk_mq_end_io);
+
+void blk_mq_end_io(struct request *rq, int error)
+{
+       if (blk_update_request(rq, error, blk_rq_bytes(rq)))
+               BUG();
+       __blk_mq_end_io(rq, error);
 }
-EXPORT_SYMBOL(blk_mq_end_io_partial);
+EXPORT_SYMBOL(blk_mq_end_io);
 
 static void __blk_mq_complete_request_remote(void *data)
 {
@@ -308,15 +326,19 @@ static void __blk_mq_complete_request_remote(void *data)
 void __blk_mq_complete_request(struct request *rq)
 {
        struct blk_mq_ctx *ctx = rq->mq_ctx;
+       bool shared = false;
        int cpu;
 
-       if (!ctx->ipi_redirect) {
+       if (!test_bit(QUEUE_FLAG_SAME_COMP, &rq->q->queue_flags)) {
                rq->q->softirq_done_fn(rq);
                return;
        }
 
        cpu = get_cpu();
-       if (cpu != ctx->cpu && cpu_online(ctx->cpu)) {
+       if (!test_bit(QUEUE_FLAG_SAME_FORCE, &rq->q->queue_flags))
+               shared = cpus_share_cache(cpu, ctx->cpu);
+
+       if (cpu != ctx->cpu && !shared && cpu_online(ctx->cpu)) {
                rq->csd.func = __blk_mq_complete_request_remote;
                rq->csd.info = rq;
                rq->csd.flags = 0;
@@ -350,13 +372,25 @@ static void blk_mq_start_request(struct request *rq, bool last)
 
        trace_block_rq_issue(q, rq);
 
+       rq->resid_len = blk_rq_bytes(rq);
+       if (unlikely(blk_bidi_rq(rq)))
+               rq->next_rq->resid_len = blk_rq_bytes(rq->next_rq);
+
        /*
         * Just mark start time and set the started bit. Due to memory
         * ordering, we know we'll see the correct deadline as long as
         * REQ_ATOMIC_STARTED is seen.
         */
        rq->deadline = jiffies + q->rq_timeout;
+
+       /*
+        * Mark us as started and clear complete. Complete might have been
+        * set if requeue raced with timeout, which then marked it as
+        * complete. So be sure to clear complete again when we start
+        * the request, otherwise we'll ignore the completion event.
+        */
        set_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
+       clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
 
        if (q->dma_drain_size && blk_rq_bytes(rq)) {
                /*
@@ -378,7 +412,7 @@ static void blk_mq_start_request(struct request *rq, bool last)
                rq->cmd_flags |= REQ_END;
 }
 
-static void blk_mq_requeue_request(struct request *rq)
+static void __blk_mq_requeue_request(struct request *rq)
 {
        struct request_queue *q = rq->q;
 
@@ -391,6 +425,22 @@ static void blk_mq_requeue_request(struct request *rq)
                rq->nr_phys_segments--;
 }
 
+void blk_mq_requeue_request(struct request *rq)
+{
+       __blk_mq_requeue_request(rq);
+       blk_clear_rq_complete(rq);
+
+       BUG_ON(blk_queued_rq(rq));
+       blk_mq_insert_request(rq, true, true, false);
+}
+EXPORT_SYMBOL(blk_mq_requeue_request);
+
+struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag)
+{
+       return tags->rqs[tag];
+}
+EXPORT_SYMBOL(blk_mq_tag_to_rq);
+
 struct blk_mq_timeout_data {
        struct blk_mq_hw_ctx *hctx;
        unsigned long *next;
@@ -412,12 +462,13 @@ static void blk_mq_timeout_check(void *__data, unsigned long *free_tags)
        do {
                struct request *rq;
 
-               tag = find_next_zero_bit(free_tags, hctx->queue_depth, tag);
-               if (tag >= hctx->queue_depth)
+               tag = find_next_zero_bit(free_tags, hctx->tags->nr_tags, tag);
+               if (tag >= hctx->tags->nr_tags)
                        break;
 
-               rq = hctx->rqs[tag++];
-
+               rq = blk_mq_tag_to_rq(hctx->tags, tag++);
+               if (rq->q != hctx->queue)
+                       continue;
                if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags))
                        continue;
 
@@ -442,6 +493,28 @@ static void blk_mq_hw_ctx_check_timeout(struct blk_mq_hw_ctx *hctx,
        blk_mq_tag_busy_iter(hctx->tags, blk_mq_timeout_check, &data);
 }
 
+static enum blk_eh_timer_return blk_mq_rq_timed_out(struct request *rq)
+{
+       struct request_queue *q = rq->q;
+
+       /*
+        * We know that complete is set at this point. If STARTED isn't set
+        * anymore, then the request isn't active and the "timeout" should
+        * just be ignored. This can happen due to the bitflag ordering.
+        * Timeout first checks if STARTED is set, and if it is, assumes
+        * the request is active. But if we race with completion, then
+        * we both flags will get cleared. So check here again, and ignore
+        * a timeout event with a request that isn't active.
+        */
+       if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags))
+               return BLK_EH_NOT_HANDLED;
+
+       if (!q->mq_ops->timeout)
+               return BLK_EH_RESET_TIMER;
+
+       return q->mq_ops->timeout(rq);
+}
+
 static void blk_mq_rq_timer(unsigned long data)
 {
        struct request_queue *q = (struct request_queue *) data;
@@ -495,11 +568,6 @@ static bool blk_mq_attempt_merge(struct request_queue *q,
        return false;
 }
 
-void blk_mq_add_timer(struct request *rq)
-{
-       __blk_add_timer(rq, NULL);
-}
-
 /*
  * Run this hardware queue, pulling any software queues mapped to it in.
  * Note that this function currently has various problems around ordering
@@ -514,6 +582,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
        LIST_HEAD(rq_list);
        int bit, queued;
 
+       WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask));
+
        if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
                return;
 
@@ -525,7 +595,6 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
        for_each_set_bit(bit, hctx->ctx_map, hctx->nr_ctx) {
                clear_bit(bit, hctx->ctx_map);
                ctx = hctx->ctxs[bit];
-               BUG_ON(bit != ctx->index_hw);
 
                spin_lock(&ctx->lock);
                list_splice_tail_init(&ctx->rq_list, &rq_list);
@@ -571,7 +640,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
                         * time
                         */
                        list_add(&rq->queuelist, &rq_list);
-                       blk_mq_requeue_request(rq);
+                       __blk_mq_requeue_request(rq);
                        break;
                default:
                        pr_err("blk-mq: bad return on queue: %d\n", ret);
@@ -606,12 +675,21 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
        if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
                return;
 
-       if (!async)
+       if (!async && cpumask_test_cpu(smp_processor_id(), hctx->cpumask))
                __blk_mq_run_hw_queue(hctx);
+       else if (hctx->queue->nr_hw_queues == 1)
+               kblockd_schedule_delayed_work(&hctx->run_work, 0);
        else {
-               struct request_queue *q = hctx->queue;
+               unsigned int cpu;
 
-               kblockd_schedule_delayed_work(q, &hctx->delayed_work, 0);
+               /*
+                * It'd be great if the workqueue API had a way to pass
+                * in a mask and had some smarts for more clever placement
+                * than the first CPU. Or we could round-robin here. For now,
+                * just queue on the first CPU.
+                */
+               cpu = cpumask_first(hctx->cpumask);
+               kblockd_schedule_delayed_work_on(cpu, &hctx->run_work, 0);
        }
 }
 
@@ -626,14 +704,17 @@ void blk_mq_run_queues(struct request_queue *q, bool async)
                    test_bit(BLK_MQ_S_STOPPED, &hctx->state))
                        continue;
 
+               preempt_disable();
                blk_mq_run_hw_queue(hctx, async);
+               preempt_enable();
        }
 }
 EXPORT_SYMBOL(blk_mq_run_queues);
 
 void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx)
 {
-       cancel_delayed_work(&hctx->delayed_work);
+       cancel_delayed_work(&hctx->run_work);
+       cancel_delayed_work(&hctx->delay_work);
        set_bit(BLK_MQ_S_STOPPED, &hctx->state);
 }
 EXPORT_SYMBOL(blk_mq_stop_hw_queue);
@@ -651,11 +732,25 @@ EXPORT_SYMBOL(blk_mq_stop_hw_queues);
 void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx)
 {
        clear_bit(BLK_MQ_S_STOPPED, &hctx->state);
+
+       preempt_disable();
        __blk_mq_run_hw_queue(hctx);
+       preempt_enable();
 }
 EXPORT_SYMBOL(blk_mq_start_hw_queue);
 
-void blk_mq_start_stopped_hw_queues(struct request_queue *q)
+void blk_mq_start_hw_queues(struct request_queue *q)
+{
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
+       queue_for_each_hw_ctx(q, hctx, i)
+               blk_mq_start_hw_queue(hctx);
+}
+EXPORT_SYMBOL(blk_mq_start_hw_queues);
+
+
+void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async)
 {
        struct blk_mq_hw_ctx *hctx;
        int i;
@@ -665,19 +760,53 @@ void blk_mq_start_stopped_hw_queues(struct request_queue *q)
                        continue;
 
                clear_bit(BLK_MQ_S_STOPPED, &hctx->state);
-               blk_mq_run_hw_queue(hctx, true);
+               preempt_disable();
+               blk_mq_run_hw_queue(hctx, async);
+               preempt_enable();
        }
 }
 EXPORT_SYMBOL(blk_mq_start_stopped_hw_queues);
 
-static void blk_mq_work_fn(struct work_struct *work)
+static void blk_mq_run_work_fn(struct work_struct *work)
 {
        struct blk_mq_hw_ctx *hctx;
 
-       hctx = container_of(work, struct blk_mq_hw_ctx, delayed_work.work);
+       hctx = container_of(work, struct blk_mq_hw_ctx, run_work.work);
+
        __blk_mq_run_hw_queue(hctx);
 }
 
+static void blk_mq_delay_work_fn(struct work_struct *work)
+{
+       struct blk_mq_hw_ctx *hctx;
+
+       hctx = container_of(work, struct blk_mq_hw_ctx, delay_work.work);
+
+       if (test_and_clear_bit(BLK_MQ_S_STOPPED, &hctx->state))
+               __blk_mq_run_hw_queue(hctx);
+}
+
+void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
+{
+       unsigned long tmo = msecs_to_jiffies(msecs);
+
+       if (hctx->queue->nr_hw_queues == 1)
+               kblockd_schedule_delayed_work(&hctx->delay_work, tmo);
+       else {
+               unsigned int cpu;
+
+               /*
+                * It'd be great if the workqueue API had a way to pass
+                * in a mask and had some smarts for more clever placement
+                * than the first CPU. Or we could round-robin here. For now,
+                * just queue on the first CPU.
+                */
+               cpu = cpumask_first(hctx->cpumask);
+               kblockd_schedule_delayed_work_on(cpu, &hctx->delay_work, tmo);
+       }
+}
+EXPORT_SYMBOL(blk_mq_delay_queue);
+
 static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
                                    struct request *rq, bool at_head)
 {
@@ -694,7 +823,7 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
        /*
         * We do this early, to ensure we are on the right CPU.
         */
-       blk_mq_add_timer(rq);
+       blk_add_timer(rq);
 }
 
 void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
@@ -719,10 +848,10 @@ void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
                spin_unlock(&ctx->lock);
        }
 
-       blk_mq_put_ctx(current_ctx);
-
        if (run_queue)
                blk_mq_run_hw_queue(hctx, async);
+
+       blk_mq_put_ctx(current_ctx);
 }
 
 static void blk_mq_insert_requests(struct request_queue *q,
@@ -758,9 +887,8 @@ static void blk_mq_insert_requests(struct request_queue *q,
        }
        spin_unlock(&ctx->lock);
 
-       blk_mq_put_ctx(current_ctx);
-
        blk_mq_run_hw_queue(hctx, from_schedule);
+       blk_mq_put_ctx(current_ctx);
 }
 
 static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b)
@@ -879,7 +1007,6 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
 
        if (unlikely(is_flush_fua)) {
                blk_mq_bio_to_request(rq, bio);
-               blk_mq_put_ctx(ctx);
                blk_insert_flush(rq);
                goto run_queue;
        }
@@ -906,18 +1033,25 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
                }
        }
 
-       spin_lock(&ctx->lock);
+       if (!(hctx->flags & BLK_MQ_F_SHOULD_MERGE)) {
+               init_request_from_bio(rq, bio);
 
-       if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) &&
-           blk_mq_attempt_merge(q, ctx, bio))
-               __blk_mq_free_request(hctx, ctx, rq);
-       else {
-               blk_mq_bio_to_request(rq, bio);
+               spin_lock(&ctx->lock);
+insert_rq:
                __blk_mq_insert_request(hctx, rq, false);
+               spin_unlock(&ctx->lock);
+               blk_account_io_start(rq, 1);
+       } else {
+               spin_lock(&ctx->lock);
+               if (!blk_mq_attempt_merge(q, ctx, bio)) {
+                       init_request_from_bio(rq, bio);
+                       goto insert_rq;
+               }
+
+               spin_unlock(&ctx->lock);
+               __blk_mq_free_request(hctx, ctx, rq);
        }
 
-       spin_unlock(&ctx->lock);
-       blk_mq_put_ctx(ctx);
 
        /*
         * For a SYNC request, send it to the hardware immediately. For an
@@ -926,6 +1060,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
         */
 run_queue:
        blk_mq_run_hw_queue(hctx, !is_sync || is_flush_fua);
+       blk_mq_put_ctx(ctx);
 }
 
 /*
@@ -937,11 +1072,11 @@ struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q, const int cpu)
 }
 EXPORT_SYMBOL(blk_mq_map_queue);
 
-struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *reg,
+struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *set,
                                                   unsigned int hctx_index)
 {
        return kmalloc_node(sizeof(struct blk_mq_hw_ctx),
-                               GFP_KERNEL | __GFP_ZERO, reg->numa_node);
+                               GFP_KERNEL | __GFP_ZERO, set->numa_node);
 }
 EXPORT_SYMBOL(blk_mq_alloc_single_hw_queue);
 
@@ -993,124 +1128,73 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
        blk_mq_hctx_mark_pending(hctx, ctx);
 
        spin_unlock(&ctx->lock);
-       blk_mq_put_ctx(ctx);
 
        blk_mq_run_hw_queue(hctx, true);
+       blk_mq_put_ctx(ctx);
 }
 
-static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
-                                  int (*init)(void *, struct blk_mq_hw_ctx *,
-                                       struct request *, unsigned int),
-                                  void *data)
-{
-       unsigned int i;
-       int ret = 0;
-
-       for (i = 0; i < hctx->queue_depth; i++) {
-               struct request *rq = hctx->rqs[i];
-
-               ret = init(data, hctx, rq, i);
-               if (ret)
-                       break;
-       }
-
-       return ret;
-}
-
-int blk_mq_init_commands(struct request_queue *q,
-                        int (*init)(void *, struct blk_mq_hw_ctx *,
-                                       struct request *, unsigned int),
-                        void *data)
-{
-       struct blk_mq_hw_ctx *hctx;
-       unsigned int i;
-       int ret = 0;
-
-       queue_for_each_hw_ctx(q, hctx, i) {
-               ret = blk_mq_init_hw_commands(hctx, init, data);
-               if (ret)
-                       break;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(blk_mq_init_commands);
-
-static void blk_mq_free_hw_commands(struct blk_mq_hw_ctx *hctx,
-                                   void (*free)(void *, struct blk_mq_hw_ctx *,
-                                       struct request *, unsigned int),
-                                   void *data)
+static void blk_mq_free_rq_map(struct blk_mq_tag_set *set,
+               struct blk_mq_tags *tags, unsigned int hctx_idx)
 {
-       unsigned int i;
+       struct page *page;
 
-       for (i = 0; i < hctx->queue_depth; i++) {
-               struct request *rq = hctx->rqs[i];
+       if (tags->rqs && set->ops->exit_request) {
+               int i;
 
-               free(data, hctx, rq, i);
+               for (i = 0; i < tags->nr_tags; i++) {
+                       if (!tags->rqs[i])
+                               continue;
+                       set->ops->exit_request(set->driver_data, tags->rqs[i],
+                                               hctx_idx, i);
+               }
        }
-}
-
-void blk_mq_free_commands(struct request_queue *q,
-                         void (*free)(void *, struct blk_mq_hw_ctx *,
-                                       struct request *, unsigned int),
-                         void *data)
-{
-       struct blk_mq_hw_ctx *hctx;
-       unsigned int i;
-
-       queue_for_each_hw_ctx(q, hctx, i)
-               blk_mq_free_hw_commands(hctx, free, data);
-}
-EXPORT_SYMBOL(blk_mq_free_commands);
-
-static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx)
-{
-       struct page *page;
 
-       while (!list_empty(&hctx->page_list)) {
-               page = list_first_entry(&hctx->page_list, struct page, lru);
+       while (!list_empty(&tags->page_list)) {
+               page = list_first_entry(&tags->page_list, struct page, lru);
                list_del_init(&page->lru);
                __free_pages(page, page->private);
        }
 
-       kfree(hctx->rqs);
+       kfree(tags->rqs);
 
-       if (hctx->tags)
-               blk_mq_free_tags(hctx->tags);
+       blk_mq_free_tags(tags);
 }
 
 static size_t order_to_size(unsigned int order)
 {
-       size_t ret = PAGE_SIZE;
-
-       while (order--)
-               ret *= 2;
-
-       return ret;
+       return (size_t)PAGE_SIZE << order;
 }
 
-static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx,
-                             unsigned int reserved_tags, int node)
+static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
+               unsigned int hctx_idx)
 {
+       struct blk_mq_tags *tags;
        unsigned int i, j, entries_per_page, max_order = 4;
        size_t rq_size, left;
 
-       INIT_LIST_HEAD(&hctx->page_list);
+       tags = blk_mq_init_tags(set->queue_depth, set->reserved_tags,
+                               set->numa_node);
+       if (!tags)
+               return NULL;
+
+       INIT_LIST_HEAD(&tags->page_list);
 
-       hctx->rqs = kmalloc_node(hctx->queue_depth * sizeof(struct request *),
-                                       GFP_KERNEL, node);
-       if (!hctx->rqs)
-               return -ENOMEM;
+       tags->rqs = kmalloc_node(set->queue_depth * sizeof(struct request *),
+                                       GFP_KERNEL, set->numa_node);
+       if (!tags->rqs) {
+               blk_mq_free_tags(tags);
+               return NULL;
+       }
 
        /*
         * rq_size is the size of the request plus driver payload, rounded
         * to the cacheline size
         */
-       rq_size = round_up(sizeof(struct request) + hctx->cmd_size,
+       rq_size = round_up(sizeof(struct request) + set->cmd_size,
                                cache_line_size());
-       left = rq_size * hctx->queue_depth;
+       left = rq_size * set->queue_depth;
 
-       for (i = 0; i < hctx->queue_depth;) {
+       for (i = 0; i < set->queue_depth; ) {
                int this_order = max_order;
                struct page *page;
                int to_do;
@@ -1120,7 +1204,8 @@ static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx,
                        this_order--;
 
                do {
-                       page = alloc_pages_node(node, GFP_KERNEL, this_order);
+                       page = alloc_pages_node(set->numa_node, GFP_KERNEL,
+                                               this_order);
                        if (page)
                                break;
                        if (!this_order--)
@@ -1130,43 +1215,39 @@ static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx,
                } while (1);
 
                if (!page)
-                       break;
+                       goto fail;
 
                page->private = this_order;
-               list_add_tail(&page->lru, &hctx->page_list);
+               list_add_tail(&page->lru, &tags->page_list);
 
                p = page_address(page);
                entries_per_page = order_to_size(this_order) / rq_size;
-               to_do = min(entries_per_page, hctx->queue_depth - i);
+               to_do = min(entries_per_page, set->queue_depth - i);
                left -= to_do * rq_size;
                for (j = 0; j < to_do; j++) {
-                       hctx->rqs[i] = p;
-                       blk_mq_rq_init(hctx, hctx->rqs[i]);
+                       tags->rqs[i] = p;
+                       if (set->ops->init_request) {
+                               if (set->ops->init_request(set->driver_data,
+                                               tags->rqs[i], hctx_idx, i,
+                                               set->numa_node))
+                                       goto fail;
+                       }
+
                        p += rq_size;
                        i++;
                }
        }
 
-       if (i < (reserved_tags + BLK_MQ_TAG_MIN))
-               goto err_rq_map;
-       else if (i != hctx->queue_depth) {
-               hctx->queue_depth = i;
-               pr_warn("%s: queue depth set to %u because of low memory\n",
-                                       __func__, i);
-       }
-
-       hctx->tags = blk_mq_init_tags(hctx->queue_depth, reserved_tags, node);
-       if (!hctx->tags) {
-err_rq_map:
-               blk_mq_free_rq_map(hctx);
-               return -ENOMEM;
-       }
+       return tags;
 
-       return 0;
+fail:
+       pr_warn("%s: failed to allocate requests\n", __func__);
+       blk_mq_free_rq_map(set, tags, hctx_idx);
+       return NULL;
 }
 
 static int blk_mq_init_hw_queues(struct request_queue *q,
-                                struct blk_mq_reg *reg, void *driver_data)
+               struct blk_mq_tag_set *set)
 {
        struct blk_mq_hw_ctx *hctx;
        unsigned int i, j;
@@ -1180,23 +1261,22 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
 
                node = hctx->numa_node;
                if (node == NUMA_NO_NODE)
-                       node = hctx->numa_node = reg->numa_node;
+                       node = hctx->numa_node = set->numa_node;
 
-               INIT_DELAYED_WORK(&hctx->delayed_work, blk_mq_work_fn);
+               INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn);
+               INIT_DELAYED_WORK(&hctx->delay_work, blk_mq_delay_work_fn);
                spin_lock_init(&hctx->lock);
                INIT_LIST_HEAD(&hctx->dispatch);
                hctx->queue = q;
                hctx->queue_num = i;
-               hctx->flags = reg->flags;
-               hctx->queue_depth = reg->queue_depth;
-               hctx->cmd_size = reg->cmd_size;
+               hctx->flags = set->flags;
+               hctx->cmd_size = set->cmd_size;
 
                blk_mq_init_cpu_notifier(&hctx->cpu_notifier,
                                                blk_mq_hctx_notify, hctx);
                blk_mq_register_cpu_notifier(&hctx->cpu_notifier);
 
-               if (blk_mq_init_rq_map(hctx, reg->reserved_tags, node))
-                       break;
+               hctx->tags = set->tags[i];
 
                /*
                 * Allocate space for all possible cpus to avoid allocation in
@@ -1216,8 +1296,8 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
                hctx->nr_ctx_map = num_maps;
                hctx->nr_ctx = 0;
 
-               if (reg->ops->init_hctx &&
-                   reg->ops->init_hctx(hctx, driver_data, i))
+               if (set->ops->init_hctx &&
+                   set->ops->init_hctx(hctx, set->driver_data, i))
                        break;
        }
 
@@ -1231,12 +1311,12 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
                if (i == j)
                        break;
 
-               if (reg->ops->exit_hctx)
-                       reg->ops->exit_hctx(hctx, j);
+               if (set->ops->exit_hctx)
+                       set->ops->exit_hctx(hctx, j);
 
                blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
-               blk_mq_free_rq_map(hctx);
                kfree(hctx->ctxs);
+               kfree(hctx->ctx_map);
        }
 
        return 1;
@@ -1258,12 +1338,13 @@ static void blk_mq_init_cpu_queues(struct request_queue *q,
                __ctx->queue = q;
 
                /* If the cpu isn't online, the cpu is mapped to first hctx */
-               hctx = q->mq_ops->map_queue(q, i);
-               hctx->nr_ctx++;
-
                if (!cpu_online(i))
                        continue;
 
+               hctx = q->mq_ops->map_queue(q, i);
+               cpumask_set_cpu(i, hctx->cpumask);
+               hctx->nr_ctx++;
+
                /*
                 * Set local node, IFF we have more than one hw queue. If
                 * not, we remain on the home node of the device
@@ -1280,6 +1361,7 @@ static void blk_mq_map_swqueue(struct request_queue *q)
        struct blk_mq_ctx *ctx;
 
        queue_for_each_hw_ctx(q, hctx, i) {
+               cpumask_clear(hctx->cpumask);
                hctx->nr_ctx = 0;
        }
 
@@ -1288,59 +1370,50 @@ static void blk_mq_map_swqueue(struct request_queue *q)
         */
        queue_for_each_ctx(q, ctx, i) {
                /* If the cpu isn't online, the cpu is mapped to first hctx */
+               if (!cpu_online(i))
+                       continue;
+
                hctx = q->mq_ops->map_queue(q, i);
+               cpumask_set_cpu(i, hctx->cpumask);
                ctx->index_hw = hctx->nr_ctx;
                hctx->ctxs[hctx->nr_ctx++] = ctx;
        }
 }
 
-struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
-                                       void *driver_data)
+struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 {
        struct blk_mq_hw_ctx **hctxs;
        struct blk_mq_ctx *ctx;
        struct request_queue *q;
        int i;
 
-       if (!reg->nr_hw_queues ||
-           !reg->ops->queue_rq || !reg->ops->map_queue ||
-           !reg->ops->alloc_hctx || !reg->ops->free_hctx)
-               return ERR_PTR(-EINVAL);
-
-       if (!reg->queue_depth)
-               reg->queue_depth = BLK_MQ_MAX_DEPTH;
-       else if (reg->queue_depth > BLK_MQ_MAX_DEPTH) {
-               pr_err("blk-mq: queuedepth too large (%u)\n", reg->queue_depth);
-               reg->queue_depth = BLK_MQ_MAX_DEPTH;
-       }
-
-       if (reg->queue_depth < (reg->reserved_tags + BLK_MQ_TAG_MIN))
-               return ERR_PTR(-EINVAL);
-
        ctx = alloc_percpu(struct blk_mq_ctx);
        if (!ctx)
                return ERR_PTR(-ENOMEM);
 
-       hctxs = kmalloc_node(reg->nr_hw_queues * sizeof(*hctxs), GFP_KERNEL,
-                       reg->numa_node);
+       hctxs = kmalloc_node(set->nr_hw_queues * sizeof(*hctxs), GFP_KERNEL,
+                       set->numa_node);
 
        if (!hctxs)
                goto err_percpu;
 
-       for (i = 0; i < reg->nr_hw_queues; i++) {
-               hctxs[i] = reg->ops->alloc_hctx(reg, i);
+       for (i = 0; i < set->nr_hw_queues; i++) {
+               hctxs[i] = set->ops->alloc_hctx(set, i);
                if (!hctxs[i])
                        goto err_hctxs;
 
+               if (!zalloc_cpumask_var(&hctxs[i]->cpumask, GFP_KERNEL))
+                       goto err_hctxs;
+
                hctxs[i]->numa_node = NUMA_NO_NODE;
                hctxs[i]->queue_num = i;
        }
 
-       q = blk_alloc_queue_node(GFP_KERNEL, reg->numa_node);
+       q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node);
        if (!q)
                goto err_hctxs;
 
-       q->mq_map = blk_mq_make_queue_map(reg);
+       q->mq_map = blk_mq_make_queue_map(set);
        if (!q->mq_map)
                goto err_map;
 
@@ -1348,33 +1421,34 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
        blk_queue_rq_timeout(q, 30000);
 
        q->nr_queues = nr_cpu_ids;
-       q->nr_hw_queues = reg->nr_hw_queues;
+       q->nr_hw_queues = set->nr_hw_queues;
 
        q->queue_ctx = ctx;
        q->queue_hw_ctx = hctxs;
 
-       q->mq_ops = reg->ops;
+       q->mq_ops = set->ops;
        q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT;
 
        q->sg_reserved_size = INT_MAX;
 
        blk_queue_make_request(q, blk_mq_make_request);
-       blk_queue_rq_timed_out(q, reg->ops->timeout);
-       if (reg->timeout)
-               blk_queue_rq_timeout(q, reg->timeout);
+       blk_queue_rq_timed_out(q, blk_mq_rq_timed_out);
+       if (set->timeout)
+               blk_queue_rq_timeout(q, set->timeout);
 
-       if (reg->ops->complete)
-               blk_queue_softirq_done(q, reg->ops->complete);
+       if (set->ops->complete)
+               blk_queue_softirq_done(q, set->ops->complete);
 
        blk_mq_init_flush(q);
-       blk_mq_init_cpu_queues(q, reg->nr_hw_queues);
+       blk_mq_init_cpu_queues(q, set->nr_hw_queues);
 
-       q->flush_rq = kzalloc(round_up(sizeof(struct request) + reg->cmd_size,
-                               cache_line_size()), GFP_KERNEL);
+       q->flush_rq = kzalloc(round_up(sizeof(struct request) +
+                               set->cmd_size, cache_line_size()),
+                               GFP_KERNEL);
        if (!q->flush_rq)
                goto err_hw;
 
-       if (blk_mq_init_hw_queues(q, reg, driver_data))
+       if (blk_mq_init_hw_queues(q, set))
                goto err_flush_rq;
 
        blk_mq_map_swqueue(q);
@@ -1392,10 +1466,11 @@ err_hw:
 err_map:
        blk_cleanup_queue(q);
 err_hctxs:
-       for (i = 0; i < reg->nr_hw_queues; i++) {
+       for (i = 0; i < set->nr_hw_queues; i++) {
                if (!hctxs[i])
                        break;
-               reg->ops->free_hctx(hctxs[i], i);
+               free_cpumask_var(hctxs[i]->cpumask);
+               set->ops->free_hctx(hctxs[i], i);
        }
        kfree(hctxs);
 err_percpu:
@@ -1412,10 +1487,10 @@ void blk_mq_free_queue(struct request_queue *q)
        queue_for_each_hw_ctx(q, hctx, i) {
                kfree(hctx->ctx_map);
                kfree(hctx->ctxs);
-               blk_mq_free_rq_map(hctx);
                blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
                if (q->mq_ops->exit_hctx)
                        q->mq_ops->exit_hctx(hctx, i);
+               free_cpumask_var(hctx->cpumask);
                q->mq_ops->free_hctx(hctx, i);
        }
 
@@ -1472,6 +1547,55 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
        return NOTIFY_OK;
 }
 
+int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
+{
+       int i;
+
+       if (!set->nr_hw_queues)
+               return -EINVAL;
+       if (!set->queue_depth || set->queue_depth > BLK_MQ_MAX_DEPTH)
+               return -EINVAL;
+       if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN)
+               return -EINVAL;
+
+       if (!set->nr_hw_queues ||
+           !set->ops->queue_rq || !set->ops->map_queue ||
+           !set->ops->alloc_hctx || !set->ops->free_hctx)
+               return -EINVAL;
+
+
+       set->tags = kmalloc_node(set->nr_hw_queues *
+                                sizeof(struct blk_mq_tags *),
+                                GFP_KERNEL, set->numa_node);
+       if (!set->tags)
+               goto out;
+
+       for (i = 0; i < set->nr_hw_queues; i++) {
+               set->tags[i] = blk_mq_init_rq_map(set, i);
+               if (!set->tags[i])
+                       goto out_unwind;
+       }
+
+       return 0;
+
+out_unwind:
+       while (--i >= 0)
+               blk_mq_free_rq_map(set, set->tags[i], i);
+out:
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(blk_mq_alloc_tag_set);
+
+void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
+{
+       int i;
+
+       for (i = 0; i < set->nr_hw_queues; i++)
+               blk_mq_free_rq_map(set, set->tags[i], i);
+       kfree(set->tags);
+}
+EXPORT_SYMBOL(blk_mq_free_tag_set);
+
 void blk_mq_disable_hotplug(void)
 {
        mutex_lock(&all_q_mutex);
index ebbe6bac9d616d4a47a815870dc9d3682403c9d1..1ae364ceaf8bbaae6f33c07cb3292c8341807ac2 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef INT_BLK_MQ_H
 #define INT_BLK_MQ_H
 
+struct blk_mq_tag_set;
+
 struct blk_mq_ctx {
        struct {
                spinlock_t              lock;
@@ -9,7 +11,6 @@ struct blk_mq_ctx {
 
        unsigned int            cpu;
        unsigned int            index_hw;
-       unsigned int            ipi_redirect;
 
        /* incremented at dispatch time */
        unsigned long           rq_dispatched[2];
@@ -27,7 +28,8 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
 void blk_mq_init_flush(struct request_queue *q);
 void blk_mq_drain_queue(struct request_queue *q);
 void blk_mq_free_queue(struct request_queue *q);
-void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq);
+void blk_mq_clone_flush_request(struct request *flush_rq,
+               struct request *orig_rq);
 
 /*
  * CPU hotplug helpers
@@ -45,10 +47,7 @@ void blk_mq_disable_hotplug(void);
 /*
  * CPU -> queue mappings
  */
-struct blk_mq_reg;
-extern unsigned int *blk_mq_make_queue_map(struct blk_mq_reg *reg);
+extern unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set);
 extern int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues);
 
-void blk_mq_add_timer(struct request *rq);
-
 #endif
index 033745cd7fba62b299301860f4ee0f50ec2ff04e..9353b468335930f32e9e82b160d8a40930eca839 100644 (file)
@@ -744,7 +744,7 @@ static inline void throtl_extend_slice(struct throtl_grp *tg, bool rw,
 static bool throtl_slice_used(struct throtl_grp *tg, bool rw)
 {
        if (time_in_range(jiffies, tg->slice_start[rw], tg->slice_end[rw]))
-               return 0;
+               return false;
 
        return 1;
 }
@@ -842,7 +842,7 @@ static bool tg_with_in_iops_limit(struct throtl_grp *tg, struct bio *bio,
        if (tg->io_disp[rw] + 1 <= io_allowed) {
                if (wait)
                        *wait = 0;
-               return 1;
+               return true;
        }
 
        /* Calc approx time to dispatch */
@@ -880,7 +880,7 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio,
        if (tg->bytes_disp[rw] + bio->bi_iter.bi_size <= bytes_allowed) {
                if (wait)
                        *wait = 0;
-               return 1;
+               return true;
        }
 
        /* Calc approx time to dispatch */
@@ -923,7 +923,7 @@ static bool tg_may_dispatch(struct throtl_grp *tg, struct bio *bio,
        if (tg->bps[rw] == -1 && tg->iops[rw] == -1) {
                if (wait)
                        *wait = 0;
-               return 1;
+               return true;
        }
 
        /*
@@ -1258,7 +1258,7 @@ out_unlock:
  * of throtl_data->service_queue.  Those bio's are ready and issued by this
  * function.
  */
-void blk_throtl_dispatch_work_fn(struct work_struct *work)
+static void blk_throtl_dispatch_work_fn(struct work_struct *work)
 {
        struct throtl_data *td = container_of(work, struct throtl_data,
                                              dispatch_work);
index d96f7061c6fd8727de9eb9fc02fae7b07dd357c1..448745683d28bce7eb9c2666c7c263891f597e21 100644 (file)
@@ -96,11 +96,7 @@ static void blk_rq_timed_out(struct request *req)
                        __blk_complete_request(req);
                break;
        case BLK_EH_RESET_TIMER:
-               if (q->mq_ops)
-                       blk_mq_add_timer(req);
-               else
-                       blk_add_timer(req);
-
+               blk_add_timer(req);
                blk_clear_rq_complete(req);
                break;
        case BLK_EH_NOT_HANDLED:
@@ -170,7 +166,15 @@ void blk_abort_request(struct request *req)
 }
 EXPORT_SYMBOL_GPL(blk_abort_request);
 
-void __blk_add_timer(struct request *req, struct list_head *timeout_list)
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:       request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer. When the request completes, we cancel the timer.
+ */
+void blk_add_timer(struct request *req)
 {
        struct request_queue *q = req->q;
        unsigned long expiry;
@@ -188,8 +192,8 @@ void __blk_add_timer(struct request *req, struct list_head *timeout_list)
                req->timeout = q->rq_timeout;
 
        req->deadline = jiffies + req->timeout;
-       if (timeout_list)
-               list_add_tail(&req->timeout_list, timeout_list);
+       if (!q->mq_ops)
+               list_add_tail(&req->timeout_list, &req->q->timeout_list);
 
        /*
         * If the timer isn't already pending or this timeout is earlier
@@ -199,21 +203,18 @@ void __blk_add_timer(struct request *req, struct list_head *timeout_list)
        expiry = round_jiffies_up(req->deadline);
 
        if (!timer_pending(&q->timeout) ||
-           time_before(expiry, q->timeout.expires))
-               mod_timer(&q->timeout, expiry);
+           time_before(expiry, q->timeout.expires)) {
+               unsigned long diff = q->timeout.expires - expiry;
 
-}
+               /*
+                * Due to added timer slack to group timers, the timer
+                * will often be a little in front of what we asked for.
+                * So apply some tolerance here too, otherwise we keep
+                * modifying the timer because expires for value X
+                * will be X + something.
+                */
+               if (diff >= HZ / 2)
+                       mod_timer(&q->timeout, expiry);
+       }
 
-/**
- * blk_add_timer - Start timeout timer for a single request
- * @req:       request that is about to start running.
- *
- * Notes:
- *    Each request has its own timer, and as it is added to the queue, we
- *    set up the timer. When the request completes, we cancel the timer.
- */
-void blk_add_timer(struct request *req)
-{
-       __blk_add_timer(req, &req->q->timeout_list);
 }
-
index 1d880f1f957fe473fbb0f78ad8ad03a3726faa73..79be2cbce7fd371701c22744f5c200a4808490bc 100644 (file)
@@ -37,9 +37,8 @@ bool __blk_end_bidi_request(struct request *rq, int error,
 void blk_rq_timed_out_timer(unsigned long data);
 void blk_rq_check_expired(struct request *rq, unsigned long *next_timeout,
                          unsigned int *next_set);
-void __blk_add_timer(struct request *req, struct list_head *timeout_list);
+void blk_add_timer(struct request *req);
 void blk_delete_timer(struct request *);
-void blk_add_timer(struct request *);
 
 
 bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
index 420a5a9f1b23f72963dc928b2dd009be443e3337..e5214c1480962e5d53c0f0ced44af571051d9654 100644 (file)
@@ -1008,7 +1008,7 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
        /*
         * we need a proper transport to send commands, not a stacked device
         */
-       if (!q->request_fn)
+       if (!queue_is_rq_based(q))
                return 0;
 
        bcd = &q->bsg_dev;
index e0985f1955e7e0ea513ddf9cea104d571626a592..22dffebc7c73531ec235e27e188f66fa88b677d8 100644 (file)
@@ -908,7 +908,7 @@ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
 {
        if (cfqd->busy_queues) {
                cfq_log(cfqd, "schedule dispatch");
-               kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work);
+               kblockd_schedule_work(&cfqd->unplug_work);
        }
 }
 
@@ -4460,7 +4460,7 @@ out_free:
 static ssize_t
 cfq_var_show(unsigned int var, char *page)
 {
-       return sprintf(page, "%d\n", var);
+       return sprintf(page, "%u\n", var);
 }
 
 static ssize_t
index 1512e41cd93d74a4e7ab3fde6809e64468f797a8..43665d0d0905ddddf018fe68655c1ff7685b0b9e 100644 (file)
@@ -466,7 +466,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        type -= CRYPTO_MSG_BASE;
        link = &crypto_dispatch[type];
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
index 870be7b4dc0529b1a9722e569eaccd71092623e3..09c93ff216e41df6ba89b9d9c9b51fc8f46e8033 100644 (file)
@@ -282,6 +282,11 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec,
        unsigned int *b_size;
        unsigned int iv_len;
 
+       if (aad_size >= PAGE_SIZE) {
+               pr_err("associate data length (%u) too big\n", aad_size);
+               return;
+       }
+
        if (enc == ENCRYPT)
                e = "encryption";
        else
@@ -308,14 +313,14 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec,
        if (IS_ERR(tfm)) {
                pr_err("alg: aead: Failed to load transform for %s: %ld\n", algo,
                       PTR_ERR(tfm));
-               return;
+               goto out_notfm;
        }
 
        req = aead_request_alloc(tfm, GFP_KERNEL);
        if (!req) {
                pr_err("alg: aead: Failed to allocate request for %s\n",
                       algo);
-               goto out;
+               goto out_noreq;
        }
 
        i = 0;
@@ -323,14 +328,7 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec,
                b_size = aead_sizes;
                do {
                        assoc = axbuf[0];
-
-                       if (aad_size < PAGE_SIZE)
-                               memset(assoc, 0xff, aad_size);
-                       else {
-                               pr_err("associate data length (%u) too big\n",
-                                       aad_size);
-                               goto out_nosg;
-                       }
+                       memset(assoc, 0xff, aad_size);
                        sg_init_one(&asg[0], assoc, aad_size);
 
                        if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) {
@@ -392,7 +390,10 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec,
        } while (*keysize);
 
 out:
+       aead_request_free(req);
+out_noreq:
        crypto_free_aead(tfm);
+out_notfm:
        kfree(sg);
 out_nosg:
        testmgr_free_buf(xoutbuf);
index 3db83dbba1d939d19800cb2d7439417ddfece4ff..3c95bda11d519fde9dae3eda93254823da1e1562 100644 (file)
@@ -487,10 +487,15 @@ static struct hash_testvec crct10dif_tv_template[] = {
  * SHA1 test vectors  from from FIPS PUB 180-1
  * Long vector from CAVS 5.0
  */
-#define SHA1_TEST_VECTORS      3
+#define SHA1_TEST_VECTORS      6
 
 static struct hash_testvec sha1_tv_template[] = {
        {
+               .plaintext = "",
+               .psize  = 0,
+               .digest = "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55"
+                         "\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09",
+       }, {
                .plaintext = "abc",
                .psize  = 3,
                .digest = "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e"
@@ -529,6 +534,144 @@ static struct hash_testvec sha1_tv_template[] = {
                          "\x45\x9c\x02\xb6\x9b\x4a\xa8\xf5\x82\x17",
                .np     = 4,
                .tap    = { 63, 64, 31, 5 }
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+               .psize  = 64,
+               .digest = "\xc8\x71\xf6\x9a\x63\xcc\xa9\x84\x84\x82"
+                         "\x64\xe7\x79\x95\x5d\xd7\x19\x41\x7c\x91",
+       }, {
+               .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3"
+                            "\x7a\x11\x85\x1c\xb3\x27\xbe\x55"
+                            "\xec\x60\xf7\x8e\x02\x99\x30\xc7"
+                            "\x3b\xd2\x69\x00\x74\x0b\xa2\x16"
+                            "\xad\x44\xdb\x4f\xe6\x7d\x14\x88"
+                            "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa"
+                            "\x91\x05\x9c\x33\xca\x3e\xd5\x6c"
+                            "\x03\x77\x0e\xa5\x19\xb0\x47\xde"
+                            "\x52\xe9\x80\x17\x8b\x22\xb9\x2d"
+                            "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f"
+                            "\x36\xcd\x41\xd8\x6f\x06\x7a\x11"
+                            "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83"
+                            "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5"
+                            "\x69\x00\x97\x0b\xa2\x39\xd0\x44"
+                            "\xdb\x72\x09\x7d\x14\xab\x1f\xb6"
+                            "\x4d\xe4\x58\xef\x86\x1d\x91\x28"
+                            "\xbf\x33\xca\x61\xf8\x6c\x03\x9a"
+                            "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c"
+                            "\x80\x17\xae\x22\xb9\x50\xe7\x5b"
+                            "\xf2\x89\x20\x94\x2b\xc2\x36\xcd"
+                            "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f"
+                            "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1"
+                            "\x25\xbc\x53\xea\x5e\xf5\x8c\x00"
+                            "\x97\x2e\xc5\x39\xd0\x67\xfe\x72"
+                            "\x09\xa0\x14\xab\x42\xd9\x4d\xe4"
+                            "\x7b\x12\x86\x1d\xb4\x28\xbf\x56"
+                            "\xed\x61\xf8\x8f\x03\x9a\x31\xc8"
+                            "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17"
+                            "\xae\x45\xdc\x50\xe7\x7e\x15\x89"
+                            "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb"
+                            "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d"
+                            "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf"
+                            "\x53\xea\x81\x18\x8c\x23\xba\x2e"
+                            "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0"
+                            "\x37\xce\x42\xd9\x70\x07\x7b\x12"
+                            "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84"
+                            "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6"
+                            "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45"
+                            "\xdc\x73\x0a\x7e\x15\xac\x20\xb7"
+                            "\x4e\xe5\x59\xf0\x87\x1e\x92\x29"
+                            "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b"
+                            "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d"
+                            "\x81\x18\xaf\x23\xba\x51\xe8\x5c"
+                            "\xf3\x8a\x21\x95\x2c\xc3\x37\xce"
+                            "\x65\xfc\x70\x07\x9e\x12\xa9\x40"
+                            "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2"
+                            "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01"
+                            "\x98\x2f\xc6\x3a\xd1\x68\xff\x73"
+                            "\x0a\xa1\x15\xac\x43\xda\x4e\xe5"
+                            "\x7c\x13\x87\x1e\xb5\x29\xc0\x57"
+                            "\xee\x62\xf9\x90\x04\x9b\x32\xc9"
+                            "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18"
+                            "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a"
+                            "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc"
+                            "\x93\x07\x9e\x35\xcc\x40\xd7\x6e"
+                            "\x05\x79\x10\xa7\x1b\xb2\x49\xe0"
+                            "\x54\xeb\x82\x19\x8d\x24\xbb\x2f"
+                            "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1"
+                            "\x38\xcf\x43\xda\x71\x08\x7c\x13"
+                            "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85"
+                            "\x1c\x90\x27\xbe\x32\xc9\x60\xf7"
+                            "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46"
+                            "\xdd\x74\x0b\x7f\x16\xad\x21\xb8"
+                            "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a"
+                            "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c"
+                            "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e"
+                            "\x82\x19\xb0\x24\xbb\x52\xe9\x5d"
+                            "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf"
+                            "\x66\xfd\x71\x08\x9f\x13\xaa\x41"
+                            "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3"
+                            "\x27\xbe\x55\xec\x60\xf7\x8e\x02"
+                            "\x99\x30\xc7\x3b\xd2\x69\x00\x74"
+                            "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6"
+                            "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58"
+                            "\xef\x63\xfa\x91\x05\x9c\x33\xca"
+                            "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19"
+                            "\xb0\x47\xde\x52\xe9\x80\x17\x8b"
+                            "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd"
+                            "\x94\x08\x9f\x36\xcd\x41\xd8\x6f"
+                            "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1"
+                            "\x55\xec\x83\x1a\x8e\x25\xbc\x30"
+                            "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2"
+                            "\x39\xd0\x44\xdb\x72\x09\x7d\x14"
+                            "\xab\x1f\xb6\x4d\xe4\x58\xef\x86"
+                            "\x1d\x91\x28\xbf\x33\xca\x61\xf8"
+                            "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47"
+                            "\xde\x75\x0c\x80\x17\xae\x22\xb9"
+                            "\x50\xe7\x5b\xf2\x89\x20\x94\x2b"
+                            "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d"
+                            "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f"
+                            "\x83\x1a\xb1\x25\xbc\x53\xea\x5e"
+                            "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0"
+                            "\x67\xfe\x72\x09\xa0\x14\xab\x42"
+                            "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4"
+                            "\x28\xbf\x56\xed\x61\xf8\x8f\x03"
+                            "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75"
+                            "\x0c\xa3\x17\xae\x45\xdc\x50\xe7"
+                            "\x7e\x15\x89\x20\xb7\x2b\xc2\x59"
+                            "\xf0\x64\xfb\x92\x06\x9d\x34\xcb"
+                            "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a"
+                            "\xb1\x48\xdf\x53\xea\x81\x18\x8c"
+                            "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe"
+                            "\x95\x09\xa0\x37\xce\x42\xd9\x70"
+                            "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2"
+                            "\x56\xed\x84\x1b\x8f\x26\xbd\x31"
+                            "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3"
+                            "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15"
+                            "\xac\x20\xb7\x4e\xe5\x59\xf0\x87"
+                            "\x1e\x92\x29\xc0\x34\xcb\x62\xf9"
+                            "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48"
+                            "\xdf\x76\x0d\x81\x18\xaf\x23\xba"
+                            "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c"
+                            "\xc3\x37\xce\x65\xfc\x70\x07\x9e"
+                            "\x12\xa9\x40\xd7\x4b\xe2\x79\x10"
+                            "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f"
+                            "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1"
+                            "\x68\xff\x73\x0a\xa1\x15\xac\x43"
+                            "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5"
+                            "\x29\xc0\x57\xee\x62\xf9\x90\x04"
+                            "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76"
+                            "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8"
+                            "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a"
+                            "\xf1\x65\xfc\x93\x07\x9e\x35\xcc"
+                            "\x40\xd7\x6e\x05\x79\x10\xa7\x1b"
+                            "\xb2\x49\xe0\x54\xeb\x82\x19\x8d"
+                            "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff"
+                            "\x96\x0a\xa1\x38\xcf\x43\xda\x71"
+                            "\x08\x7c\x13\xaa\x1e\xb5\x4c",
+               .psize     = 1023,
+               .digest    = "\xb8\xe3\x54\xed\xc5\xfc\xef\xa4"
+                            "\x55\x73\x4a\x81\x99\xe4\x47\x2a"
+                            "\x30\xd6\xc9\x85",
        }
 };
 
@@ -536,10 +679,17 @@ static struct hash_testvec sha1_tv_template[] = {
 /*
  * SHA224 test vectors from from FIPS PUB 180-2
  */
-#define SHA224_TEST_VECTORS     2
+#define SHA224_TEST_VECTORS     5
 
 static struct hash_testvec sha224_tv_template[] = {
        {
+               .plaintext = "",
+               .psize  = 0,
+               .digest = "\xd1\x4a\x02\x8c\x2a\x3a\x2b\xc9"
+                         "\x47\x61\x02\xbb\x28\x82\x34\xc4"
+                         "\x15\xa2\xb0\x1f\x82\x8e\xa6\x2a"
+                         "\xc5\xb3\xe4\x2f",
+       }, {
                .plaintext = "abc",
                .psize  = 3,
                .digest = "\x23\x09\x7D\x22\x34\x05\xD8\x22"
@@ -556,16 +706,164 @@ static struct hash_testvec sha224_tv_template[] = {
                          "\x52\x52\x25\x25",
                .np     = 2,
                .tap    = { 28, 28 }
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+               .psize  = 64,
+               .digest = "\xc4\xdb\x2b\x3a\x58\xc3\x99\x01"
+                         "\x42\xfd\x10\x92\xaa\x4e\x04\x08"
+                         "\x58\xbb\xbb\xe8\xf8\x14\xa7\x0c"
+                         "\xef\x3b\xcb\x0e",
+       }, {
+               .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3"
+                            "\x7a\x11\x85\x1c\xb3\x27\xbe\x55"
+                            "\xec\x60\xf7\x8e\x02\x99\x30\xc7"
+                            "\x3b\xd2\x69\x00\x74\x0b\xa2\x16"
+                            "\xad\x44\xdb\x4f\xe6\x7d\x14\x88"
+                            "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa"
+                            "\x91\x05\x9c\x33\xca\x3e\xd5\x6c"
+                            "\x03\x77\x0e\xa5\x19\xb0\x47\xde"
+                            "\x52\xe9\x80\x17\x8b\x22\xb9\x2d"
+                            "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f"
+                            "\x36\xcd\x41\xd8\x6f\x06\x7a\x11"
+                            "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83"
+                            "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5"
+                            "\x69\x00\x97\x0b\xa2\x39\xd0\x44"
+                            "\xdb\x72\x09\x7d\x14\xab\x1f\xb6"
+                            "\x4d\xe4\x58\xef\x86\x1d\x91\x28"
+                            "\xbf\x33\xca\x61\xf8\x6c\x03\x9a"
+                            "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c"
+                            "\x80\x17\xae\x22\xb9\x50\xe7\x5b"
+                            "\xf2\x89\x20\x94\x2b\xc2\x36\xcd"
+                            "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f"
+                            "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1"
+                            "\x25\xbc\x53\xea\x5e\xf5\x8c\x00"
+                            "\x97\x2e\xc5\x39\xd0\x67\xfe\x72"
+                            "\x09\xa0\x14\xab\x42\xd9\x4d\xe4"
+                            "\x7b\x12\x86\x1d\xb4\x28\xbf\x56"
+                            "\xed\x61\xf8\x8f\x03\x9a\x31\xc8"
+                            "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17"
+                            "\xae\x45\xdc\x50\xe7\x7e\x15\x89"
+                            "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb"
+                            "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d"
+                            "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf"
+                            "\x53\xea\x81\x18\x8c\x23\xba\x2e"
+                            "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0"
+                            "\x37\xce\x42\xd9\x70\x07\x7b\x12"
+                            "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84"
+                            "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6"
+                            "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45"
+                            "\xdc\x73\x0a\x7e\x15\xac\x20\xb7"
+                            "\x4e\xe5\x59\xf0\x87\x1e\x92\x29"
+                            "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b"
+                            "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d"
+                            "\x81\x18\xaf\x23\xba\x51\xe8\x5c"
+                            "\xf3\x8a\x21\x95\x2c\xc3\x37\xce"
+                            "\x65\xfc\x70\x07\x9e\x12\xa9\x40"
+                            "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2"
+                            "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01"
+                            "\x98\x2f\xc6\x3a\xd1\x68\xff\x73"
+                            "\x0a\xa1\x15\xac\x43\xda\x4e\xe5"
+                            "\x7c\x13\x87\x1e\xb5\x29\xc0\x57"
+                            "\xee\x62\xf9\x90\x04\x9b\x32\xc9"
+                            "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18"
+                            "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a"
+                            "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc"
+                            "\x93\x07\x9e\x35\xcc\x40\xd7\x6e"
+                            "\x05\x79\x10\xa7\x1b\xb2\x49\xe0"
+                            "\x54\xeb\x82\x19\x8d\x24\xbb\x2f"
+                            "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1"
+                            "\x38\xcf\x43\xda\x71\x08\x7c\x13"
+                            "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85"
+                            "\x1c\x90\x27\xbe\x32\xc9\x60\xf7"
+                            "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46"
+                            "\xdd\x74\x0b\x7f\x16\xad\x21\xb8"
+                            "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a"
+                            "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c"
+                            "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e"
+                            "\x82\x19\xb0\x24\xbb\x52\xe9\x5d"
+                            "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf"
+                            "\x66\xfd\x71\x08\x9f\x13\xaa\x41"
+                            "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3"
+                            "\x27\xbe\x55\xec\x60\xf7\x8e\x02"
+                            "\x99\x30\xc7\x3b\xd2\x69\x00\x74"
+                            "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6"
+                            "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58"
+                            "\xef\x63\xfa\x91\x05\x9c\x33\xca"
+                            "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19"
+                            "\xb0\x47\xde\x52\xe9\x80\x17\x8b"
+                            "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd"
+                            "\x94\x08\x9f\x36\xcd\x41\xd8\x6f"
+                            "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1"
+                            "\x55\xec\x83\x1a\x8e\x25\xbc\x30"
+                            "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2"
+                            "\x39\xd0\x44\xdb\x72\x09\x7d\x14"
+                            "\xab\x1f\xb6\x4d\xe4\x58\xef\x86"
+                            "\x1d\x91\x28\xbf\x33\xca\x61\xf8"
+                            "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47"
+                            "\xde\x75\x0c\x80\x17\xae\x22\xb9"
+                            "\x50\xe7\x5b\xf2\x89\x20\x94\x2b"
+                            "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d"
+                            "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f"
+                            "\x83\x1a\xb1\x25\xbc\x53\xea\x5e"
+                            "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0"
+                            "\x67\xfe\x72\x09\xa0\x14\xab\x42"
+                            "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4"
+                            "\x28\xbf\x56\xed\x61\xf8\x8f\x03"
+                            "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75"
+                            "\x0c\xa3\x17\xae\x45\xdc\x50\xe7"
+                            "\x7e\x15\x89\x20\xb7\x2b\xc2\x59"
+                            "\xf0\x64\xfb\x92\x06\x9d\x34\xcb"
+                            "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a"
+                            "\xb1\x48\xdf\x53\xea\x81\x18\x8c"
+                            "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe"
+                            "\x95\x09\xa0\x37\xce\x42\xd9\x70"
+                            "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2"
+                            "\x56\xed\x84\x1b\x8f\x26\xbd\x31"
+                            "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3"
+                            "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15"
+                            "\xac\x20\xb7\x4e\xe5\x59\xf0\x87"
+                            "\x1e\x92\x29\xc0\x34\xcb\x62\xf9"
+                            "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48"
+                            "\xdf\x76\x0d\x81\x18\xaf\x23\xba"
+                            "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c"
+                            "\xc3\x37\xce\x65\xfc\x70\x07\x9e"
+                            "\x12\xa9\x40\xd7\x4b\xe2\x79\x10"
+                            "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f"
+                            "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1"
+                            "\x68\xff\x73\x0a\xa1\x15\xac\x43"
+                            "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5"
+                            "\x29\xc0\x57\xee\x62\xf9\x90\x04"
+                            "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76"
+                            "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8"
+                            "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a"
+                            "\xf1\x65\xfc\x93\x07\x9e\x35\xcc"
+                            "\x40\xd7\x6e\x05\x79\x10\xa7\x1b"
+                            "\xb2\x49\xe0\x54\xeb\x82\x19\x8d"
+                            "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff"
+                            "\x96\x0a\xa1\x38\xcf\x43\xda\x71"
+                            "\x08\x7c\x13\xaa\x1e\xb5\x4c",
+               .psize     = 1023,
+               .digest    = "\x98\x43\x07\x63\x75\xe0\xa7\x1c"
+                            "\x78\xb1\x8b\xfd\x04\xf5\x2d\x91"
+                            "\x20\x48\xa4\x28\xff\x55\xb1\xd3"
+                            "\xe6\xf9\x4f\xcc",
        }
 };
 
 /*
  * SHA256 test vectors from from NIST
  */
-#define SHA256_TEST_VECTORS    2
+#define SHA256_TEST_VECTORS    5
 
 static struct hash_testvec sha256_tv_template[] = {
        {
+               .plaintext = "",
+               .psize  = 0,
+               .digest = "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14"
+                         "\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24"
+                         "\x27\xae\x41\xe4\x64\x9b\x93\x4c"
+                         "\xa4\x95\x99\x1b\x78\x52\xb8\x55",
+       }, {
                .plaintext = "abc",
                .psize  = 3,
                .digest = "\xba\x78\x16\xbf\x8f\x01\xcf\xea"
@@ -581,16 +879,166 @@ static struct hash_testvec sha256_tv_template[] = {
                          "\xf6\xec\xed\xd4\x19\xdb\x06\xc1",
                .np     = 2,
                .tap    = { 28, 28 }
-       },
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+               .psize  = 64,
+               .digest = "\xb5\xfe\xad\x56\x7d\xff\xcb\xa4"
+                         "\x2c\x32\x29\x32\x19\xbb\xfb\xfa"
+                         "\xd6\xff\x94\xa3\x72\x91\x85\x66"
+                         "\x3b\xa7\x87\x77\x58\xa3\x40\x3a",
+       }, {
+               .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3"
+                            "\x7a\x11\x85\x1c\xb3\x27\xbe\x55"
+                            "\xec\x60\xf7\x8e\x02\x99\x30\xc7"
+                            "\x3b\xd2\x69\x00\x74\x0b\xa2\x16"
+                            "\xad\x44\xdb\x4f\xe6\x7d\x14\x88"
+                            "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa"
+                            "\x91\x05\x9c\x33\xca\x3e\xd5\x6c"
+                            "\x03\x77\x0e\xa5\x19\xb0\x47\xde"
+                            "\x52\xe9\x80\x17\x8b\x22\xb9\x2d"
+                            "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f"
+                            "\x36\xcd\x41\xd8\x6f\x06\x7a\x11"
+                            "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83"
+                            "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5"
+                            "\x69\x00\x97\x0b\xa2\x39\xd0\x44"
+                            "\xdb\x72\x09\x7d\x14\xab\x1f\xb6"
+                            "\x4d\xe4\x58\xef\x86\x1d\x91\x28"
+                            "\xbf\x33\xca\x61\xf8\x6c\x03\x9a"
+                            "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c"
+                            "\x80\x17\xae\x22\xb9\x50\xe7\x5b"
+                            "\xf2\x89\x20\x94\x2b\xc2\x36\xcd"
+                            "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f"
+                            "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1"
+                            "\x25\xbc\x53\xea\x5e\xf5\x8c\x00"
+                            "\x97\x2e\xc5\x39\xd0\x67\xfe\x72"
+                            "\x09\xa0\x14\xab\x42\xd9\x4d\xe4"
+                            "\x7b\x12\x86\x1d\xb4\x28\xbf\x56"
+                            "\xed\x61\xf8\x8f\x03\x9a\x31\xc8"
+                            "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17"
+                            "\xae\x45\xdc\x50\xe7\x7e\x15\x89"
+                            "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb"
+                            "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d"
+                            "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf"
+                            "\x53\xea\x81\x18\x8c\x23\xba\x2e"
+                            "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0"
+                            "\x37\xce\x42\xd9\x70\x07\x7b\x12"
+                            "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84"
+                            "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6"
+                            "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45"
+                            "\xdc\x73\x0a\x7e\x15\xac\x20\xb7"
+                            "\x4e\xe5\x59\xf0\x87\x1e\x92\x29"
+                            "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b"
+                            "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d"
+                            "\x81\x18\xaf\x23\xba\x51\xe8\x5c"
+                            "\xf3\x8a\x21\x95\x2c\xc3\x37\xce"
+                            "\x65\xfc\x70\x07\x9e\x12\xa9\x40"
+                            "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2"
+                            "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01"
+                            "\x98\x2f\xc6\x3a\xd1\x68\xff\x73"
+                            "\x0a\xa1\x15\xac\x43\xda\x4e\xe5"
+                            "\x7c\x13\x87\x1e\xb5\x29\xc0\x57"
+                            "\xee\x62\xf9\x90\x04\x9b\x32\xc9"
+                            "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18"
+                            "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a"
+                            "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc"
+                            "\x93\x07\x9e\x35\xcc\x40\xd7\x6e"
+                            "\x05\x79\x10\xa7\x1b\xb2\x49\xe0"
+                            "\x54\xeb\x82\x19\x8d\x24\xbb\x2f"
+                            "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1"
+                            "\x38\xcf\x43\xda\x71\x08\x7c\x13"
+                            "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85"
+                            "\x1c\x90\x27\xbe\x32\xc9\x60\xf7"
+                            "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46"
+                            "\xdd\x74\x0b\x7f\x16\xad\x21\xb8"
+                            "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a"
+                            "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c"
+                            "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e"
+                            "\x82\x19\xb0\x24\xbb\x52\xe9\x5d"
+                            "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf"
+                            "\x66\xfd\x71\x08\x9f\x13\xaa\x41"
+                            "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3"
+                            "\x27\xbe\x55\xec\x60\xf7\x8e\x02"
+                            "\x99\x30\xc7\x3b\xd2\x69\x00\x74"
+                            "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6"
+                            "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58"
+                            "\xef\x63\xfa\x91\x05\x9c\x33\xca"
+                            "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19"
+                            "\xb0\x47\xde\x52\xe9\x80\x17\x8b"
+                            "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd"
+                            "\x94\x08\x9f\x36\xcd\x41\xd8\x6f"
+                            "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1"
+                            "\x55\xec\x83\x1a\x8e\x25\xbc\x30"
+                            "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2"
+                            "\x39\xd0\x44\xdb\x72\x09\x7d\x14"
+                            "\xab\x1f\xb6\x4d\xe4\x58\xef\x86"
+                            "\x1d\x91\x28\xbf\x33\xca\x61\xf8"
+                            "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47"
+                            "\xde\x75\x0c\x80\x17\xae\x22\xb9"
+                            "\x50\xe7\x5b\xf2\x89\x20\x94\x2b"
+                            "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d"
+                            "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f"
+                            "\x83\x1a\xb1\x25\xbc\x53\xea\x5e"
+                            "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0"
+                            "\x67\xfe\x72\x09\xa0\x14\xab\x42"
+                            "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4"
+                            "\x28\xbf\x56\xed\x61\xf8\x8f\x03"
+                            "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75"
+                            "\x0c\xa3\x17\xae\x45\xdc\x50\xe7"
+                            "\x7e\x15\x89\x20\xb7\x2b\xc2\x59"
+                            "\xf0\x64\xfb\x92\x06\x9d\x34\xcb"
+                            "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a"
+                            "\xb1\x48\xdf\x53\xea\x81\x18\x8c"
+                            "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe"
+                            "\x95\x09\xa0\x37\xce\x42\xd9\x70"
+                            "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2"
+                            "\x56\xed\x84\x1b\x8f\x26\xbd\x31"
+                            "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3"
+                            "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15"
+                            "\xac\x20\xb7\x4e\xe5\x59\xf0\x87"
+                            "\x1e\x92\x29\xc0\x34\xcb\x62\xf9"
+                            "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48"
+                            "\xdf\x76\x0d\x81\x18\xaf\x23\xba"
+                            "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c"
+                            "\xc3\x37\xce\x65\xfc\x70\x07\x9e"
+                            "\x12\xa9\x40\xd7\x4b\xe2\x79\x10"
+                            "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f"
+                            "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1"
+                            "\x68\xff\x73\x0a\xa1\x15\xac\x43"
+                            "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5"
+                            "\x29\xc0\x57\xee\x62\xf9\x90\x04"
+                            "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76"
+                            "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8"
+                            "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a"
+                            "\xf1\x65\xfc\x93\x07\x9e\x35\xcc"
+                            "\x40\xd7\x6e\x05\x79\x10\xa7\x1b"
+                            "\xb2\x49\xe0\x54\xeb\x82\x19\x8d"
+                            "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff"
+                            "\x96\x0a\xa1\x38\xcf\x43\xda\x71"
+                            "\x08\x7c\x13\xaa\x1e\xb5\x4c",
+               .psize     = 1023,
+               .digest    = "\xc5\xce\x0c\xca\x01\x4f\x53\x3a"
+                            "\x32\x32\x17\xcc\xd4\x6a\x71\xa9"
+                            "\xf3\xed\x50\x10\x64\x8e\x06\xbe"
+                            "\x9b\x4a\xa6\xbb\x05\x89\x59\x51",
+       }
 };
 
 /*
  * SHA384 test vectors from from NIST and kerneli
  */
-#define SHA384_TEST_VECTORS    4
+#define SHA384_TEST_VECTORS    6
 
 static struct hash_testvec sha384_tv_template[] = {
        {
+               .plaintext = "",
+               .psize  = 0,
+               .digest = "\x38\xb0\x60\xa7\x51\xac\x96\x38"
+                         "\x4c\xd9\x32\x7e\xb1\xb1\xe3\x6a"
+                         "\x21\xfd\xb7\x11\x14\xbe\x07\x43"
+                         "\x4c\x0c\xc7\xbf\x63\xf6\xe1\xda"
+                         "\x27\x4e\xde\xbf\xe7\x6f\x65\xfb"
+                         "\xd5\x1a\xd2\xf1\x48\x98\xb9\x5b",
+       }, {
                .plaintext= "abc",
                .psize  = 3,
                .digest = "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b"
@@ -630,16 +1078,163 @@ static struct hash_testvec sha384_tv_template[] = {
                          "\xc9\x38\xe2\xd1\x99\xe8\xbe\xa4",
                .np     = 4,
                .tap    = { 26, 26, 26, 26 }
-       },
+       }, {
+               .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3"
+                            "\x7a\x11\x85\x1c\xb3\x27\xbe\x55"
+                            "\xec\x60\xf7\x8e\x02\x99\x30\xc7"
+                            "\x3b\xd2\x69\x00\x74\x0b\xa2\x16"
+                            "\xad\x44\xdb\x4f\xe6\x7d\x14\x88"
+                            "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa"
+                            "\x91\x05\x9c\x33\xca\x3e\xd5\x6c"
+                            "\x03\x77\x0e\xa5\x19\xb0\x47\xde"
+                            "\x52\xe9\x80\x17\x8b\x22\xb9\x2d"
+                            "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f"
+                            "\x36\xcd\x41\xd8\x6f\x06\x7a\x11"
+                            "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83"
+                            "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5"
+                            "\x69\x00\x97\x0b\xa2\x39\xd0\x44"
+                            "\xdb\x72\x09\x7d\x14\xab\x1f\xb6"
+                            "\x4d\xe4\x58\xef\x86\x1d\x91\x28"
+                            "\xbf\x33\xca\x61\xf8\x6c\x03\x9a"
+                            "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c"
+                            "\x80\x17\xae\x22\xb9\x50\xe7\x5b"
+                            "\xf2\x89\x20\x94\x2b\xc2\x36\xcd"
+                            "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f"
+                            "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1"
+                            "\x25\xbc\x53\xea\x5e\xf5\x8c\x00"
+                            "\x97\x2e\xc5\x39\xd0\x67\xfe\x72"
+                            "\x09\xa0\x14\xab\x42\xd9\x4d\xe4"
+                            "\x7b\x12\x86\x1d\xb4\x28\xbf\x56"
+                            "\xed\x61\xf8\x8f\x03\x9a\x31\xc8"
+                            "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17"
+                            "\xae\x45\xdc\x50\xe7\x7e\x15\x89"
+                            "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb"
+                            "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d"
+                            "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf"
+                            "\x53\xea\x81\x18\x8c\x23\xba\x2e"
+                            "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0"
+                            "\x37\xce\x42\xd9\x70\x07\x7b\x12"
+                            "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84"
+                            "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6"
+                            "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45"
+                            "\xdc\x73\x0a\x7e\x15\xac\x20\xb7"
+                            "\x4e\xe5\x59\xf0\x87\x1e\x92\x29"
+                            "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b"
+                            "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d"
+                            "\x81\x18\xaf\x23\xba\x51\xe8\x5c"
+                            "\xf3\x8a\x21\x95\x2c\xc3\x37\xce"
+                            "\x65\xfc\x70\x07\x9e\x12\xa9\x40"
+                            "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2"
+                            "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01"
+                            "\x98\x2f\xc6\x3a\xd1\x68\xff\x73"
+                            "\x0a\xa1\x15\xac\x43\xda\x4e\xe5"
+                            "\x7c\x13\x87\x1e\xb5\x29\xc0\x57"
+                            "\xee\x62\xf9\x90\x04\x9b\x32\xc9"
+                            "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18"
+                            "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a"
+                            "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc"
+                            "\x93\x07\x9e\x35\xcc\x40\xd7\x6e"
+                            "\x05\x79\x10\xa7\x1b\xb2\x49\xe0"
+                            "\x54\xeb\x82\x19\x8d\x24\xbb\x2f"
+                            "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1"
+                            "\x38\xcf\x43\xda\x71\x08\x7c\x13"
+                            "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85"
+                            "\x1c\x90\x27\xbe\x32\xc9\x60\xf7"
+                            "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46"
+                            "\xdd\x74\x0b\x7f\x16\xad\x21\xb8"
+                            "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a"
+                            "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c"
+                            "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e"
+                            "\x82\x19\xb0\x24\xbb\x52\xe9\x5d"
+                            "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf"
+                            "\x66\xfd\x71\x08\x9f\x13\xaa\x41"
+                            "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3"
+                            "\x27\xbe\x55\xec\x60\xf7\x8e\x02"
+                            "\x99\x30\xc7\x3b\xd2\x69\x00\x74"
+                            "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6"
+                            "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58"
+                            "\xef\x63\xfa\x91\x05\x9c\x33\xca"
+                            "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19"
+                            "\xb0\x47\xde\x52\xe9\x80\x17\x8b"
+                            "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd"
+                            "\x94\x08\x9f\x36\xcd\x41\xd8\x6f"
+                            "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1"
+                            "\x55\xec\x83\x1a\x8e\x25\xbc\x30"
+                            "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2"
+                            "\x39\xd0\x44\xdb\x72\x09\x7d\x14"
+                            "\xab\x1f\xb6\x4d\xe4\x58\xef\x86"
+                            "\x1d\x91\x28\xbf\x33\xca\x61\xf8"
+                            "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47"
+                            "\xde\x75\x0c\x80\x17\xae\x22\xb9"
+                            "\x50\xe7\x5b\xf2\x89\x20\x94\x2b"
+                            "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d"
+                            "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f"
+                            "\x83\x1a\xb1\x25\xbc\x53\xea\x5e"
+                            "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0"
+                            "\x67\xfe\x72\x09\xa0\x14\xab\x42"
+                            "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4"
+                            "\x28\xbf\x56\xed\x61\xf8\x8f\x03"
+                            "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75"
+                            "\x0c\xa3\x17\xae\x45\xdc\x50\xe7"
+                            "\x7e\x15\x89\x20\xb7\x2b\xc2\x59"
+                            "\xf0\x64\xfb\x92\x06\x9d\x34\xcb"
+                            "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a"
+                            "\xb1\x48\xdf\x53\xea\x81\x18\x8c"
+                            "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe"
+                            "\x95\x09\xa0\x37\xce\x42\xd9\x70"
+                            "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2"
+                            "\x56\xed\x84\x1b\x8f\x26\xbd\x31"
+                            "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3"
+                            "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15"
+                            "\xac\x20\xb7\x4e\xe5\x59\xf0\x87"
+                            "\x1e\x92\x29\xc0\x34\xcb\x62\xf9"
+                            "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48"
+                            "\xdf\x76\x0d\x81\x18\xaf\x23\xba"
+                            "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c"
+                            "\xc3\x37\xce\x65\xfc\x70\x07\x9e"
+                            "\x12\xa9\x40\xd7\x4b\xe2\x79\x10"
+                            "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f"
+                            "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1"
+                            "\x68\xff\x73\x0a\xa1\x15\xac\x43"
+                            "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5"
+                            "\x29\xc0\x57\xee\x62\xf9\x90\x04"
+                            "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76"
+                            "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8"
+                            "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a"
+                            "\xf1\x65\xfc\x93\x07\x9e\x35\xcc"
+                            "\x40\xd7\x6e\x05\x79\x10\xa7\x1b"
+                            "\xb2\x49\xe0\x54\xeb\x82\x19\x8d"
+                            "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff"
+                            "\x96\x0a\xa1\x38\xcf\x43\xda\x71"
+                            "\x08\x7c\x13\xaa\x1e\xb5\x4c",
+               .psize     = 1023,
+               .digest    = "\x4d\x97\x23\xc8\xea\x7a\x7c\x15"
+                            "\xb8\xff\x97\x9c\xf5\x13\x4f\x31"
+                            "\xde\x67\xf7\x24\x73\xcd\x70\x1c"
+                            "\x03\x4a\xba\x8a\x87\x49\xfe\xdc"
+                            "\x75\x29\x62\x83\xae\x3f\x17\xab"
+                            "\xfd\x10\x4d\x8e\x17\x1c\x1f\xca",
+       }
 };
 
 /*
  * SHA512 test vectors from from NIST and kerneli
  */
-#define SHA512_TEST_VECTORS    4
+#define SHA512_TEST_VECTORS    6
 
 static struct hash_testvec sha512_tv_template[] = {
        {
+               .plaintext = "",
+               .psize  = 0,
+               .digest = "\xcf\x83\xe1\x35\x7e\xef\xb8\xbd"
+                         "\xf1\x54\x28\x50\xd6\x6d\x80\x07"
+                         "\xd6\x20\xe4\x05\x0b\x57\x15\xdc"
+                         "\x83\xf4\xa9\x21\xd3\x6c\xe9\xce"
+                         "\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0"
+                         "\xff\x83\x18\xd2\x87\x7e\xec\x2f"
+                         "\x63\xb9\x31\xbd\x47\x41\x7a\x81"
+                         "\xa5\x38\x32\x7a\xf9\x27\xda\x3e",
+       }, {
                .plaintext = "abc",
                .psize  = 3,
                .digest = "\xdd\xaf\x35\xa1\x93\x61\x7a\xba"
@@ -687,7 +1282,145 @@ static struct hash_testvec sha512_tv_template[] = {
                          "\xed\xb4\x19\x87\x23\x28\x50\xc9",
                .np     = 4,
                .tap    = { 26, 26, 26, 26 }
-       },
+       }, {
+               .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3"
+                            "\x7a\x11\x85\x1c\xb3\x27\xbe\x55"
+                            "\xec\x60\xf7\x8e\x02\x99\x30\xc7"
+                            "\x3b\xd2\x69\x00\x74\x0b\xa2\x16"
+                            "\xad\x44\xdb\x4f\xe6\x7d\x14\x88"
+                            "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa"
+                            "\x91\x05\x9c\x33\xca\x3e\xd5\x6c"
+                            "\x03\x77\x0e\xa5\x19\xb0\x47\xde"
+                            "\x52\xe9\x80\x17\x8b\x22\xb9\x2d"
+                            "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f"
+                            "\x36\xcd\x41\xd8\x6f\x06\x7a\x11"
+                            "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83"
+                            "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5"
+                            "\x69\x00\x97\x0b\xa2\x39\xd0\x44"
+                            "\xdb\x72\x09\x7d\x14\xab\x1f\xb6"
+                            "\x4d\xe4\x58\xef\x86\x1d\x91\x28"
+                            "\xbf\x33\xca\x61\xf8\x6c\x03\x9a"
+                            "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c"
+                            "\x80\x17\xae\x22\xb9\x50\xe7\x5b"
+                            "\xf2\x89\x20\x94\x2b\xc2\x36\xcd"
+                            "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f"
+                            "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1"
+                            "\x25\xbc\x53\xea\x5e\xf5\x8c\x00"
+                            "\x97\x2e\xc5\x39\xd0\x67\xfe\x72"
+                            "\x09\xa0\x14\xab\x42\xd9\x4d\xe4"
+                            "\x7b\x12\x86\x1d\xb4\x28\xbf\x56"
+                            "\xed\x61\xf8\x8f\x03\x9a\x31\xc8"
+                            "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17"
+                            "\xae\x45\xdc\x50\xe7\x7e\x15\x89"
+                            "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb"
+                            "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d"
+                            "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf"
+                            "\x53\xea\x81\x18\x8c\x23\xba\x2e"
+                            "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0"
+                            "\x37\xce\x42\xd9\x70\x07\x7b\x12"
+                            "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84"
+                            "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6"
+                            "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45"
+                            "\xdc\x73\x0a\x7e\x15\xac\x20\xb7"
+                            "\x4e\xe5\x59\xf0\x87\x1e\x92\x29"
+                            "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b"
+                            "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d"
+                            "\x81\x18\xaf\x23\xba\x51\xe8\x5c"
+                            "\xf3\x8a\x21\x95\x2c\xc3\x37\xce"
+                            "\x65\xfc\x70\x07\x9e\x12\xa9\x40"
+                            "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2"
+                            "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01"
+                            "\x98\x2f\xc6\x3a\xd1\x68\xff\x73"
+                            "\x0a\xa1\x15\xac\x43\xda\x4e\xe5"
+                            "\x7c\x13\x87\x1e\xb5\x29\xc0\x57"
+                            "\xee\x62\xf9\x90\x04\x9b\x32\xc9"
+                            "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18"
+                            "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a"
+                            "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc"
+                            "\x93\x07\x9e\x35\xcc\x40\xd7\x6e"
+                            "\x05\x79\x10\xa7\x1b\xb2\x49\xe0"
+                            "\x54\xeb\x82\x19\x8d\x24\xbb\x2f"
+                            "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1"
+                            "\x38\xcf\x43\xda\x71\x08\x7c\x13"
+                            "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85"
+                            "\x1c\x90\x27\xbe\x32\xc9\x60\xf7"
+                            "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46"
+                            "\xdd\x74\x0b\x7f\x16\xad\x21\xb8"
+                            "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a"
+                            "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c"
+                            "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e"
+                            "\x82\x19\xb0\x24\xbb\x52\xe9\x5d"
+                            "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf"
+                            "\x66\xfd\x71\x08\x9f\x13\xaa\x41"
+                            "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3"
+                            "\x27\xbe\x55\xec\x60\xf7\x8e\x02"
+                            "\x99\x30\xc7\x3b\xd2\x69\x00\x74"
+                            "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6"
+                            "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58"
+                            "\xef\x63\xfa\x91\x05\x9c\x33\xca"
+                            "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19"
+                            "\xb0\x47\xde\x52\xe9\x80\x17\x8b"
+                            "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd"
+                            "\x94\x08\x9f\x36\xcd\x41\xd8\x6f"
+                            "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1"
+                            "\x55\xec\x83\x1a\x8e\x25\xbc\x30"
+                            "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2"
+                            "\x39\xd0\x44\xdb\x72\x09\x7d\x14"
+                            "\xab\x1f\xb6\x4d\xe4\x58\xef\x86"
+                            "\x1d\x91\x28\xbf\x33\xca\x61\xf8"
+                            "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47"
+                            "\xde\x75\x0c\x80\x17\xae\x22\xb9"
+                            "\x50\xe7\x5b\xf2\x89\x20\x94\x2b"
+                            "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d"
+                            "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f"
+                            "\x83\x1a\xb1\x25\xbc\x53\xea\x5e"
+                            "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0"
+                            "\x67\xfe\x72\x09\xa0\x14\xab\x42"
+                            "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4"
+                            "\x28\xbf\x56\xed\x61\xf8\x8f\x03"
+                            "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75"
+                            "\x0c\xa3\x17\xae\x45\xdc\x50\xe7"
+                            "\x7e\x15\x89\x20\xb7\x2b\xc2\x59"
+                            "\xf0\x64\xfb\x92\x06\x9d\x34\xcb"
+                            "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a"
+                            "\xb1\x48\xdf\x53\xea\x81\x18\x8c"
+                            "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe"
+                            "\x95\x09\xa0\x37\xce\x42\xd9\x70"
+                            "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2"
+                            "\x56\xed\x84\x1b\x8f\x26\xbd\x31"
+                            "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3"
+                            "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15"
+                            "\xac\x20\xb7\x4e\xe5\x59\xf0\x87"
+                            "\x1e\x92\x29\xc0\x34\xcb\x62\xf9"
+                            "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48"
+                            "\xdf\x76\x0d\x81\x18\xaf\x23\xba"
+                            "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c"
+                            "\xc3\x37\xce\x65\xfc\x70\x07\x9e"
+                            "\x12\xa9\x40\xd7\x4b\xe2\x79\x10"
+                            "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f"
+                            "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1"
+                            "\x68\xff\x73\x0a\xa1\x15\xac\x43"
+                            "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5"
+                            "\x29\xc0\x57\xee\x62\xf9\x90\x04"
+                            "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76"
+                            "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8"
+                            "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a"
+                            "\xf1\x65\xfc\x93\x07\x9e\x35\xcc"
+                            "\x40\xd7\x6e\x05\x79\x10\xa7\x1b"
+                            "\xb2\x49\xe0\x54\xeb\x82\x19\x8d"
+                            "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff"
+                            "\x96\x0a\xa1\x38\xcf\x43\xda\x71"
+                            "\x08\x7c\x13\xaa\x1e\xb5\x4c",
+               .psize     = 1023,
+               .digest    = "\x76\xc9\xd4\x91\x7a\x5f\x0f\xaa"
+                            "\x13\x39\xf3\x01\x7a\xfa\xe5\x41"
+                            "\x5f\x0b\xf8\xeb\x32\xfc\xbf\xb0"
+                            "\xfa\x8c\xcd\x17\x83\xe2\xfa\xeb"
+                            "\x1c\x19\xde\xe2\x75\xdc\x34\x64"
+                            "\x5f\x35\x9c\x61\x2f\x10\xf9\xec"
+                            "\x59\xca\x9d\xcc\x25\x0c\x43\xba"
+                            "\x85\xa8\xf8\xfe\xb5\x24\xb2\xee",
+       }
 };
 
 
@@ -12844,7 +13577,7 @@ static struct cipher_testvec cast6_xts_dec_tv_template[] = {
 #define AES_GCM_4106_DEC_TEST_VECTORS 7
 #define AES_GCM_4543_ENC_TEST_VECTORS 1
 #define AES_GCM_4543_DEC_TEST_VECTORS 2
-#define AES_CCM_ENC_TEST_VECTORS 7
+#define AES_CCM_ENC_TEST_VECTORS 8
 #define AES_CCM_DEC_TEST_VECTORS 7
 #define AES_CCM_4309_ENC_TEST_VECTORS 7
 #define AES_CCM_4309_DEC_TEST_VECTORS 10
@@ -18746,7 +19479,29 @@ static struct aead_testvec aes_ccm_enc_tv_template[] = {
                          "\x7c\xf9\xbe\xc2\x40\x88\x97\xc6"
                          "\xba",
                .rlen   = 33,
-       },
+       }, {
+               /*
+                * This is the same vector as aes_ccm_rfc4309_enc_tv_template[0]
+                * below but rewritten to use the ccm algorithm directly.
+                */
+               .key    = "\x83\xac\x54\x66\xc2\xeb\xe5\x05"
+                         "\x2e\x01\xd1\xfc\x5d\x82\x66\x2e",
+               .klen   = 16,
+               .iv     = "\x03\x96\xac\x59\x30\x07\xa1\xe2\xa2\xc7\x55\x24\0\0\0\0",
+               .alen   = 0,
+               .input  = "\x19\xc8\x81\xf6\xe9\x86\xff\x93"
+                         "\x0b\x78\x67\xe5\xbb\xb7\xfc\x6e"
+                         "\x83\x77\xb3\xa6\x0c\x8c\x9f\x9c"
+                         "\x35\x2e\xad\xe0\x62\xf9\x91\xa1",
+               .ilen   = 32,
+               .result = "\xab\x6f\xe1\x69\x1d\x19\x99\xa8"
+                         "\x92\xa0\xc4\x6f\x7e\xe2\x8b\xb1"
+                         "\x70\xbb\x8c\xa6\x4c\x6e\x97\x8a"
+                         "\x57\x2b\xbe\x5d\x98\xa6\xb1\x32"
+                         "\xda\x24\xea\xd9\xa1\x39\x98\xfd"
+                         "\xa4\xbe\xd9\xf2\x1a\x6d\x22\xa8",
+               .rlen   = 48,
+       }
 };
 
 static struct aead_testvec aes_ccm_dec_tv_template[] = {
index 37d73024b82e4f9a7df2820e331bd873e0805947..e20708f2b8e56a89924adf0c5fa8517ccadb4d5d 100644 (file)
@@ -215,8 +215,15 @@ static int power_saving_thread(void *data)
                 * borrow CPU time from this CPU and cause RT task use > 95%
                 * CPU time. To make 'avoid starvation' work, takes a nap here.
                 */
-               if (do_sleep)
+               if (unlikely(do_sleep))
                        schedule_timeout_killable(HZ * idle_pct / 100);
+
+               /* If an external event has set the need_resched flag, then
+                * we need to deal with it, or this loop will continue to
+                * spin without calling __mwait().
+                */
+               if (unlikely(need_resched()))
+                       schedule();
        }
 
        exit_round_robin(tsk_index);
index c29c2c3ec0ad8ffc2c6427393593dbf147899d1b..b06f5f55ada952ced85de9c845dfb49cac421633 100644 (file)
@@ -170,6 +170,9 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
        acpi_status status;
        int ret;
 
+       if (pr->apic_id == -1)
+               return -ENODEV;
+
        status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
        if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
                return -ENODEV;
@@ -260,10 +263,8 @@ static int acpi_processor_get_info(struct acpi_device *device)
        }
 
        apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
-       if (apic_id < 0) {
+       if (apic_id < 0)
                acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n");
-               return -ENODEV;
-       }
        pr->apic_id = apic_id;
 
        cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
index b7ed86a20427e43080db1f4238afba5864e426a6..8bb43f06e11fda07c6e71718fab7b2baa37a5a57 100644 (file)
@@ -135,6 +135,7 @@ acpi-y +=           \
        rsxface.o
 
 acpi-y +=              \
+       tbdata.o        \
        tbfadt.o        \
        tbfind.o        \
        tbinstal.o      \
diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h
new file mode 100644 (file)
index 0000000..8698ffb
--- /dev/null
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ * Module Name: acapps - common include for ACPI applications/tools
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#ifndef _ACAPPS
+#define _ACAPPS
+
+/* Common info for tool signons */
+
+#define ACPICA_NAME                 "Intel ACPI Component Architecture"
+#define ACPICA_COPYRIGHT            "Copyright (c) 2000 - 2014 Intel Corporation"
+
+#if ACPI_MACHINE_WIDTH == 64
+#define ACPI_WIDTH          "-64"
+
+#elif ACPI_MACHINE_WIDTH == 32
+#define ACPI_WIDTH          "-32"
+
+#else
+#error unknown ACPI_MACHINE_WIDTH
+#define ACPI_WIDTH          "-??"
+
+#endif
+
+/* Macros for signons and file headers */
+
+#define ACPI_COMMON_SIGNON(utility_name) \
+       "\n%s\n%s version %8.8X%s [%s]\n%s\n\n", \
+       ACPICA_NAME, \
+       utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \
+       ACPICA_COPYRIGHT
+
+#define ACPI_COMMON_HEADER(utility_name, prefix) \
+       "%s%s\n%s%s version %8.8X%s [%s]\n%s%s\n%s\n", \
+       prefix, ACPICA_NAME, \
+       prefix, utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \
+       prefix, ACPICA_COPYRIGHT, \
+       prefix
+
+/* Macros for usage messages */
+
+#define ACPI_USAGE_HEADER(usage) \
+       printf ("Usage: %s\nOptions:\n", usage);
+
+#define ACPI_OPTION(name, description) \
+       printf ("  %-18s%s\n", name, description);
+
+#define FILE_SUFFIX_DISASSEMBLY     "dsl"
+#define ACPI_TABLE_FILE_SUFFIX      ".dat"
+
+/*
+ * getopt
+ */
+int acpi_getopt(int argc, char **argv, char *opts);
+
+int acpi_getopt_argument(int argc, char **argv);
+
+extern int acpi_gbl_optind;
+extern int acpi_gbl_opterr;
+extern int acpi_gbl_sub_opt_char;
+extern char *acpi_gbl_optarg;
+
+/*
+ * cmfsize - Common get file size function
+ */
+u32 cm_get_file_size(FILE * file);
+
+#ifndef ACPI_DUMP_APP
+/*
+ * adisasm
+ */
+acpi_status
+ad_aml_disassemble(u8 out_to_file,
+                  char *filename, char *prefix, char **out_filename);
+
+void ad_print_statistics(void);
+
+acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length);
+
+void ad_dump_tables(void);
+
+acpi_status ad_get_local_tables(void);
+
+acpi_status
+ad_parse_table(struct acpi_table_header *table,
+              acpi_owner_id * owner_id, u8 load_table, u8 external);
+
+acpi_status ad_display_tables(char *filename, struct acpi_table_header *table);
+
+acpi_status ad_display_statistics(void);
+
+/*
+ * adwalk
+ */
+void
+acpi_dm_cross_reference_namespace(union acpi_parse_object *parse_tree_root,
+                                 struct acpi_namespace_node *namespace_root,
+                                 acpi_owner_id owner_id);
+
+void acpi_dm_dump_tree(union acpi_parse_object *origin);
+
+void acpi_dm_find_orphan_methods(union acpi_parse_object *origin);
+
+void
+acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root,
+                             struct acpi_namespace_node *namespace_root,
+                             acpi_owner_id owner_id);
+
+void
+acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root,
+                                struct acpi_namespace_node *namespace_root);
+
+/*
+ * adfile
+ */
+acpi_status ad_initialize(void);
+
+char *fl_generate_filename(char *input_filename, char *suffix);
+
+acpi_status
+fl_split_input_pathname(char *input_path,
+                       char **out_directory_path, char **out_filename);
+
+char *ad_generate_filename(char *prefix, char *table_id);
+
+void
+ad_write_table(struct acpi_table_header *table,
+              u32 length, char *table_name, char *oem_table_id);
+#endif
+
+#endif                         /* _ACAPPS */
index 49bbc71fad54efd709ba9b7e6a610b5f8a30a7a3..1f602907dfab7a0ce0e4406fa5601de13dc7f196 100644 (file)
@@ -103,8 +103,8 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE);
 
 /*
  * Create the predefined _OSI method in the namespace? Default is TRUE
- * because ACPI CA is fully compatible with other ACPI implementations.
- * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
+ * because ACPICA is fully compatible with other ACPI implementations.
+ * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior.
  */
 ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE);
 
@@ -160,10 +160,10 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE);
 
 /*
- * Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
+ * Optionally do not install any SSDTs from the RSDT/XSDT during initialization.
  * This can be useful for debugging ACPI problems on some machines.
  */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE);
 
 /*
  * We keep track of the latest version of Windows that has been requested by
@@ -509,5 +509,6 @@ ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL);
  ****************************************************************************/
 
 extern const struct ah_predefined_name asl_predefined_info[];
+extern const struct ah_device_id asl_device_ids[];
 
 #endif                         /* __ACGLOBAL_H__ */
index 52a21dafb54039ca3c3d62bb22328acfb7a3321a..f68cb602dc23eeb41cc8ff3deb4a73fd500758a5 100644 (file)
@@ -733,7 +733,8 @@ union acpi_parse_value {
 #define ACPI_DASM_MATCHOP               0x06   /* Parent opcode is a Match() operator */
 #define ACPI_DASM_LNOT_PREFIX           0x07   /* Start of a Lnot_equal (etc.) pair of opcodes */
 #define ACPI_DASM_LNOT_SUFFIX           0x08   /* End  of a Lnot_equal (etc.) pair of opcodes */
-#define ACPI_DASM_IGNORE                0x09   /* Not used at this time */
+#define ACPI_DASM_HID_STRING            0x09   /* String is a _HID or _CID */
+#define ACPI_DASM_IGNORE                0x0A   /* Not used at this time */
 
 /*
  * Generic operation (for example:  If, While, Store)
@@ -1147,4 +1148,9 @@ struct ah_predefined_name {
 #endif
 };
 
+struct ah_device_id {
+       char *name;
+       char *description;
+};
+
 #endif                         /* __ACLOCAL_H__ */
index 5fa4b202769790e81a9ff39964957fc5860cb844..bda9a7eb50c1cd50c3e9125b2ffbf8a6dc6eb231 100644 (file)
@@ -53,6 +53,26 @@ acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
 
 u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
 
+/*
+ * tbdata - table data structure management
+ */
+acpi_status acpi_tb_get_next_root_index(u32 *table_index);
+
+void
+acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
+                             acpi_physical_address address,
+                             u8 flags, struct acpi_table_header *table);
+
+acpi_status
+acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
+                          acpi_physical_address address, u8 flags);
+
+void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc);
+
+u8 acpi_tb_is_table_loaded(u32 table_index);
+
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
+
 /*
  * tbfadt - FADT parse/convert/validate
  */
@@ -72,22 +92,35 @@ acpi_tb_find_table(char *signature,
  */
 acpi_status acpi_tb_resize_root_table_list(void);
 
-acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
+acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc);
 
-struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
-                                                *table_header,
-                                                struct acpi_table_desc
-                                                *table_desc);
+void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc);
 
 acpi_status
-acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index);
+acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature);
+
+void acpi_tb_override_table(struct acpi_table_desc *old_table_desc);
+
+acpi_status
+acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
+                     struct acpi_table_header **table_ptr,
+                     u32 *table_length, u8 *table_flags);
+
+void
+acpi_tb_release_table(struct acpi_table_header *table,
+                     u32 table_length, u8 table_flags);
+
+acpi_status
+acpi_tb_install_standard_table(acpi_physical_address address,
+                              u8 flags,
+                              u8 reload, u8 override, u32 *table_index);
 
 acpi_status
 acpi_tb_store_table(acpi_physical_address address,
                    struct acpi_table_header *table,
                    u32 length, u8 flags, u32 *table_index);
 
-void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
+void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc);
 
 void acpi_tb_terminate(void);
 
@@ -99,10 +132,6 @@ acpi_status acpi_tb_release_owner_id(u32 table_index);
 
 acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id);
 
-u8 acpi_tb_is_table_loaded(u32 table_index);
-
-void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
-
 /*
  * tbutils - table manager utilities
  */
@@ -124,8 +153,13 @@ void acpi_tb_check_dsdt_header(void);
 struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index);
 
 void
-acpi_tb_install_table(acpi_physical_address address,
-                     char *signature, u32 table_index);
+acpi_tb_install_table_with_override(u32 table_index,
+                                   struct acpi_table_desc *new_table_desc,
+                                   u8 override);
+
+acpi_status
+acpi_tb_install_fixed_table(acpi_physical_address address,
+                           char *signature, u32 table_index);
 
 acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);
 
index ceeec0b7ccb1764b1e8bc1bd4b7e91ef1f7b372c..1e256c5bda20675e73c1dbccd736cfc56606aebc 100644 (file)
@@ -176,8 +176,7 @@ acpi_status acpi_ut_init_globals(void);
 
 char *acpi_ut_get_mutex_name(u32 mutex_id);
 
-const char *acpi_ut_get_notify_name(u32 notify_value);
-
+const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type);
 #endif
 
 char *acpi_ut_get_type_name(acpi_object_type type);
@@ -737,4 +736,11 @@ acpi_ut_method_error(const char *module_name,
                     struct acpi_namespace_node *node,
                     const char *path, acpi_status lookup_status);
 
+/*
+ * Utility functions for ACPI names and IDs
+ */
+const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg);
+
+const struct ah_device_id *acpi_ah_match_hardware_id(char *hid);
+
 #endif                         /* _ACUTILS_H */
index 5d594eb2e5ecb6c627587daffaac0f0e5dcf35d3..24ea3424981bd9e2128eb694bb6c3ea8bb0ecb7e 100644 (file)
@@ -167,7 +167,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
                          "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
                          acpi_ut_get_node_name(node),
                          acpi_ut_get_type_name(node->type), notify_value,
-                         acpi_ut_get_notify_name(notify_value), node));
+                         acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
+                         node));
 
        status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
                                 info);
index 4d8a709c1fc4505b4ea176e0347142a43eed0fba..29630e303829e22ebaa44a75b0bd8b7f334a549d 100644 (file)
@@ -117,7 +117,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
        ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler);
 
        /*
-        * We are guaranteed by the ACPI CA initialization/shutdown code that
+        * We are guaranteed by the ACPICA initialization/shutdown code that
         * if this interrupt handler is installed, ACPI is enabled.
         */
 
index a734b27da0615e7bf73a6454183605931bce48b0..11e5803b8b41958824c4f108954d6bb4ae37aaa8 100644 (file)
@@ -239,7 +239,7 @@ acpi_remove_notify_handler(acpi_handle device,
        union acpi_operand_object *obj_desc;
        union acpi_operand_object *handler_obj;
        union acpi_operand_object *previous_handler_obj;
-       acpi_status status;
+       acpi_status status = AE_OK;
        u32 i;
 
        ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
@@ -251,20 +251,17 @@ acpi_remove_notify_handler(acpi_handle device,
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Make sure all deferred notify tasks are completed */
-
-       acpi_os_wait_events_complete();
-
-       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
        /* Root Object. Global handlers are removed here */
 
        if (device == ACPI_ROOT_OBJECT) {
                for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
                        if (handler_type & (i + 1)) {
+                               status =
+                                   acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+                               if (ACPI_FAILURE(status)) {
+                                       return_ACPI_STATUS(status);
+                               }
+
                                if (!acpi_gbl_global_notify[i].handler ||
                                    (acpi_gbl_global_notify[i].handler !=
                                     handler)) {
@@ -277,31 +274,40 @@ acpi_remove_notify_handler(acpi_handle device,
 
                                acpi_gbl_global_notify[i].handler = NULL;
                                acpi_gbl_global_notify[i].context = NULL;
+
+                               (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+                               /* Make sure all deferred notify tasks are completed */
+
+                               acpi_os_wait_events_complete();
                        }
                }
 
-               goto unlock_and_exit;
+               return_ACPI_STATUS(AE_OK);
        }
 
        /* All other objects: Are Notifies allowed on this object? */
 
        if (!acpi_ev_is_notify_object(node)) {
-               status = AE_TYPE;
-               goto unlock_and_exit;
+               return_ACPI_STATUS(AE_TYPE);
        }
 
        /* Must have an existing internal object */
 
        obj_desc = acpi_ns_get_attached_object(node);
        if (!obj_desc) {
-               status = AE_NOT_EXIST;
-               goto unlock_and_exit;
+               return_ACPI_STATUS(AE_NOT_EXIST);
        }
 
        /* Internal object exists. Find the handler and remove it */
 
        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
                if (handler_type & (i + 1)) {
+                       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+                       if (ACPI_FAILURE(status)) {
+                               return_ACPI_STATUS(status);
+                       }
+
                        handler_obj = obj_desc->common_notify.notify_list[i];
                        previous_handler_obj = NULL;
 
@@ -329,10 +335,17 @@ acpi_remove_notify_handler(acpi_handle device,
                                    handler_obj->notify.next[i];
                        }
 
+                       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+                       /* Make sure all deferred notify tasks are completed */
+
+                       acpi_os_wait_events_complete();
                        acpi_ut_remove_reference(handler_obj);
                }
        }
 
+       return_ACPI_STATUS(status);
+
 unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(status);
@@ -457,6 +470,8 @@ exit:
        return_ACPI_STATUS(status);
 }
 
+ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_remove_sci_handler
@@ -468,7 +483,6 @@ exit:
  * DESCRIPTION: Remove a handler for a System Control Interrupt.
  *
  ******************************************************************************/
-
 acpi_status acpi_remove_sci_handler(acpi_sci_handler address)
 {
        struct acpi_sci_handler_info *prev_sci_handler;
@@ -522,6 +536,8 @@ unlock_and_exit:
        return_ACPI_STATUS(status);
 }
 
+ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_install_global_event_handler
@@ -537,7 +553,6 @@ unlock_and_exit:
  *              Can be used to update event counters, etc.
  *
  ******************************************************************************/
-
 acpi_status
 acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
 {
@@ -840,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Make sure all deferred GPE tasks are completed */
-
-       acpi_os_wait_events_complete();
-
        status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
@@ -895,9 +906,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
                (void)acpi_ev_add_gpe_reference(gpe_event_info);
        }
 
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+       (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+       /* Make sure all deferred GPE tasks are completed */
+
+       acpi_os_wait_events_complete();
+
        /* Now we can free the handler object */
 
        ACPI_FREE(handler);
+       return_ACPI_STATUS(status);
 
 unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
index 8ba1464efd112a8f89a48eabbf7fd343c87ab3b6..7d2949420db7085c3a1f696e601eb426133aafee 100644 (file)
@@ -343,16 +343,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                struct acpi_walk_state *walk_state)
 {
        union acpi_operand_object *ddb_handle;
+       struct acpi_table_header *table_header;
        struct acpi_table_header *table;
-       struct acpi_table_desc table_desc;
        u32 table_index;
        acpi_status status;
        u32 length;
 
        ACPI_FUNCTION_TRACE(ex_load_op);
 
-       ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
-
        /* Source Object can be either an op_region or a Buffer/Field */
 
        switch (obj_desc->common.type) {
@@ -380,17 +378,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
 
                /* Get the table header first so we can get the table length */
 
-               table = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
-               if (!table) {
+               table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
+               if (!table_header) {
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
                status =
                    acpi_ex_region_read(obj_desc,
                                        sizeof(struct acpi_table_header),
-                                       ACPI_CAST_PTR(u8, table));
-               length = table->length;
-               ACPI_FREE(table);
+                                       ACPI_CAST_PTR(u8, table_header));
+               length = table_header->length;
+               ACPI_FREE(table_header);
 
                if (ACPI_FAILURE(status)) {
                        return_ACPI_STATUS(status);
@@ -420,22 +418,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
 
                /* Allocate a buffer for the table */
 
-               table_desc.pointer = ACPI_ALLOCATE(length);
-               if (!table_desc.pointer) {
+               table = ACPI_ALLOCATE(length);
+               if (!table) {
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
                /* Read the entire table */
 
                status = acpi_ex_region_read(obj_desc, length,
-                                            ACPI_CAST_PTR(u8,
-                                                          table_desc.pointer));
+                                            ACPI_CAST_PTR(u8, table));
                if (ACPI_FAILURE(status)) {
-                       ACPI_FREE(table_desc.pointer);
+                       ACPI_FREE(table);
                        return_ACPI_STATUS(status);
                }
-
-               table_desc.address = obj_desc->region.address;
                break;
 
        case ACPI_TYPE_BUFFER:  /* Buffer or resolved region_field */
@@ -452,10 +447,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
 
                /* Get the actual table length from the table header */
 
-               table =
+               table_header =
                    ACPI_CAST_PTR(struct acpi_table_header,
                                  obj_desc->buffer.pointer);
-               length = table->length;
+               length = table_header->length;
 
                /* Table cannot extend beyond the buffer */
 
@@ -470,13 +465,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                 * Copy the table from the buffer because the buffer could be modified
                 * or even deleted in the future
                 */
-               table_desc.pointer = ACPI_ALLOCATE(length);
-               if (!table_desc.pointer) {
+               table = ACPI_ALLOCATE(length);
+               if (!table) {
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
-               ACPI_MEMCPY(table_desc.pointer, table, length);
-               table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
+               ACPI_MEMCPY(table, table_header, length);
                break;
 
        default:
@@ -484,27 +478,32 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
-       /* Validate table checksum (will not get validated in tb_add_table) */
-
-       status = acpi_tb_verify_checksum(table_desc.pointer, length);
-       if (ACPI_FAILURE(status)) {
-               ACPI_FREE(table_desc.pointer);
-               return_ACPI_STATUS(status);
-       }
-
-       /* Complete the table descriptor */
+       /* Install the new table into the local data structures */
 
-       table_desc.length = length;
-       table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+       ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 
-       /* Install the new table into the local data structures */
+       status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
+                                               ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
+                                               TRUE, TRUE, &table_index);
 
-       status = acpi_tb_add_table(&table_desc, &table_index);
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
        if (ACPI_FAILURE(status)) {
 
                /* Delete allocated table buffer */
 
-               acpi_tb_delete_table(&table_desc);
+               ACPI_FREE(table);
+               return_ACPI_STATUS(status);
+       }
+
+       /*
+        * Note: Now table is "INSTALLED", it must be validated before
+        * loading.
+        */
+       status =
+           acpi_tb_validate_table(&acpi_gbl_root_table_list.
+                                  tables[table_index]);
+       if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
 
@@ -536,9 +535,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(status);
        }
 
-       ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
-       acpi_tb_print_table_header(0, table_desc.pointer);
-
        /* Remove the reference by added by acpi_ex_store above */
 
        acpi_ut_remove_reference(ddb_handle);
@@ -546,8 +542,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
        /* Invoke table handler if present */
 
        if (acpi_gbl_table_handler) {
-               (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD,
-                                            table_desc.pointer,
+               (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
                                             acpi_gbl_table_handler_context);
        }
 
@@ -575,6 +570,13 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
 
        ACPI_FUNCTION_TRACE(ex_unload_table);
 
+       /*
+        * Temporarily emit a warning so that the ASL for the machine can be
+        * hopefully obtained. This is to say that the Unload() operator is
+        * extremely rare if not completely unused.
+        */
+       ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table"));
+
        /*
         * Validate the handle
         * Although the handle is partially validated in acpi_ex_reconfiguration()
index 973fdae00f9479ddd160a8d3fff96e9367b26619..925202acc3e4f2c19a9d2a138fc3e697577f4ca1 100644 (file)
@@ -134,9 +134,11 @@ static struct acpi_exdump_info acpi_ex_dump_method[9] = {
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
+static struct acpi_exdump_info acpi_ex_dump_mutex[6] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.original_sync_level),
+        "Original Sync Level"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
        {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
         "Acquire Depth"},
diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c
new file mode 100644 (file)
index 0000000..cbe2994
--- /dev/null
@@ -0,0 +1,723 @@
+/******************************************************************************
+ *
+ * Module Name: tbdata - Table manager data structure functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_TABLES
+ACPI_MODULE_NAME("tbdata")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_init_table_descriptor
+ *
+ * PARAMETERS:  table_desc              - Table descriptor
+ *              address                 - Physical address of the table
+ *              flags                   - Allocation flags of the table
+ *              table                   - Pointer to the table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Initialize a new table descriptor
+ *
+ ******************************************************************************/
+void
+acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
+                             acpi_physical_address address,
+                             u8 flags, struct acpi_table_header *table)
+{
+
+       /*
+        * Initialize the table descriptor. Set the pointer to NULL, since the
+        * table is not fully mapped at this time.
+        */
+       ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc));
+       table_desc->address = address;
+       table_desc->length = table->length;
+       table_desc->flags = flags;
+       ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_acquire_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *              table_ptr           - Where table is returned
+ *              table_length        - Where table length is returned
+ *              table_flags         - Where table allocation flags are returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Acquire an ACPI table. It can be used for tables not
+ *              maintained in the acpi_gbl_root_table_list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
+                     struct acpi_table_header **table_ptr,
+                     u32 *table_length, u8 *table_flags)
+{
+       struct acpi_table_header *table = NULL;
+
+       switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+       case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+               table =
+                   acpi_os_map_memory(table_desc->address, table_desc->length);
+               break;
+
+       case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+       case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+               table =
+                   ACPI_CAST_PTR(struct acpi_table_header,
+                                 table_desc->address);
+               break;
+
+       default:
+
+               break;
+       }
+
+       /* Table is not valid yet */
+
+       if (!table) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Fill the return values */
+
+       *table_ptr = table;
+       *table_length = table_desc->length;
+       *table_flags = table_desc->flags;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_release_table
+ *
+ * PARAMETERS:  table               - Pointer for the table
+ *              table_length        - Length for the table
+ *              table_flags         - Allocation flags for the table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table().
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_release_table(struct acpi_table_header *table,
+                     u32 table_length, u8 table_flags)
+{
+
+       switch (table_flags & ACPI_TABLE_ORIGIN_MASK) {
+       case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+               acpi_os_unmap_memory(table, table_length);
+               break;
+
+       case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+       case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+       default:
+
+               break;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_acquire_temp_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor to be acquired
+ *              address             - Address of the table
+ *              flags               - Allocation flags of the table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function validates the table header to obtain the length
+ *              of a table and fills the table descriptor to make its state as
+ *              "INSTALLED". Such a table descriptor is only used for verified
+ *              installation.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
+                          acpi_physical_address address, u8 flags)
+{
+       struct acpi_table_header *table_header;
+
+       switch (flags & ACPI_TABLE_ORIGIN_MASK) {
+       case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+               /* Get the length of the full table from the header */
+
+               table_header =
+                   acpi_os_map_memory(address,
+                                      sizeof(struct acpi_table_header));
+               if (!table_header) {
+                       return (AE_NO_MEMORY);
+               }
+
+               acpi_tb_init_table_descriptor(table_desc, address, flags,
+                                             table_header);
+               acpi_os_unmap_memory(table_header,
+                                    sizeof(struct acpi_table_header));
+               return (AE_OK);
+
+       case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+       case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+               table_header = ACPI_CAST_PTR(struct acpi_table_header, address);
+               if (!table_header) {
+                       return (AE_NO_MEMORY);
+               }
+
+               acpi_tb_init_table_descriptor(table_desc, address, flags,
+                                             table_header);
+               return (AE_OK);
+
+       default:
+
+               break;
+       }
+
+       /* Table is not valid yet */
+
+       return (AE_NO_MEMORY);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_release_temp_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor to be released
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table().
+ *
+ *****************************************************************************/
+
+void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc)
+{
+
+       /*
+        * Note that the .Address is maintained by the callers of
+        * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table()
+        * where .Address will be freed.
+        */
+       acpi_tb_invalidate_table(table_desc);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_validate_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to validate the table, the returned
+ *              table descriptor is in "VALIDATED" state.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc)
+{
+       acpi_status status = AE_OK;
+
+       ACPI_FUNCTION_TRACE(tb_validate_table);
+
+       /* Validate the table if necessary */
+
+       if (!table_desc->pointer) {
+               status = acpi_tb_acquire_table(table_desc, &table_desc->pointer,
+                                              &table_desc->length,
+                                              &table_desc->flags);
+               if (!table_desc->pointer) {
+                       status = AE_NO_MEMORY;
+               }
+       }
+
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_invalidate_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of
+ *              acpi_tb_validate_table().
+ *
+ ******************************************************************************/
+
+void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc)
+{
+
+       ACPI_FUNCTION_TRACE(tb_invalidate_table);
+
+       /* Table must be validated */
+
+       if (!table_desc->pointer) {
+               return_VOID;
+       }
+
+       acpi_tb_release_table(table_desc->pointer, table_desc->length,
+                             table_desc->flags);
+       table_desc->pointer = NULL;
+
+       return_VOID;
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_verify_table
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *              signature           - Table signature to verify
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to validate and verify the table, the
+ *              returned table descriptor is in "VALIDATED" state.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature)
+{
+       acpi_status status = AE_OK;
+
+       ACPI_FUNCTION_TRACE(tb_verify_table);
+
+       /* Validate the table */
+
+       status = acpi_tb_validate_table(table_desc);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* If a particular signature is expected (DSDT/FACS), it must match */
+
+       if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) {
+               ACPI_BIOS_ERROR((AE_INFO,
+                                "Invalid signature 0x%X for ACPI table, expected [%s]",
+                                table_desc->signature.integer, signature));
+               status = AE_BAD_SIGNATURE;
+               goto invalidate_and_exit;
+       }
+
+       /* Verify the checksum */
+
+       status =
+           acpi_tb_verify_checksum(table_desc->pointer, table_desc->length);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
+                               "%4.4s " ACPI_PRINTF_UINT
+                               " Attempted table install failed",
+                               acpi_ut_valid_acpi_name(table_desc->signature.
+                                                       ascii) ? table_desc->
+                               signature.ascii : "????",
+                               ACPI_FORMAT_TO_UINT(table_desc->address)));
+               goto invalidate_and_exit;
+       }
+
+       return_ACPI_STATUS(AE_OK);
+
+invalidate_and_exit:
+       acpi_tb_invalidate_table(table_desc);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_resize_root_table_list
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Expand the size of global table array
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_resize_root_table_list(void)
+{
+       struct acpi_table_desc *tables;
+       u32 table_count;
+
+       ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
+
+       /* allow_resize flag is a parameter to acpi_initialize_tables */
+
+       if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+               ACPI_ERROR((AE_INFO,
+                           "Resize of Root Table Array is not allowed"));
+               return_ACPI_STATUS(AE_SUPPORT);
+       }
+
+       /* Increase the Table Array size */
+
+       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+               table_count = acpi_gbl_root_table_list.max_table_count;
+       } else {
+               table_count = acpi_gbl_root_table_list.current_table_count;
+       }
+
+       tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count +
+                                      ACPI_ROOT_TABLE_SIZE_INCREMENT) *
+                                     sizeof(struct acpi_table_desc));
+       if (!tables) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not allocate new root table array"));
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* Copy and free the previous table array */
+
+       if (acpi_gbl_root_table_list.tables) {
+               ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+                           (acpi_size) table_count *
+                           sizeof(struct acpi_table_desc));
+
+               if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+                       ACPI_FREE(acpi_gbl_root_table_list.tables);
+               }
+       }
+
+       acpi_gbl_root_table_list.tables = tables;
+       acpi_gbl_root_table_list.max_table_count =
+           table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT;
+       acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED;
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_get_next_root_index
+ *
+ * PARAMETERS:  table_index         - Where table index is returned
+ *
+ * RETURN:      Status and table index.
+ *
+ * DESCRIPTION: Allocate a new ACPI table entry to the global table list
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_get_next_root_index(u32 *table_index)
+{
+       acpi_status status;
+
+       /* Ensure that there is room for the table in the Root Table List */
+
+       if (acpi_gbl_root_table_list.current_table_count >=
+           acpi_gbl_root_table_list.max_table_count) {
+               status = acpi_tb_resize_root_table_list();
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       }
+
+       *table_index = acpi_gbl_root_table_list.current_table_count;
+       acpi_gbl_root_table_list.current_table_count++;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_terminate
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
+
+void acpi_tb_terminate(void)
+{
+       u32 i;
+
+       ACPI_FUNCTION_TRACE(tb_terminate);
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+       /* Delete the individual tables */
+
+       for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+               acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]);
+       }
+
+       /*
+        * Delete the root table array if allocated locally. Array cannot be
+        * mapped, so we don't need to check for that flag.
+        */
+       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+               ACPI_FREE(acpi_gbl_root_table_list.tables);
+       }
+
+       acpi_gbl_root_table_list.tables = NULL;
+       acpi_gbl_root_table_list.flags = 0;
+       acpi_gbl_root_table_list.current_table_count = 0;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_delete_namespace_by_owner
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
+{
+       acpi_owner_id owner_id;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner);
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       if (table_index >= acpi_gbl_root_table_list.current_table_count) {
+
+               /* The table index does not exist */
+
+               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+               return_ACPI_STATUS(AE_NOT_EXIST);
+       }
+
+       /* Get the owner ID for this table, used to delete namespace nodes */
+
+       owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id;
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+
+       /*
+        * Need to acquire the namespace writer lock to prevent interference
+        * with any concurrent namespace walks. The interpreter must be
+        * released during the deletion since the acquisition of the deletion
+        * lock may block, and also since the execution of a namespace walk
+        * must be allowed to use the interpreter.
+        */
+       (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
+       status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
+
+       acpi_ns_delete_namespace_by_owner(owner_id);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock);
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_allocate_owner_id
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Allocates owner_id in table_desc
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_allocate_owner_id(u32 table_index)
+{
+       acpi_status status = AE_BAD_PARAMETER;
+
+       ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.current_table_count) {
+               status =
+                   acpi_ut_allocate_owner_id(&
+                                             (acpi_gbl_root_table_list.
+                                              tables[table_index].owner_id));
+       }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_release_owner_id
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Releases owner_id in table_desc
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_release_owner_id(u32 table_index)
+{
+       acpi_status status = AE_BAD_PARAMETER;
+
+       ACPI_FUNCTION_TRACE(tb_release_owner_id);
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.current_table_count) {
+               acpi_ut_release_owner_id(&
+                                        (acpi_gbl_root_table_list.
+                                         tables[table_index].owner_id));
+               status = AE_OK;
+       }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_get_owner_id
+ *
+ * PARAMETERS:  table_index         - Table index
+ *              owner_id            - Where the table owner_id is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: returns owner_id for the ACPI table
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id)
+{
+       acpi_status status = AE_BAD_PARAMETER;
+
+       ACPI_FUNCTION_TRACE(tb_get_owner_id);
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.current_table_count) {
+               *owner_id =
+                   acpi_gbl_root_table_list.tables[table_index].owner_id;
+               status = AE_OK;
+       }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_is_table_loaded
+ *
+ * PARAMETERS:  table_index         - Index into the root table
+ *
+ * RETURN:      Table Loaded Flag
+ *
+ ******************************************************************************/
+
+u8 acpi_tb_is_table_loaded(u32 table_index)
+{
+       u8 is_loaded = FALSE;
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.current_table_count) {
+               is_loaded = (u8)
+                   (acpi_gbl_root_table_list.tables[table_index].flags &
+                    ACPI_TABLE_IS_LOADED);
+       }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return (is_loaded);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS:  table_index         - Table index
+ *              is_loaded           - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
+
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
+{
+
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.current_table_count) {
+               if (is_loaded) {
+                       acpi_gbl_root_table_list.tables[table_index].flags |=
+                           ACPI_TABLE_IS_LOADED;
+               } else {
+                       acpi_gbl_root_table_list.tables[table_index].flags &=
+                           ~ACPI_TABLE_IS_LOADED;
+               }
+       }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+}
index ec14588254d433e63e1b17352f16f3702b9a09f6..a37af164b8c8efe2476683a3dd6a49b6729c35e7 100644 (file)
@@ -332,15 +332,15 @@ void acpi_tb_parse_fadt(u32 table_index)
 
        /* Obtain the DSDT and FACS tables via their addresses within the FADT */
 
-       acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
-                             ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+       acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+                                   ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
 
        /* If Hardware Reduced flag is set, there is no FACS */
 
        if (!acpi_gbl_reduced_hardware) {
-               acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.
-                                     Xfacs, ACPI_SIG_FACS,
-                                     ACPI_TABLE_INDEX_FACS);
+               acpi_tb_install_fixed_table((acpi_physical_address)
+                                           acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS,
+                                           ACPI_TABLE_INDEX_FACS);
        }
 }
 
index c12003947bd53c09ed4c63603f93736b19f911e3..cb947700206ca56fb7d4e09cab0998f455a6afaa 100644 (file)
@@ -99,8 +99,8 @@ acpi_tb_find_table(char *signature,
                        /* Table is not currently mapped, map it */
 
                        status =
-                           acpi_tb_verify_table(&acpi_gbl_root_table_list.
-                                                tables[i]);
+                           acpi_tb_validate_table(&acpi_gbl_root_table_list.
+                                                  tables[i]);
                        if (ACPI_FAILURE(status)) {
                                return_ACPI_STATUS(status);
                        }
index e3040947e9a00fff25b9cedc13813d27d8ebaf59..d4d6029fef44195f1be3365e147c019371f2225b 100644 (file)
 
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acnamesp.h"
 #include "actables.h"
 
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbinstal")
 
-/******************************************************************************
+/* Local prototypes */
+static u8
+acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index);
+
+/*******************************************************************************
  *
- * FUNCTION:    acpi_tb_verify_table
+ * FUNCTION:    acpi_tb_compare_tables
  *
- * PARAMETERS:  table_desc          - table
+ * PARAMETERS:  table_desc          - Table 1 descriptor to be compared
+ *              table_index         - Index of table 2 to be compared
  *
- * RETURN:      Status
+ * RETURN:      TRUE if both tables are identical.
  *
- * DESCRIPTION: this function is called to verify and map table
+ * DESCRIPTION: This function compares a table with another table that has
+ *              already been installed in the root table list.
  *
- *****************************************************************************/
-acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
+ ******************************************************************************/
+
+static u8
+acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index)
 {
        acpi_status status = AE_OK;
+       u8 is_identical;
+       struct acpi_table_header *table;
+       u32 table_length;
+       u8 table_flags;
 
-       ACPI_FUNCTION_TRACE(tb_verify_table);
-
-       /* Map the table if necessary */
-
-       if (!table_desc->pointer) {
-               if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
-                   ACPI_TABLE_ORIGIN_MAPPED) {
-                       table_desc->pointer =
-                           acpi_os_map_memory(table_desc->address,
-                                              table_desc->length);
-               }
-               if (!table_desc->pointer) {
-                       return_ACPI_STATUS(AE_NO_MEMORY);
-               }
+       status =
+           acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index],
+                                 &table, &table_length, &table_flags);
+       if (ACPI_FAILURE(status)) {
+               return (FALSE);
        }
 
-       /* Always calculate checksum, ignore bad checksum if requested */
+       /*
+        * Check for a table match on the entire table length,
+        * not just the header.
+        */
+       is_identical = (u8)((table_desc->length != table_length ||
+                            ACPI_MEMCMP(table_desc->pointer, table,
+                                        table_length)) ? FALSE : TRUE);
 
-       status =
-           acpi_tb_verify_checksum(table_desc->pointer, table_desc->length);
+       /* Release the acquired table */
 
-       return_ACPI_STATUS(status);
+       acpi_tb_release_table(table, table_length, table_flags);
+       return (is_identical);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_add_table
+ * FUNCTION:    acpi_tb_install_table_with_override
  *
- * PARAMETERS:  table_desc          - Table descriptor
- *              table_index         - Where the table index is returned
+ * PARAMETERS:  table_index             - Index into root table array
+ *              new_table_desc          - New table descriptor to install
+ *              override                - Whether override should be performed
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: This function is called to add an ACPI table. It is used to
- *              dynamically load tables via the Load and load_table AML
- *              operators.
+ * DESCRIPTION: Install an ACPI table into the global data structure. The
+ *              table override mechanism is called to allow the host
+ *              OS to replace any table before it is installed in the root
+ *              table array.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
+void
+acpi_tb_install_table_with_override(u32 table_index,
+                                   struct acpi_table_desc *new_table_desc,
+                                   u8 override)
 {
-       u32 i;
-       acpi_status status = AE_OK;
 
-       ACPI_FUNCTION_TRACE(tb_add_table);
-
-       if (!table_desc->pointer) {
-               status = acpi_tb_verify_table(table_desc);
-               if (ACPI_FAILURE(status) || !table_desc->pointer) {
-                       return_ACPI_STATUS(status);
-               }
+       if (table_index >= acpi_gbl_root_table_list.current_table_count) {
+               return;
        }
 
        /*
-        * Validate the incoming table signature.
+        * ACPI Table Override:
         *
-        * 1) Originally, we checked the table signature for "SSDT" or "PSDT".
-        * 2) We added support for OEMx tables, signature "OEM".
-        * 3) Valid tables were encountered with a null signature, so we just
-        *    gave up on validating the signature, (05/2008).
-        * 4) We encountered non-AML tables such as the MADT, which caused
-        *    interpreter errors and kernel faults. So now, we once again allow
-        *    only "SSDT", "OEMx", and now, also a null signature. (05/2011).
+        * Before we install the table, let the host OS override it with a new
+        * one if desired. Any table within the RSDT/XSDT can be replaced,
+        * including the DSDT which is pointed to by the FADT.
         */
-       if ((table_desc->pointer->signature[0] != 0x00) &&
-           (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
-           && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) {
-               ACPI_BIOS_ERROR((AE_INFO,
-                                "Table has invalid signature [%4.4s] (0x%8.8X), "
-                                "must be SSDT or OEMx",
-                                acpi_ut_valid_acpi_name(table_desc->pointer->
-                                                        signature) ?
-                                table_desc->pointer->signature : "????",
-                                *(u32 *)table_desc->pointer->signature));
-
-               return_ACPI_STATUS(AE_BAD_SIGNATURE);
+       if (override) {
+               acpi_tb_override_table(new_table_desc);
        }
 
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
+                                     tables[table_index],
+                                     new_table_desc->address,
+                                     new_table_desc->flags,
+                                     new_table_desc->pointer);
 
-       /* Check if table is already registered */
+       acpi_tb_print_table_header(new_table_desc->address,
+                                  new_table_desc->pointer);
 
-       for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
-               if (!acpi_gbl_root_table_list.tables[i].pointer) {
-                       status =
-                           acpi_tb_verify_table(&acpi_gbl_root_table_list.
-                                                tables[i]);
-                       if (ACPI_FAILURE(status)
-                           || !acpi_gbl_root_table_list.tables[i].pointer) {
-                               continue;
-                       }
-               }
+       /* Set the global integer width (based upon revision of the DSDT) */
 
-               /*
-                * Check for a table match on the entire table length,
-                * not just the header.
-                */
-               if (table_desc->length !=
-                   acpi_gbl_root_table_list.tables[i].length) {
-                       continue;
-               }
-
-               if (ACPI_MEMCMP(table_desc->pointer,
-                               acpi_gbl_root_table_list.tables[i].pointer,
-                               acpi_gbl_root_table_list.tables[i].length)) {
-                       continue;
-               }
-
-               /*
-                * Note: the current mechanism does not unregister a table if it is
-                * dynamically unloaded. The related namespace entries are deleted,
-                * but the table remains in the root table list.
-                *
-                * The assumption here is that the number of different tables that
-                * will be loaded is actually small, and there is minimal overhead
-                * in just keeping the table in case it is needed again.
-                *
-                * If this assumption changes in the future (perhaps on large
-                * machines with many table load/unload operations), tables will
-                * need to be unregistered when they are unloaded, and slots in the
-                * root table list should be reused when empty.
-                */
-
-               /*
-                * Table is already registered.
-                * We can delete the table that was passed as a parameter.
-                */
-               acpi_tb_delete_table(table_desc);
-               *table_index = i;
-
-               if (acpi_gbl_root_table_list.tables[i].
-                   flags & ACPI_TABLE_IS_LOADED) {
-
-                       /* Table is still loaded, this is an error */
-
-                       status = AE_ALREADY_EXISTS;
-                       goto release;
-               } else {
-                       /* Table was unloaded, allow it to be reloaded */
-
-                       table_desc->pointer =
-                           acpi_gbl_root_table_list.tables[i].pointer;
-                       table_desc->address =
-                           acpi_gbl_root_table_list.tables[i].address;
-                       status = AE_OK;
-                       goto print_header;
-               }
+       if (table_index == ACPI_TABLE_INDEX_DSDT) {
+               acpi_ut_set_integer_width(new_table_desc->pointer->revision);
        }
-
-       /*
-        * ACPI Table Override:
-        * Allow the host to override dynamically loaded tables.
-        * NOTE: the table is fully mapped at this point, and the mapping will
-        * be deleted by tb_table_override if the table is actually overridden.
-        */
-       (void)acpi_tb_table_override(table_desc->pointer, table_desc);
-
-       /* Add the table to the global root table list */
-
-       status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
-                                    table_desc->length, table_desc->flags,
-                                    table_index);
-       if (ACPI_FAILURE(status)) {
-               goto release;
-       }
-
-print_header:
-       acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
-
-release:
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_table_override
+ * FUNCTION:    acpi_tb_install_fixed_table
  *
- * PARAMETERS:  table_header        - Header for the original table
- *              table_desc          - Table descriptor initialized for the
- *                                    original table. May or may not be mapped.
+ * PARAMETERS:  address                 - Physical address of DSDT or FACS
+ *              signature               - Table signature, NULL if no need to
+ *                                        match
+ *              table_index             - Index into root table array
  *
- * RETURN:      Pointer to the entire new table. NULL if table not overridden.
- *              If overridden, installs the new table within the input table
- *              descriptor.
+ * RETURN:      Status
  *
- * DESCRIPTION: Attempt table override by calling the OSL override functions.
- *              Note: If the table is overridden, then the entire new table
- *              is mapped and returned by this function.
+ * DESCRIPTION: Install a fixed ACPI table (DSDT/FACS) into the global data
+ *              structure.
  *
  ******************************************************************************/
 
-struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
-                                                *table_header,
-                                                struct acpi_table_desc
-                                                *table_desc)
+acpi_status
+acpi_tb_install_fixed_table(acpi_physical_address address,
+                           char *signature, u32 table_index)
 {
+       struct acpi_table_desc new_table_desc;
        acpi_status status;
-       struct acpi_table_header *new_table = NULL;
-       acpi_physical_address new_address = 0;
-       u32 new_table_length = 0;
-       u8 new_flags;
-       char *override_type;
 
-       /* (1) Attempt logical override (returns a logical address) */
+       ACPI_FUNCTION_TRACE(tb_install_fixed_table);
 
-       status = acpi_os_table_override(table_header, &new_table);
-       if (ACPI_SUCCESS(status) && new_table) {
-               new_address = ACPI_PTR_TO_PHYSADDR(new_table);
-               new_table_length = new_table->length;
-               new_flags = ACPI_TABLE_ORIGIN_OVERRIDE;
-               override_type = "Logical";
-               goto finish_override;
+       if (!address) {
+               ACPI_ERROR((AE_INFO,
+                           "Null physical address for ACPI table [%s]",
+                           signature));
+               return (AE_NO_MEMORY);
        }
 
-       /* (2) Attempt physical override (returns a physical address) */
+       /* Fill a table descriptor for validation */
 
-       status = acpi_os_physical_table_override(table_header,
-                                                &new_address,
-                                                &new_table_length);
-       if (ACPI_SUCCESS(status) && new_address && new_table_length) {
-
-               /* Map the entire new table */
-
-               new_table = acpi_os_map_memory(new_address, new_table_length);
-               if (!new_table) {
-                       ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
-                                       "%4.4s " ACPI_PRINTF_UINT
-                                       " Attempted physical table override failed",
-                                       table_header->signature,
-                                       ACPI_FORMAT_TO_UINT(table_desc->
-                                                           address)));
-                       return (NULL);
-               }
-
-               override_type = "Physical";
-               new_flags = ACPI_TABLE_ORIGIN_MAPPED;
-               goto finish_override;
+       status = acpi_tb_acquire_temp_table(&new_table_desc, address,
+                                           ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO, "Could not acquire table length at %p",
+                           ACPI_CAST_PTR(void, address)));
+               return_ACPI_STATUS(status);
        }
 
-       return (NULL);          /* There was no override */
-
-finish_override:
-
-       ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
-                  " %s table override, new table: " ACPI_PRINTF_UINT,
-                  table_header->signature,
-                  ACPI_FORMAT_TO_UINT(table_desc->address),
-                  override_type, ACPI_FORMAT_TO_UINT(new_table)));
+       /* Validate and verify a table before installation */
 
-       /* We can now unmap/delete the original table (if fully mapped) */
+       status = acpi_tb_verify_table(&new_table_desc, signature);
+       if (ACPI_FAILURE(status)) {
+               goto release_and_exit;
+       }
 
-       acpi_tb_delete_table(table_desc);
+       acpi_tb_install_table_with_override(table_index, &new_table_desc, TRUE);
 
-       /* Setup descriptor for the new table */
+release_and_exit:
 
-       table_desc->address = new_address;
-       table_desc->pointer = new_table;
-       table_desc->length = new_table_length;
-       table_desc->flags = new_flags;
+       /* Release the temporary table descriptor */
 
-       return (new_table);
+       acpi_tb_release_temp_table(&new_table_desc);
+       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_resize_root_table_list
+ * FUNCTION:    acpi_tb_install_standard_table
  *
- * PARAMETERS:  None
+ * PARAMETERS:  address             - Address of the table (might be a virtual
+ *                                    address depending on the table_flags)
+ *              flags               - Flags for the table
+ *              reload              - Whether reload should be performed
+ *              override            - Whether override should be performed
+ *              table_index         - Where the table index is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Expand the size of global table array
+ * DESCRIPTION: This function is called to install an ACPI table that is
+ *              neither DSDT nor FACS (a "standard" table.)
+ *              When this function is called by "Load" or "LoadTable" opcodes,
+ *              or by acpi_load_table() API, the "Reload" parameter is set.
+ *              After sucessfully returning from this function, table is
+ *              "INSTALLED" but not "VALIDATED".
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_resize_root_table_list(void)
+acpi_status
+acpi_tb_install_standard_table(acpi_physical_address address,
+                              u8 flags,
+                              u8 reload, u8 override, u32 *table_index)
 {
-       struct acpi_table_desc *tables;
-       u32 table_count;
-
-       ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
-
-       /* allow_resize flag is a parameter to acpi_initialize_tables */
+       u32 i;
+       acpi_status status = AE_OK;
+       struct acpi_table_desc new_table_desc;
 
-       if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
-               ACPI_ERROR((AE_INFO,
-                           "Resize of Root Table Array is not allowed"));
-               return_ACPI_STATUS(AE_SUPPORT);
-       }
+       ACPI_FUNCTION_TRACE(tb_install_standard_table);
 
-       /* Increase the Table Array size */
+       /* Acquire a temporary table descriptor for validation */
 
-       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
-               table_count = acpi_gbl_root_table_list.max_table_count;
-       } else {
-               table_count = acpi_gbl_root_table_list.current_table_count;
+       status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO, "Could not acquire table length at %p",
+                           ACPI_CAST_PTR(void, address)));
+               return_ACPI_STATUS(status);
        }
 
-       tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count +
-                                      ACPI_ROOT_TABLE_SIZE_INCREMENT) *
-                                     sizeof(struct acpi_table_desc));
-       if (!tables) {
-               ACPI_ERROR((AE_INFO,
-                           "Could not allocate new root table array"));
-               return_ACPI_STATUS(AE_NO_MEMORY);
+       /*
+        * Optionally do not load any SSDTs from the RSDT/XSDT. This can
+        * be useful for debugging ACPI problems on some machines.
+        */
+       if (!reload &&
+           acpi_gbl_disable_ssdt_table_install &&
+           ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) {
+               ACPI_INFO((AE_INFO, "Ignoring installation of %4.4s at %p",
+                          new_table_desc.signature.ascii, ACPI_CAST_PTR(void,
+                                                                        address)));
+               goto release_and_exit;
        }
 
-       /* Copy and free the previous table array */
-
-       if (acpi_gbl_root_table_list.tables) {
-               ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
-                           (acpi_size) table_count *
-                           sizeof(struct acpi_table_desc));
+       /* Validate and verify a table before installation */
 
-               if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
-                       ACPI_FREE(acpi_gbl_root_table_list.tables);
-               }
+       status = acpi_tb_verify_table(&new_table_desc, NULL);
+       if (ACPI_FAILURE(status)) {
+               goto release_and_exit;
        }
 
-       acpi_gbl_root_table_list.tables = tables;
-       acpi_gbl_root_table_list.max_table_count =
-           table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT;
-       acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED;
-
-       return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_store_table
- *
- * PARAMETERS:  address             - Table address
- *              table               - Table header
- *              length              - Table length
- *              flags               - flags
- *
- * RETURN:      Status and table index.
- *
- * DESCRIPTION: Add an ACPI table to the global table list
- *
- ******************************************************************************/
+       if (reload) {
+               /*
+                * Validate the incoming table signature.
+                *
+                * 1) Originally, we checked the table signature for "SSDT" or "PSDT".
+                * 2) We added support for OEMx tables, signature "OEM".
+                * 3) Valid tables were encountered with a null signature, so we just
+                *    gave up on validating the signature, (05/2008).
+                * 4) We encountered non-AML tables such as the MADT, which caused
+                *    interpreter errors and kernel faults. So now, we once again allow
+                *    only "SSDT", "OEMx", and now, also a null signature. (05/2011).
+                */
+               if ((new_table_desc.signature.ascii[0] != 0x00) &&
+                   (!ACPI_COMPARE_NAME
+                    (&new_table_desc.signature, ACPI_SIG_SSDT))
+                   && (ACPI_STRNCMP(new_table_desc.signature.ascii, "OEM", 3)))
+               {
+                       ACPI_BIOS_ERROR((AE_INFO,
+                                        "Table has invalid signature [%4.4s] (0x%8.8X), "
+                                        "must be SSDT or OEMx",
+                                        acpi_ut_valid_acpi_name(new_table_desc.
+                                                                signature.
+                                                                ascii) ?
+                                        new_table_desc.signature.
+                                        ascii : "????",
+                                        new_table_desc.signature.integer));
+
+                       status = AE_BAD_SIGNATURE;
+                       goto release_and_exit;
+               }
 
-acpi_status
-acpi_tb_store_table(acpi_physical_address address,
-                   struct acpi_table_header *table,
-                   u32 length, u8 flags, u32 *table_index)
-{
-       acpi_status status;
-       struct acpi_table_desc *new_table;
+               /* Check if table is already registered */
 
-       /* Ensure that there is room for the table in the Root Table List */
+               for (i = 0; i < acpi_gbl_root_table_list.current_table_count;
+                    ++i) {
+                       /*
+                        * Check for a table match on the entire table length,
+                        * not just the header.
+                        */
+                       if (!acpi_tb_compare_tables(&new_table_desc, i)) {
+                               continue;
+                       }
 
-       if (acpi_gbl_root_table_list.current_table_count >=
-           acpi_gbl_root_table_list.max_table_count) {
-               status = acpi_tb_resize_root_table_list();
-               if (ACPI_FAILURE(status)) {
-                       return (status);
+                       /*
+                        * Note: the current mechanism does not unregister a table if it is
+                        * dynamically unloaded. The related namespace entries are deleted,
+                        * but the table remains in the root table list.
+                        *
+                        * The assumption here is that the number of different tables that
+                        * will be loaded is actually small, and there is minimal overhead
+                        * in just keeping the table in case it is needed again.
+                        *
+                        * If this assumption changes in the future (perhaps on large
+                        * machines with many table load/unload operations), tables will
+                        * need to be unregistered when they are unloaded, and slots in the
+                        * root table list should be reused when empty.
+                        */
+                       if (acpi_gbl_root_table_list.tables[i].
+                           flags & ACPI_TABLE_IS_LOADED) {
+
+                               /* Table is still loaded, this is an error */
+
+                               status = AE_ALREADY_EXISTS;
+                               goto release_and_exit;
+                       } else {
+                               /*
+                                * Table was unloaded, allow it to be reloaded.
+                                * As we are going to return AE_OK to the caller, we should
+                                * take the responsibility of freeing the input descriptor.
+                                * Refill the input descriptor to ensure
+                                * acpi_tb_install_table_with_override() can be called again to
+                                * indicate the re-installation.
+                                */
+                               acpi_tb_uninstall_table(&new_table_desc);
+                               *table_index = i;
+                               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+                               return_ACPI_STATUS(AE_OK);
+                       }
                }
        }
 
-       new_table =
-           &acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.
-                                            current_table_count];
-
-       /* Initialize added table */
-
-       new_table->address = address;
-       new_table->pointer = table;
-       new_table->length = length;
-       new_table->owner_id = 0;
-       new_table->flags = flags;
-
-       ACPI_MOVE_32_TO_32(&new_table->signature, table->signature);
-
-       *table_index = acpi_gbl_root_table_list.current_table_count;
-       acpi_gbl_root_table_list.current_table_count++;
-       return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_delete_table
- *
- * PARAMETERS:  table_index         - Table index
- *
- * RETURN:      None
- *
- * DESCRIPTION: Delete one internal ACPI table
- *
- ******************************************************************************/
+       /* Add the table to the global root table list */
 
-void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
-{
-       /* Table must be mapped or allocated */
-       if (!table_desc->pointer) {
-               return;
+       status = acpi_tb_get_next_root_index(&i);
+       if (ACPI_FAILURE(status)) {
+               goto release_and_exit;
        }
-       switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
-       case ACPI_TABLE_ORIGIN_MAPPED:
-
-               acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
-               break;
-
-       case ACPI_TABLE_ORIGIN_ALLOCATED:
 
-               ACPI_FREE(table_desc->pointer);
-               break;
+       *table_index = i;
+       acpi_tb_install_table_with_override(i, &new_table_desc, override);
 
-               /* Not mapped or allocated, there is nothing we can do */
+release_and_exit:
 
-       default:
+       /* Release the temporary table descriptor */
 
-               return;
-       }
-
-       table_desc->pointer = NULL;
+       acpi_tb_release_temp_table(&new_table_desc);
+       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_terminate
+ * FUNCTION:    acpi_tb_override_table
  *
- * PARAMETERS:  None
+ * PARAMETERS:  old_table_desc      - Validated table descriptor to be
+ *                                    overridden
  *
  * RETURN:      None
  *
- * DESCRIPTION: Delete all internal ACPI tables
+ * DESCRIPTION: Attempt table override by calling the OSL override functions.
+ *              Note: If the table is overridden, then the entire new table
+ *              is acquired and returned by this function.
+ *              Before/after invocation, the table descriptor is in a state
+ *              that is "VALIDATED".
  *
  ******************************************************************************/
 
-void acpi_tb_terminate(void)
+void acpi_tb_override_table(struct acpi_table_desc *old_table_desc)
 {
-       u32 i;
-
-       ACPI_FUNCTION_TRACE(tb_terminate);
-
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-
-       /* Delete the individual tables */
+       acpi_status status;
+       char *override_type;
+       struct acpi_table_desc new_table_desc;
+       struct acpi_table_header *table;
+       acpi_physical_address address;
+       u32 length;
 
-       for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
-               acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
-       }
+       /* (1) Attempt logical override (returns a logical address) */
 
-       /*
-        * Delete the root table array if allocated locally. Array cannot be
-        * mapped, so we don't need to check for that flag.
-        */
-       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
-               ACPI_FREE(acpi_gbl_root_table_list.tables);
+       status = acpi_os_table_override(old_table_desc->pointer, &table);
+       if (ACPI_SUCCESS(status) && table) {
+               acpi_tb_acquire_temp_table(&new_table_desc,
+                                          ACPI_PTR_TO_PHYSADDR(table),
+                                          ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL);
+               override_type = "Logical";
+               goto finish_override;
        }
 
-       acpi_gbl_root_table_list.tables = NULL;
-       acpi_gbl_root_table_list.flags = 0;
-       acpi_gbl_root_table_list.current_table_count = 0;
+       /* (2) Attempt physical override (returns a physical address) */
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       status = acpi_os_physical_table_override(old_table_desc->pointer,
+                                                &address, &length);
+       if (ACPI_SUCCESS(status) && address && length) {
+               acpi_tb_acquire_temp_table(&new_table_desc, address,
+                                          ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL);
+               override_type = "Physical";
+               goto finish_override;
+       }
 
-       return_VOID;
-}
+       return;                 /* There was no override */
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_delete_namespace_by_owner
- *
- * PARAMETERS:  table_index         - Table index
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Delete all namespace objects created when this table was loaded.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
-{
-       acpi_owner_id owner_id;
-       acpi_status status;
+finish_override:
 
-       ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner);
+       /* Validate and verify a table before overriding */
 
-       status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       status = acpi_tb_verify_table(&new_table_desc, NULL);
        if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+               return;
        }
 
-       if (table_index >= acpi_gbl_root_table_list.current_table_count) {
-
-               /* The table index does not exist */
-
-               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-               return_ACPI_STATUS(AE_NOT_EXIST);
-       }
+       ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
+                  " %s table override, new table: " ACPI_PRINTF_UINT,
+                  old_table_desc->signature.ascii,
+                  ACPI_FORMAT_TO_UINT(old_table_desc->address),
+                  override_type, ACPI_FORMAT_TO_UINT(new_table_desc.address)));
 
-       /* Get the owner ID for this table, used to delete namespace nodes */
+       /* We can now uninstall the original table */
 
-       owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id;
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       acpi_tb_uninstall_table(old_table_desc);
 
        /*
-        * Need to acquire the namespace writer lock to prevent interference
-        * with any concurrent namespace walks. The interpreter must be
-        * released during the deletion since the acquisition of the deletion
-        * lock may block, and also since the execution of a namespace walk
-        * must be allowed to use the interpreter.
+        * Replace the original table descriptor and keep its state as
+        * "VALIDATED".
         */
-       (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
-       status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
+       acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address,
+                                     new_table_desc.flags,
+                                     new_table_desc.pointer);
+       acpi_tb_validate_table(old_table_desc);
 
-       acpi_ns_delete_namespace_by_owner(owner_id);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
+       /* Release the temporary table descriptor */
 
-       acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock);
-
-       status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
-       return_ACPI_STATUS(status);
+       acpi_tb_release_temp_table(&new_table_desc);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_allocate_owner_id
+ * FUNCTION:    acpi_tb_store_table
  *
- * PARAMETERS:  table_index         - Table index
+ * PARAMETERS:  address             - Table address
+ *              table               - Table header
+ *              length              - Table length
+ *              flags               - Install flags
+ *              table_index         - Where the table index is returned
  *
- * RETURN:      Status
+ * RETURN:      Status and table index.
  *
- * DESCRIPTION: Allocates owner_id in table_desc
+ * DESCRIPTION: Add an ACPI table to the global table list
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_allocate_owner_id(u32 table_index)
+acpi_status
+acpi_tb_store_table(acpi_physical_address address,
+                   struct acpi_table_header * table,
+                   u32 length, u8 flags, u32 *table_index)
 {
-       acpi_status status = AE_BAD_PARAMETER;
-
-       ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
+       acpi_status status;
+       struct acpi_table_desc *table_desc;
 
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (table_index < acpi_gbl_root_table_list.current_table_count) {
-               status = acpi_ut_allocate_owner_id
-                   (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
+       status = acpi_tb_get_next_root_index(table_index);
+       if (ACPI_FAILURE(status)) {
+               return (status);
        }
 
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_release_owner_id
- *
- * PARAMETERS:  table_index         - Table index
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Releases owner_id in table_desc
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_release_owner_id(u32 table_index)
-{
-       acpi_status status = AE_BAD_PARAMETER;
-
-       ACPI_FUNCTION_TRACE(tb_release_owner_id);
-
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (table_index < acpi_gbl_root_table_list.current_table_count) {
-               acpi_ut_release_owner_id(&
-                                        (acpi_gbl_root_table_list.
-                                         tables[table_index].owner_id));
-               status = AE_OK;
-       }
+       /* Initialize added table */
 
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_ACPI_STATUS(status);
+       table_desc = &acpi_gbl_root_table_list.tables[*table_index];
+       acpi_tb_init_table_descriptor(table_desc, address, flags, table);
+       table_desc->pointer = table;
+       return (AE_OK);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_get_owner_id
+ * FUNCTION:    acpi_tb_uninstall_table
  *
- * PARAMETERS:  table_index         - Table index
- *              owner_id            - Where the table owner_id is returned
+ * PARAMETERS:  table_desc          - Table descriptor
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: returns owner_id for the ACPI table
+ * DESCRIPTION: Delete one internal ACPI table
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id)
+void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc)
 {
-       acpi_status status = AE_BAD_PARAMETER;
-
-       ACPI_FUNCTION_TRACE(tb_get_owner_id);
 
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (table_index < acpi_gbl_root_table_list.current_table_count) {
-               *owner_id =
-                   acpi_gbl_root_table_list.tables[table_index].owner_id;
-               status = AE_OK;
-       }
+       ACPI_FUNCTION_TRACE(tb_uninstall_table);
 
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_is_table_loaded
- *
- * PARAMETERS:  table_index         - Table index
- *
- * RETURN:      Table Loaded Flag
- *
- ******************************************************************************/
+       /* Table must be installed */
 
-u8 acpi_tb_is_table_loaded(u32 table_index)
-{
-       u8 is_loaded = FALSE;
-
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (table_index < acpi_gbl_root_table_list.current_table_count) {
-               is_loaded = (u8)
-                   (acpi_gbl_root_table_list.tables[table_index].flags &
-                    ACPI_TABLE_IS_LOADED);
+       if (!table_desc->address) {
+               return_VOID;
        }
 
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return (is_loaded);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_set_table_loaded_flag
- *
- * PARAMETERS:  table_index         - Table index
- *              is_loaded           - TRUE if table is loaded, FALSE otherwise
- *
- * RETURN:      None
- *
- * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
- *
- ******************************************************************************/
-
-void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
-{
+       acpi_tb_invalidate_table(table_desc);
 
-       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (table_index < acpi_gbl_root_table_list.current_table_count) {
-               if (is_loaded) {
-                       acpi_gbl_root_table_list.tables[table_index].flags |=
-                           ACPI_TABLE_IS_LOADED;
-               } else {
-                       acpi_gbl_root_table_list.tables[table_index].flags &=
-                           ~ACPI_TABLE_IS_LOADED;
-               }
+       if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+           ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) {
+               ACPI_FREE(ACPI_CAST_PTR(void, table_desc->address));
        }
 
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL);
+       return_VOID;
 }
index a4702eee91a820d131960754c14da6aa62f50939..e1638ad5db4ce23c8be4537b924a22fe81818f57 100644 (file)
@@ -178,9 +178,13 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
        }
 
        ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length);
-       acpi_tb_delete_table(table_desc);
-       table_desc->pointer = new_table;
-       table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+       acpi_tb_uninstall_table(table_desc);
+
+       acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
+                                     tables[ACPI_TABLE_INDEX_DSDT],
+                                     ACPI_PTR_TO_PHYSADDR(new_table),
+                                     ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
+                                     new_table);
 
        ACPI_INFO((AE_INFO,
                   "Forced DSDT copy: length 0x%05X copied locally, original unmapped",
@@ -189,116 +193,6 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
        return (new_table);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_install_table
- *
- * PARAMETERS:  address                 - Physical address of DSDT or FACS
- *              signature               - Table signature, NULL if no need to
- *                                        match
- *              table_index             - Index into root table array
- *
- * RETURN:      None
- *
- * DESCRIPTION: Install an ACPI table into the global data structure. The
- *              table override mechanism is called to allow the host
- *              OS to replace any table before it is installed in the root
- *              table array.
- *
- ******************************************************************************/
-
-void
-acpi_tb_install_table(acpi_physical_address address,
-                     char *signature, u32 table_index)
-{
-       struct acpi_table_header *table;
-       struct acpi_table_header *final_table;
-       struct acpi_table_desc *table_desc;
-
-       if (!address) {
-               ACPI_ERROR((AE_INFO,
-                           "Null physical address for ACPI table [%s]",
-                           signature));
-               return;
-       }
-
-       /* Map just the table header */
-
-       table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
-       if (!table) {
-               ACPI_ERROR((AE_INFO,
-                           "Could not map memory for table [%s] at %p",
-                           signature, ACPI_CAST_PTR(void, address)));
-               return;
-       }
-
-       /* If a particular signature is expected (DSDT/FACS), it must match */
-
-       if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
-               ACPI_BIOS_ERROR((AE_INFO,
-                                "Invalid signature 0x%X for ACPI table, expected [%s]",
-                                *ACPI_CAST_PTR(u32, table->signature),
-                                signature));
-               goto unmap_and_exit;
-       }
-
-       /*
-        * Initialize the table entry. Set the pointer to NULL, since the
-        * table is not fully mapped at this time.
-        */
-       table_desc = &acpi_gbl_root_table_list.tables[table_index];
-
-       table_desc->address = address;
-       table_desc->pointer = NULL;
-       table_desc->length = table->length;
-       table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED;
-       ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
-
-       /*
-        * ACPI Table Override:
-        *
-        * Before we install the table, let the host OS override it with a new
-        * one if desired. Any table within the RSDT/XSDT can be replaced,
-        * including the DSDT which is pointed to by the FADT.
-        *
-        * NOTE: If the table is overridden, then final_table will contain a
-        * mapped pointer to the full new table. If the table is not overridden,
-        * or if there has been a physical override, then the table will be
-        * fully mapped later (in verify table). In any case, we must
-        * unmap the header that was mapped above.
-        */
-       final_table = acpi_tb_table_override(table, table_desc);
-       if (!final_table) {
-               final_table = table;    /* There was no override */
-       }
-
-       acpi_tb_print_table_header(table_desc->address, final_table);
-
-       /* Set the global integer width (based upon revision of the DSDT) */
-
-       if (table_index == ACPI_TABLE_INDEX_DSDT) {
-               acpi_ut_set_integer_width(final_table->revision);
-       }
-
-       /*
-        * If we have a physical override during this early loading of the ACPI
-        * tables, unmap the table for now. It will be mapped again later when
-        * it is actually used. This supports very early loading of ACPI tables,
-        * before virtual memory is fully initialized and running within the
-        * host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE
-        * flag set and will not be deleted below.
-        */
-       if (final_table != table) {
-               acpi_tb_delete_table(table_desc);
-       }
-
-unmap_and_exit:
-
-       /* Always unmap the table header that we mapped above */
-
-       acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_get_root_table_entry
@@ -461,9 +355,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
        u32 table_count;
        struct acpi_table_header *table;
        acpi_physical_address address;
+       acpi_physical_address rsdt_address;
        u32 length;
        u8 *table_entry;
        acpi_status status;
+       u32 table_index;
 
        ACPI_FUNCTION_TRACE(tb_parse_root_table);
 
@@ -488,11 +384,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
                 * as per the ACPI specification.
                 */
                address = (acpi_physical_address) rsdp->xsdt_physical_address;
+               rsdt_address =
+                   (acpi_physical_address) rsdp->rsdt_physical_address;
                table_entry_size = ACPI_XSDT_ENTRY_SIZE;
        } else {
                /* Root table is an RSDT (32-bit physical addresses) */
 
                address = (acpi_physical_address) rsdp->rsdt_physical_address;
+               rsdt_address = address;
                table_entry_size = ACPI_RSDT_ENTRY_SIZE;
        }
 
@@ -515,8 +414,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
 
                        /* Fall back to the RSDT */
 
-                       address =
-                           (acpi_physical_address) rsdp->rsdt_physical_address;
+                       address = rsdt_address;
                        table_entry_size = ACPI_RSDT_ENTRY_SIZE;
                }
        }
@@ -573,31 +471,24 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
        /* Initialize the root table array from the RSDT/XSDT */
 
        for (i = 0; i < table_count; i++) {
-               if (acpi_gbl_root_table_list.current_table_count >=
-                   acpi_gbl_root_table_list.max_table_count) {
-
-                       /* There is no more room in the root table array, attempt resize */
-
-                       status = acpi_tb_resize_root_table_list();
-                       if (ACPI_FAILURE(status)) {
-                               ACPI_WARNING((AE_INFO,
-                                             "Truncating %u table entries!",
-                                             (unsigned) (table_count -
-                                              (acpi_gbl_root_table_list.
-                                                         current_table_count -
-                                                         2))));
-                               break;
-                       }
-               }
 
                /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
 
-               acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.
-                                               current_table_count].address =
-                   acpi_tb_get_root_table_entry(table_entry, table_entry_size);
+               status =
+                   acpi_tb_install_standard_table(acpi_tb_get_root_table_entry
+                                                  (table_entry,
+                                                   table_entry_size),
+                                                  ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
+                                                  FALSE, TRUE, &table_index);
+
+               if (ACPI_SUCCESS(status) &&
+                   ACPI_COMPARE_NAME(&acpi_gbl_root_table_list.
+                                     tables[table_index].signature,
+                                     ACPI_SIG_FADT)) {
+                       acpi_tb_parse_fadt(table_index);
+               }
 
                table_entry += table_entry_size;
-               acpi_gbl_root_table_list.current_table_count++;
        }
 
        /*
@@ -606,22 +497,5 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
         */
        acpi_os_unmap_memory(table, length);
 
-       /*
-        * Complete the initialization of the root table array by examining
-        * the header of each table
-        */
-       for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) {
-               acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
-                                     address, NULL, i);
-
-               /* Special case for FADT - validate it then get the DSDT and FACS */
-
-               if (ACPI_COMPARE_NAME
-                   (&acpi_gbl_root_table_list.tables[i].signature,
-                    ACPI_SIG_FADT)) {
-                       acpi_tb_parse_fadt(i);
-               }
-       }
-
        return_ACPI_STATUS(AE_OK);
 }
index a1593159d9ea4faeb3d0d61b8731974a1af05676..6482b0ded65214e120ebb51a01f8fc6790ca7353 100644 (file)
@@ -206,8 +206,8 @@ acpi_status
 acpi_get_table_header(char *signature,
                      u32 instance, struct acpi_table_header *out_table_header)
 {
-       u32 i;
-       u32 j;
+       u32 i;
+       u32 j;
        struct acpi_table_header *header;
 
        /* Parameter validation */
@@ -233,7 +233,7 @@ acpi_get_table_header(char *signature,
                if (!acpi_gbl_root_table_list.tables[i].pointer) {
                        if ((acpi_gbl_root_table_list.tables[i].flags &
                             ACPI_TABLE_ORIGIN_MASK) ==
-                           ACPI_TABLE_ORIGIN_MAPPED) {
+                           ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) {
                                header =
                                    acpi_os_map_memory(acpi_gbl_root_table_list.
                                                       tables[i].address,
@@ -321,8 +321,8 @@ acpi_get_table_with_size(char *signature,
               u32 instance, struct acpi_table_header **out_table,
               acpi_size *tbl_size)
 {
-       u32 i;
-       u32 j;
+       u32 i;
+       u32 j;
        acpi_status status;
 
        /* Parameter validation */
@@ -346,7 +346,7 @@ acpi_get_table_with_size(char *signature,
                }
 
                status =
-                   acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+                   acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
                if (ACPI_SUCCESS(status)) {
                        *out_table = acpi_gbl_root_table_list.tables[i].pointer;
                        *tbl_size = acpi_gbl_root_table_list.tables[i].length;
@@ -390,7 +390,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
  *
  ******************************************************************************/
 acpi_status
-acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
+acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table)
 {
        acpi_status status;
 
@@ -416,8 +416,8 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
                /* Table is not mapped, map it */
 
                status =
-                   acpi_tb_verify_table(&acpi_gbl_root_table_list.
-                                        tables[table_index]);
+                   acpi_tb_validate_table(&acpi_gbl_root_table_list.
+                                          tables[table_index]);
                if (ACPI_FAILURE(status)) {
                        (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
                        return_ACPI_STATUS(status);
index 0909420fc776510c1d4fef5278112391a5ad0f4d..ab5308b81aa82e1e5d92fe89c36c60441d381326 100644 (file)
@@ -117,7 +117,7 @@ static acpi_status acpi_tb_load_namespace(void)
                                tables[ACPI_TABLE_INDEX_DSDT].signature),
                               ACPI_SIG_DSDT)
            ||
-           ACPI_FAILURE(acpi_tb_verify_table
+           ACPI_FAILURE(acpi_tb_validate_table
                         (&acpi_gbl_root_table_list.
                          tables[ACPI_TABLE_INDEX_DSDT]))) {
                status = AE_NO_ACPI_TABLES;
@@ -128,7 +128,7 @@ static acpi_status acpi_tb_load_namespace(void)
         * Save the DSDT pointer for simple access. This is the mapped memory
         * address. We must take care here because the address of the .Tables
         * array can change dynamically as tables are loaded at run-time. Note:
-        * .Pointer field is not validated until after call to acpi_tb_verify_table.
+        * .Pointer field is not validated until after call to acpi_tb_validate_table.
         */
        acpi_gbl_DSDT =
            acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer;
@@ -174,24 +174,11 @@ static acpi_status acpi_tb_load_namespace(void)
                                        (acpi_gbl_root_table_list.tables[i].
                                         signature), ACPI_SIG_PSDT))
                    ||
-                   ACPI_FAILURE(acpi_tb_verify_table
+                   ACPI_FAILURE(acpi_tb_validate_table
                                 (&acpi_gbl_root_table_list.tables[i]))) {
                        continue;
                }
 
-               /*
-                * Optionally do not load any SSDTs from the RSDT/XSDT. This can
-                * be useful for debugging ACPI problems on some machines.
-                */
-               if (acpi_gbl_disable_ssdt_table_load) {
-                       ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p",
-                                  acpi_gbl_root_table_list.tables[i].signature.
-                                  ascii, ACPI_CAST_PTR(void,
-                                                       acpi_gbl_root_table_list.
-                                                       tables[i].address)));
-                       continue;
-               }
-
                /* Ignore errors while loading tables, get as many as possible */
 
                (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
@@ -206,6 +193,45 @@ unlock_and_exit:
        return_ACPI_STATUS(status);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_install_table
+ *
+ * PARAMETERS:  address             - Address of the ACPI table to be installed.
+ *              physical            - Whether the address is a physical table
+ *                                    address or not
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Dynamically install an ACPI table.
+ *              Note: This function should only be invoked after
+ *                    acpi_initialize_tables() and before acpi_load_tables().
+ *
+ ******************************************************************************/
+
+acpi_status __init
+acpi_install_table(acpi_physical_address address, u8 physical)
+{
+       acpi_status status;
+       u8 flags;
+       u32 table_index;
+
+       ACPI_FUNCTION_TRACE(acpi_install_table);
+
+       if (physical) {
+               flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL;
+       } else {
+               flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL;
+       }
+
+       status = acpi_tb_install_standard_table(address, flags,
+                                               FALSE, FALSE, &table_index);
+
+       return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL_INIT(acpi_install_table)
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_table
@@ -222,11 +248,9 @@ unlock_and_exit:
  *              to ensure that the table is not deleted or unmapped.
  *
  ******************************************************************************/
-
 acpi_status acpi_load_table(struct acpi_table_header *table)
 {
        acpi_status status;
-       struct acpi_table_desc table_desc;
        u32 table_index;
 
        ACPI_FUNCTION_TRACE(acpi_load_table);
@@ -237,14 +261,6 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Init local table descriptor */
-
-       ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
-       table_desc.address = ACPI_PTR_TO_PHYSADDR(table);
-       table_desc.pointer = table;
-       table_desc.length = table->length;
-       table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
-
        /* Must acquire the interpreter lock during this operation */
 
        status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
@@ -255,7 +271,24 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
        /* Install the table and load it into the namespace */
 
        ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:"));
-       status = acpi_tb_add_table(&table_desc, &table_index);
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+       status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
+                                               ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
+                                               TRUE, FALSE, &table_index);
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       if (ACPI_FAILURE(status)) {
+               goto unlock_and_exit;
+       }
+
+       /*
+        * Note: Now table is "INSTALLED", it must be validated before
+        * using.
+        */
+       status =
+           acpi_tb_validate_table(&acpi_gbl_root_table_list.
+                                  tables[table_index]);
        if (ACPI_FAILURE(status)) {
                goto unlock_and_exit;
        }
index fbfa9eca011f8457ba0fecd5e1bed00b69466022..90ec37c473c617f24af5beae34b1e2b6931eb4b4 100644 (file)
@@ -462,7 +462,7 @@ char *acpi_ut_get_mutex_name(u32 mutex_id)
 
 /* Names for Notify() values, used for debug output */
 
-static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = {
+static const char *acpi_gbl_generic_notify[ACPI_NOTIFY_MAX + 1] = {
        /* 00 */ "Bus Check",
        /* 01 */ "Device Check",
        /* 02 */ "Device Wake",
@@ -473,23 +473,75 @@ static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = {
        /* 07 */ "Power Fault",
        /* 08 */ "Capabilities Check",
        /* 09 */ "Device PLD Check",
-       /* 10 */ "Reserved",
-       /* 11 */ "System Locality Update",
-       /* 12 */ "Shutdown Request"
+       /* 0A */ "Reserved",
+       /* 0B */ "System Locality Update",
+       /* 0C */ "Shutdown Request"
 };
 
-const char *acpi_ut_get_notify_name(u32 notify_value)
+static const char *acpi_gbl_device_notify[4] = {
+       /* 80 */ "Status Change",
+       /* 81 */ "Information Change",
+       /* 82 */ "Device-Specific Change",
+       /* 83 */ "Device-Specific Change"
+};
+
+static const char *acpi_gbl_processor_notify[4] = {
+       /* 80 */ "Performance Capability Change",
+       /* 81 */ "C-State Change",
+       /* 82 */ "Throttling Capability Change",
+       /* 83 */ "Device-Specific Change"
+};
+
+static const char *acpi_gbl_thermal_notify[4] = {
+       /* 80 */ "Thermal Status Change",
+       /* 81 */ "Thermal Trip Point Change",
+       /* 82 */ "Thermal Device List Change",
+       /* 83 */ "Thermal Relationship Change"
+};
+
+const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type)
 {
 
+       /* 00 - 0C are common to all object types */
+
        if (notify_value <= ACPI_NOTIFY_MAX) {
-               return (acpi_gbl_notify_value_names[notify_value]);
-       } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+               return (acpi_gbl_generic_notify[notify_value]);
+       }
+
+       /* 0D - 7F are reserved */
+
+       if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
                return ("Reserved");
-       } else if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
-               return ("Device Specific");
-       } else {
-               return ("Hardware Specific");
        }
+
+       /* 80 - 83 are per-object-type */
+
+       if (notify_value <= 0x83) {
+               switch (type) {
+               case ACPI_TYPE_ANY:
+               case ACPI_TYPE_DEVICE:
+                       return (acpi_gbl_device_notify[notify_value - 0x80]);
+
+               case ACPI_TYPE_PROCESSOR:
+                       return (acpi_gbl_processor_notify[notify_value - 0x80]);
+
+               case ACPI_TYPE_THERMAL:
+                       return (acpi_gbl_thermal_notify[notify_value - 0x80]);
+
+               default:
+                       return ("Target object type does not support notifies");
+               }
+       }
+
+       /* 84 - BF are device-specific */
+
+       if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
+               return ("Device-Specific");
+       }
+
+       /* C0 and above are hardware-specific */
+
+       return ("Hardware-Specific");
 }
 #endif
 
index 77219336c7e01f78c67003a1fc93e48d56e3197b..6dc54b3c28b07e2fe1b04002540a04a25cddfff1 100644 (file)
@@ -353,7 +353,7 @@ void acpi_ut_print_string(char *string, u16 max_length)
        }
 
        acpi_os_printf("\"");
-       for (i = 0; string[i] && (i < max_length); i++) {
+       for (i = 0; (i < max_length) && string[i]; i++) {
 
                /* Escape sequences */
 
index d7d32c28829b17834507bf8683f2c2a5c77d0a0d..ad11ba4a412dedc893ae4bdbb9230b3583bbf00b 100644 (file)
@@ -206,13 +206,13 @@ unlock:
        spin_unlock_irqrestore(&ec->lock, flags);
 }
 
-static int acpi_ec_sync_query(struct acpi_ec *ec);
+static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
 
 static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
 {
        if (state & ACPI_EC_FLAG_SCI) {
                if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
-                       return acpi_ec_sync_query(ec);
+                       return acpi_ec_sync_query(ec, NULL);
        }
        return 0;
 }
@@ -443,10 +443,8 @@ acpi_handle ec_get_handle(void)
 
 EXPORT_SYMBOL(ec_get_handle);
 
-static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
-
 /*
- * Clears stale _Q events that might have accumulated in the EC.
+ * Process _Q events that might have accumulated in the EC.
  * Run with locked ec mutex.
  */
 static void acpi_ec_clear(struct acpi_ec *ec)
@@ -455,7 +453,7 @@ static void acpi_ec_clear(struct acpi_ec *ec)
        u8 value = 0;
 
        for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
-               status = acpi_ec_query_unlocked(ec, &value);
+               status = acpi_ec_sync_query(ec, &value);
                if (status || !value)
                        break;
        }
@@ -582,13 +580,18 @@ static void acpi_ec_run(void *cxt)
        kfree(handler);
 }
 
-static int acpi_ec_sync_query(struct acpi_ec *ec)
+static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
 {
        u8 value = 0;
        int status;
        struct acpi_ec_query_handler *handler, *copy;
-       if ((status = acpi_ec_query_unlocked(ec, &value)))
+
+       status = acpi_ec_query_unlocked(ec, &value);
+       if (data)
+               *data = value;
+       if (status)
                return status;
+
        list_for_each_entry(handler, &ec->list, node) {
                if (value == handler->query_bit) {
                        /* have custom handler for this bit */
@@ -612,7 +615,7 @@ static void acpi_ec_gpe_query(void *ec_cxt)
        if (!ec)
                return;
        mutex_lock(&ec->mutex);
-       acpi_ec_sync_query(ec);
+       acpi_ec_sync_query(ec, NULL);
        mutex_unlock(&ec->mutex);
 }
 
index 6776c599816f33100a2403ae7286e534f0a96354..9aeae41e22fbe16af38945c25cefb856a65a9e84 100644 (file)
@@ -1770,16 +1770,15 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
 }
 #endif
 
-static int __init acpi_no_auto_ssdt_setup(char *s)
+static int __init acpi_no_static_ssdt_setup(char *s)
 {
-        printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n");
+       acpi_gbl_disable_ssdt_table_install = TRUE;
+       pr_info("ACPI: static SSDT installation disabled\n");
 
-        acpi_gbl_disable_ssdt_table_load = TRUE;
-
-        return 1;
+       return 0;
 }
 
-__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
+early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup);
 
 static int __init acpi_disable_return_repair(char *s)
 {
index 7efe546a8c42704137f3cbae8a3159485f3473b9..db5fc6f9628ebcf1f5efbf8b4bf1d1291c7d94e9 100644 (file)
@@ -2259,12 +2259,16 @@ int __init acpi_scan_init(void)
        if (result)
                goto out;
 
-       result = acpi_bus_scan_fixed();
-       if (result) {
-               acpi_detach_data(acpi_root->handle, acpi_scan_drop_device);
-               acpi_device_del(acpi_root);
-               put_device(&acpi_root->dev);
-               goto out;
+       /* Fixed feature devices do not exist on HW-reduced platform */
+       if (!acpi_gbl_reduced_hardware) {
+               result = acpi_bus_scan_fixed();
+               if (result) {
+                       acpi_detach_data(acpi_root->handle,
+                                        acpi_scan_drop_device);
+                       acpi_device_del(acpi_root);
+                       put_device(&acpi_root->dev);
+                       goto out;
+               }
        }
 
        acpi_update_all_gpes();
index c2706047337f17c0fad38b3161cabc93d95be0e5..a91bf471262d58128d477c8b93a38eeec5102169 100644 (file)
@@ -123,6 +123,15 @@ config AHCI_IMX
 
          If unsure, say N.
 
+config AHCI_MVEBU
+       tristate "Marvell EBU AHCI SATA support"
+       depends on ARCH_MVEBU
+       help
+         This option enables support for the Marvebu EBU SoC's
+         onboard AHCI SATA.
+
+         If unsure, say N.
+
 config AHCI_SUNXI
        tristate "Allwinner sunxi AHCI SATA support"
        depends on ARCH_SUNXI
index 44c8016e565c9b8771924fbc7f7b5a00d9c078c7..5a02aeecef5b548438c75e90fb17ae81b6804b4c 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_SATA_DWC)                += sata_dwc_460ex.o
 obj-$(CONFIG_SATA_HIGHBANK)    += sata_highbank.o libahci.o
 obj-$(CONFIG_AHCI_DA850)       += ahci_da850.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_IMX)         += ahci_imx.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_MVEBU)       += ahci_mvebu.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_SUNXI)       += ahci_sunxi.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_ST)          += ahci_st.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_XGENE)       += ahci_xgene.o libahci.o libahci_platform.o
index 71e15b73513d22ed2bf5ac34afec9b5f42679fe7..60707814a84b19e2581d6309c2a17d4823d1e015 100644 (file)
@@ -1115,6 +1115,17 @@ static bool ahci_broken_online(struct pci_dev *pdev)
        return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
 }
 
+static bool ahci_broken_devslp(struct pci_dev *pdev)
+{
+       /* device with broken DEVSLP but still showing SDS capability */
+       static const struct pci_device_id ids[] = {
+               { PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
+               {}
+       };
+
+       return pci_match_id(ids, pdev);
+}
+
 #ifdef CONFIG_ATA_ACPI
 static void ahci_gtf_filter_workaround(struct ata_host *host)
 {
@@ -1364,6 +1375,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+       /* must set flag prior to save config in order to take effect */
+       if (ahci_broken_devslp(pdev))
+               hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
+
        /* save initial config */
        ahci_pci_save_initial_config(pdev, hpriv);
 
index b5eb886da22635c3c76775bc0ef6374af3464b98..af63c75c20011e10d76be66edb27d595cb47978c 100644 (file)
@@ -236,6 +236,7 @@ enum {
                                                        port start (wait until
                                                        error-handling stage) */
        AHCI_HFLAG_MULTI_MSI            = (1 << 16), /* multiple PCI MSIs */
+       AHCI_HFLAG_NO_DEVSLP            = (1 << 17), /* no device sleep */
 
        /* ap->flags bits */
 
index 497c7abe1c7df5ef79ccd246828b68a1251c5201..5824d99e63fda9bd1f460897716c16995b42169f 100644 (file)
 #include "ahci.h"
 
 enum {
-       PORT_PHY_CTL = 0x178,                   /* Port0 PHY Control */
-       PORT_PHY_CTL_PDDQ_LOC = 0x100000,       /* PORT_PHY_CTL bits */
-       HOST_TIMER1MS = 0xe0,                   /* Timer 1-ms */
+       /* Timer 1-ms Register */
+       IMX_TIMER1MS                            = 0x00e0,
+       /* Port0 PHY Control Register */
+       IMX_P0PHYCR                             = 0x0178,
+       IMX_P0PHYCR_TEST_PDDQ                   = 1 << 20,
+       IMX_P0PHYCR_CR_READ                     = 1 << 19,
+       IMX_P0PHYCR_CR_WRITE                    = 1 << 18,
+       IMX_P0PHYCR_CR_CAP_DATA                 = 1 << 17,
+       IMX_P0PHYCR_CR_CAP_ADDR                 = 1 << 16,
+       /* Port0 PHY Status Register */
+       IMX_P0PHYSR                             = 0x017c,
+       IMX_P0PHYSR_CR_ACK                      = 1 << 18,
+       IMX_P0PHYSR_CR_DATA_OUT                 = 0xffff << 0,
+       /* Lane0 Output Status Register */
+       IMX_LANE0_OUT_STAT                      = 0x2003,
+       IMX_LANE0_OUT_STAT_RX_PLL_STATE         = 1 << 1,
+       /* Clock Reset Register */
+       IMX_CLOCK_RESET                         = 0x7f3f,
+       IMX_CLOCK_RESET_RESET                   = 1 << 0,
 };
 
 enum ahci_imx_type {
@@ -54,9 +70,149 @@ MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support
 
 static void ahci_imx_host_stop(struct ata_host *host);
 
+static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert)
+{
+       int timeout = 10;
+       u32 crval;
+       u32 srval;
+
+       /* Assert or deassert the bit */
+       crval = readl(mmio + IMX_P0PHYCR);
+       if (assert)
+               crval |= bit;
+       else
+               crval &= ~bit;
+       writel(crval, mmio + IMX_P0PHYCR);
+
+       /* Wait for the cr_ack signal */
+       do {
+               srval = readl(mmio + IMX_P0PHYSR);
+               if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK)
+                       break;
+               usleep_range(100, 200);
+       } while (--timeout);
+
+       return timeout ? 0 : -ETIMEDOUT;
+}
+
+static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio)
+{
+       u32 crval = addr;
+       int ret;
+
+       /* Supply the address on cr_data_in */
+       writel(crval, mmio + IMX_P0PHYCR);
+
+       /* Assert the cr_cap_addr signal */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true);
+       if (ret)
+               return ret;
+
+       /* Deassert cr_cap_addr */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int imx_phy_reg_write(u16 val, void __iomem *mmio)
+{
+       u32 crval = val;
+       int ret;
+
+       /* Supply the data on cr_data_in */
+       writel(crval, mmio + IMX_P0PHYCR);
+
+       /* Assert the cr_cap_data signal */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true);
+       if (ret)
+               return ret;
+
+       /* Deassert cr_cap_data */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false);
+       if (ret)
+               return ret;
+
+       if (val & IMX_CLOCK_RESET_RESET) {
+               /*
+                * In case we're resetting the phy, it's unable to acknowledge,
+                * so we return immediately here.
+                */
+               crval |= IMX_P0PHYCR_CR_WRITE;
+               writel(crval, mmio + IMX_P0PHYCR);
+               goto out;
+       }
+
+       /* Assert the cr_write signal */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true);
+       if (ret)
+               return ret;
+
+       /* Deassert cr_write */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false);
+       if (ret)
+               return ret;
+
+out:
+       return 0;
+}
+
+static int imx_phy_reg_read(u16 *val, void __iomem *mmio)
+{
+       int ret;
+
+       /* Assert the cr_read signal */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true);
+       if (ret)
+               return ret;
+
+       /* Capture the data from cr_data_out[] */
+       *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT;
+
+       /* Deassert cr_read */
+       ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
+{
+       void __iomem *mmio = hpriv->mmio;
+       int timeout = 10;
+       u16 val;
+       int ret;
+
+       /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */
+       ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio);
+       if (ret)
+               return ret;
+       ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio);
+       if (ret)
+               return ret;
+
+       /* Wait for PHY RX_PLL to be stable */
+       do {
+               usleep_range(100, 200);
+               ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio);
+               if (ret)
+                       return ret;
+               ret = imx_phy_reg_read(&val, mmio);
+               if (ret)
+                       return ret;
+               if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE)
+                       break;
+       } while (--timeout);
+
+       return timeout ? 0 : -ETIMEDOUT;
+}
+
 static int imx_sata_enable(struct ahci_host_priv *hpriv)
 {
        struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+       struct device *dev = &imxpriv->ahci_pdev->dev;
        int ret;
 
        if (imxpriv->no_device)
@@ -101,6 +257,12 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+
+               ret = imx_sata_phy_reset(hpriv);
+               if (ret) {
+                       dev_err(dev, "failed to reset phy: %d\n", ret);
+                       goto disable_regulator;
+               }
        }
 
        usleep_range(1000, 2000);
@@ -156,8 +318,8 @@ static void ahci_imx_error_handler(struct ata_port *ap)
         * without full reset once the pddq mode is enabled making it
         * impossible to use as part of libata LPM.
         */
-       reg_val = readl(mmio + PORT_PHY_CTL);
-       writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
+       reg_val = readl(mmio + IMX_P0PHYCR);
+       writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR);
        imx_sata_disable(hpriv);
        imxpriv->no_device = true;
 }
@@ -217,6 +379,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
        if (!imxpriv)
                return -ENOMEM;
 
+       imxpriv->ahci_pdev = pdev;
        imxpriv->no_device = false;
        imxpriv->first_time = true;
        imxpriv->type = (enum ahci_imx_type)of_id->data;
@@ -248,7 +411,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
 
        /*
         * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
-        * and IP vendor specific register HOST_TIMER1MS.
+        * and IP vendor specific register IMX_TIMER1MS.
         * Configure CAP_SSS (support stagered spin up).
         * Implement the port0.
         * Get the ahb clock rate, and configure the TIMER1MS register.
@@ -265,7 +428,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
        }
 
        reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
-       writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
+       writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
 
        ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
        if (ret)
diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c
new file mode 100644 (file)
index 0000000..1df8630
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * AHCI glue platform driver for Marvell EBU SOCs
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ * Marcin Wojtas <mw@semihalf.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/ahci_platform.h>
+#include <linux/kernel.h>
+#include <linux/mbus.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "ahci.h"
+
+#define AHCI_VENDOR_SPECIFIC_0_ADDR  0xa0
+#define AHCI_VENDOR_SPECIFIC_0_DATA  0xa4
+
+#define AHCI_WINDOW_CTRL(win)  (0x60 + ((win) << 4))
+#define AHCI_WINDOW_BASE(win)  (0x64 + ((win) << 4))
+#define AHCI_WINDOW_SIZE(win)  (0x68 + ((win) << 4))
+
+static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv,
+                                  const struct mbus_dram_target_info *dram)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               writel(0, hpriv->mmio + AHCI_WINDOW_CTRL(i));
+               writel(0, hpriv->mmio + AHCI_WINDOW_BASE(i));
+               writel(0, hpriv->mmio + AHCI_WINDOW_SIZE(i));
+       }
+
+       for (i = 0; i < dram->num_cs; i++) {
+               const struct mbus_dram_window *cs = dram->cs + i;
+
+               writel((cs->mbus_attr << 8) |
+                      (dram->mbus_dram_target_id << 4) | 1,
+                      hpriv->mmio + AHCI_WINDOW_CTRL(i));
+               writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i));
+               writel(((cs->size - 1) & 0xffff0000),
+                      hpriv->mmio + AHCI_WINDOW_SIZE(i));
+       }
+}
+
+static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
+{
+       /*
+        * Enable the regret bit to allow the SATA unit to regret a
+        * request that didn't receive an acknowlegde and avoid a
+        * deadlock
+        */
+       writel(0x4, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR);
+       writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
+}
+
+static const struct ata_port_info ahci_mvebu_port_info = {
+       .flags     = AHCI_FLAG_COMMON,
+       .pio_mask  = ATA_PIO4,
+       .udma_mask = ATA_UDMA6,
+       .port_ops  = &ahci_platform_ops,
+};
+
+static int ahci_mvebu_probe(struct platform_device *pdev)
+{
+       struct ahci_host_priv *hpriv;
+       const struct mbus_dram_target_info *dram;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       dram = mv_mbus_dram_info();
+       if (!dram)
+               return -ENODEV;
+
+       ahci_mvebu_mbus_config(hpriv, dram);
+       ahci_mvebu_regret_option(hpriv);
+
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+static const struct of_device_id ahci_mvebu_of_match[] = {
+       { .compatible = "marvell,armada-380-ahci", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match);
+
+/*
+ * We currently don't provide power management related operations,
+ * since there is no suspend/resume support at the platform level for
+ * Armada 38x for the moment.
+ */
+static struct platform_driver ahci_mvebu_driver = {
+       .probe = ahci_mvebu_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "ahci-mvebu",
+               .owner = THIS_MODULE,
+               .of_match_table = ahci_mvebu_of_match,
+       },
+};
+module_platform_driver(ahci_mvebu_driver);
+
+MODULE_DESCRIPTION("Marvell EBU AHCI SATA driver");
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>, Marcin Wojtas <mw@semihalf.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ahci_mvebu");
index 6bd4f660b4e15966ca2c351b4501c0521491de32..b9861453fc8148612a740418f5fee3088d7b65a1 100644 (file)
@@ -452,6 +452,13 @@ void ahci_save_initial_config(struct device *dev,
                cap &= ~HOST_CAP_SNTF;
        }
 
+       if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) {
+               dev_info(dev,
+                        "controller can't do DEVSLP, turning off\n");
+               cap2 &= ~HOST_CAP2_SDS;
+               cap2 &= ~HOST_CAP2_SADM;
+       }
+
        if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) {
                dev_info(dev, "controller can do FBS, turning on CAP_FBS\n");
                cap |= HOST_CAP_FBS;
index ef8567de6a7515b45631f4a06f3447fe0604f0b3..72691fd939483af322e4460d8d168b2bf5899b46 100644 (file)
@@ -1993,7 +1993,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
        memcpy(rbuf, hdr, sizeof(hdr));
        memcpy(&rbuf[8], "ATA     ", 8);
        ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
-       ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
+
+       /* From SAT, use last 2 words from fw rev unless they are spaces */
+       ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4);
+       if (strncmp(&rbuf[32], "    ", 4) == 0)
+               ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
 
        if (rbuf[32] == 0 || rbuf[32] == ' ')
                memcpy(&rbuf[32], "n/a ", 4);
index b603720b877dd0344478ddecf234bb14f77975fa..1121153f1ecde7e08502c2a0a33bc501abc6a9bd 100644 (file)
@@ -2433,15 +2433,6 @@ int ata_pci_sff_activate_host(struct ata_host *host,
                mask = (1 << 2) | (1 << 0);
                if ((tmp8 & mask) != mask)
                        legacy_mode = 1;
-#if defined(CONFIG_NO_ATA_LEGACY)
-               /* Some platforms with PCI limits cannot address compat
-                  port space. In that case we punt if their firmware has
-                  left a device in compatibility mode */
-               if (legacy_mode) {
-                       printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
-                       return -EOPNOTSUPP;
-               }
-#endif
        }
 
        if (!devres_open_group(dev, NULL, GFP_KERNEL))
index 83c4ddb1bc7f6e95b79d5e65462430a3c02a292d..2a97d3a531ece7d9fdcedfca294f007ec21e25a9 100644 (file)
@@ -865,7 +865,7 @@ static int octeon_cf_probe(struct platform_device *pdev)
        if (node == NULL)
                return -EINVAL;
 
-       cf_port = kzalloc(sizeof(*cf_port), GFP_KERNEL);
+       cf_port = devm_kzalloc(&pdev->dev, sizeof(*cf_port), GFP_KERNEL);
        if (!cf_port)
                return -ENOMEM;
 
@@ -881,10 +881,9 @@ static int octeon_cf_probe(struct platform_device *pdev)
        n_size = of_n_size_cells(node);
 
        reg_prop = of_find_property(node, "reg", &reg_len);
-       if (!reg_prop || reg_len < sizeof(__be32)) {
-               rv = -EINVAL;
-               goto free_cf_port;
-       }
+       if (!reg_prop || reg_len < sizeof(__be32))
+               return -EINVAL;
+
        cs_num = reg_prop->value;
        cf_port->cs0 = be32_to_cpup(cs_num);
 
@@ -901,16 +900,13 @@ static int octeon_cf_probe(struct platform_device *pdev)
                                res_dma = platform_get_resource(dma_dev, IORESOURCE_MEM, 0);
                                if (!res_dma) {
                                        of_node_put(dma_node);
-                                       rv = -EINVAL;
-                                       goto free_cf_port;
+                                       return -EINVAL;
                                }
                                cf_port->dma_base = (u64)devm_ioremap_nocache(&pdev->dev, res_dma->start,
                                                                         resource_size(res_dma));
-
                                if (!cf_port->dma_base) {
                                        of_node_put(dma_node);
-                                       rv = -EINVAL;
-                                       goto free_cf_port;
+                                       return -EINVAL;
                                }
 
                                irq_handler = octeon_cf_interrupt;
@@ -921,41 +917,34 @@ static int octeon_cf_probe(struct platform_device *pdev)
                        of_node_put(dma_node);
                }
                res_cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               if (!res_cs1) {
-                       rv = -EINVAL;
-                       goto free_cf_port;
-               }
+               if (!res_cs1)
+                       return -EINVAL;
+
                cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,
                                           resource_size(res_cs1));
-
                if (!cs1)
-                       goto free_cf_port;
+                       return rv;
+
+               if (reg_len < (n_addr + n_size + 1) * sizeof(__be32))
+                       return -EINVAL;
 
-               if (reg_len < (n_addr + n_size + 1) * sizeof(__be32)) {
-                       rv = -EINVAL;
-                       goto free_cf_port;
-               }
                cs_num += n_addr + n_size;
                cf_port->cs1 = be32_to_cpup(cs_num);
        }
 
        res_cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       if (!res_cs0) {
-               rv = -EINVAL;
-               goto free_cf_port;
-       }
+       if (!res_cs0)
+               return -EINVAL;
 
        cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start,
                                   resource_size(res_cs0));
-
        if (!cs0)
-               goto free_cf_port;
+               return rv;
 
        /* allocate host */
        host = ata_host_alloc(&pdev->dev, 1);
        if (!host)
-               goto free_cf_port;
+               return rv;
 
        ap = host->ports[0];
        ap->private_data = cf_port;
@@ -1020,17 +1009,12 @@ static int octeon_cf_probe(struct platform_device *pdev)
 
        ata_port_desc(ap, "cmd %p ctl %p", base, ap->ioaddr.ctl_addr);
 
-
        dev_info(&pdev->dev, "version " DRV_VERSION" %d bit%s.\n",
                 is_16bit ? 16 : 8,
                 cf_port->is_true_ide ? ", True IDE" : "");
 
        return ata_host_activate(host, irq, irq_handler,
                                 IRQF_SHARED, &octeon_cf_sht);
-
-free_cf_port:
-       kfree(cf_port);
-       return rv;
 }
 
 static void octeon_cf_shutdown(struct device *dev)
index 8986b9f22781fa667cf41a37b5889e8ac3be0a36..62ec61e8f84ac90d7c4e433ccc4ead67ff96fbd3 100644 (file)
@@ -52,6 +52,7 @@ static DEFINE_MUTEX(deferred_probe_mutex);
 static LIST_HEAD(deferred_probe_pending_list);
 static LIST_HEAD(deferred_probe_active_list);
 static struct workqueue_struct *deferred_wq;
+static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
 
 /**
  * deferred_probe_work_func() - Retry probing devices in the active list.
@@ -135,6 +136,17 @@ static bool driver_deferred_probe_enable = false;
  * This functions moves all devices from the pending list to the active
  * list and schedules the deferred probe workqueue to process them.  It
  * should be called anytime a driver is successfully bound to a device.
+ *
+ * Note, there is a race condition in multi-threaded probe. In the case where
+ * more than one device is probing at the same time, it is possible for one
+ * probe to complete successfully while another is about to defer. If the second
+ * depends on the first, then it will get put on the pending list after the
+ * trigger event has already occured and will be stuck there.
+ *
+ * The atomic 'deferred_trigger_count' is used to determine if a successful
+ * trigger has occurred in the midst of probing a driver. If the trigger count
+ * changes in the midst of a probe, then deferred processing should be triggered
+ * again.
  */
 static void driver_deferred_probe_trigger(void)
 {
@@ -147,6 +159,7 @@ static void driver_deferred_probe_trigger(void)
         * into the active list so they can be retried by the workqueue
         */
        mutex_lock(&deferred_probe_mutex);
+       atomic_inc(&deferred_trigger_count);
        list_splice_tail_init(&deferred_probe_pending_list,
                              &deferred_probe_active_list);
        mutex_unlock(&deferred_probe_mutex);
@@ -265,6 +278,7 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
 static int really_probe(struct device *dev, struct device_driver *drv)
 {
        int ret = 0;
+       int local_trigger_count = atomic_read(&deferred_trigger_count);
 
        atomic_inc(&probe_count);
        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
@@ -310,6 +324,9 @@ probe_failed:
                /* Driver requested deferred probing */
                dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
                driver_deferred_probe_add(dev);
+               /* Did a trigger occur while probing? Need to re-trigger if yes */
+               if (local_trigger_count != atomic_read(&deferred_trigger_count))
+                       driver_deferred_probe_trigger();
        } else if (ret != -ENODEV && ret != -ENXIO) {
                /* driver matched but the probe failed */
                printk(KERN_WARNING
index e714709704e4578ccc3703ca30108e596461ad28..5b47210889e038d72f7a172062b3c4ddd2daa07d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
@@ -87,7 +88,11 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
                return -ENXIO;
        return dev->archdata.irqs[num];
 #else
-       struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
+       struct resource *r;
+       if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node)
+               return of_irq_get(dev->dev.of_node, num);
+
+       r = platform_get_resource(dev, IORESOURCE_IRQ, num);
 
        return r ? r->start : -ENXIO;
 #endif
index 748dea4f34dc1e18b089557478a2b00221bd83c5..758da2287d9a3d01143c1d588c6f28dbbf0d8c14 100644 (file)
@@ -1406,7 +1406,7 @@ next_segment:
 
                track = block / (floppy->dtype->sects * floppy->type->sect_mult);
                sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
-               data = rq->buffer + 512 * cnt;
+               data = bio_data(rq->bio) + 512 * cnt;
 #ifdef DEBUG
                printk("access to track %d, sector %d, with buffer at "
                       "0x%08lx\n", track, sector, data);
index 96b629e1f0c9b0d887187b9a529ecee2c19d9945..7e8a55f8917cb9bbe3c84aabc3a4eb1da9d627fe 100644 (file)
@@ -1484,7 +1484,7 @@ repeat:
        ReqCnt = 0;
        ReqCmd = rq_data_dir(fd_request);
        ReqBlock = blk_rq_pos(fd_request);
-       ReqBuffer = fd_request->buffer;
+       ReqBuffer = bio_data(fd_request->bio);
        setup_req_params( drive );
        do_fd_action( drive );
 
index 73894ca3395662c80178a110ca53823454f857f4..4595c22f33f71e5b8305bb649b0df461658bb98f 100644 (file)
@@ -4080,7 +4080,7 @@ static void cciss_interrupt_mode(ctlr_info_t *h)
                goto default_int_mode;
 
        if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
-               err = pci_enable_msix(h->pdev, cciss_msix_entries, 4);
+               err = pci_enable_msix_exact(h->pdev, cciss_msix_entries, 4);
                if (!err) {
                        h->intr[0] = cciss_msix_entries[0].vector;
                        h->intr[1] = cciss_msix_entries[1].vector;
@@ -4088,10 +4088,6 @@ static void cciss_interrupt_mode(ctlr_info_t *h)
                        h->intr[3] = cciss_msix_entries[3].vector;
                        h->msix_vector = 1;
                        return;
-               }
-               if (err > 0) {
-                       dev_warn(&h->pdev->dev,
-                               "only %d MSI-X vectors available\n", err);
                } else {
                        dev_warn(&h->pdev->dev,
                                "MSI-X init failed %d\n", err);
index 90ae4ba8f9ee8898c34d9994c34cb0e860e91327..05a1780ffa850483cdf4d73a89b3a9a78964ed4c 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/drbd_limits.h>
 #include <linux/dynamic_debug.h>
 #include "drbd_int.h"
-#include "drbd_wrappers.h"
 
 
 enum al_transaction_types {
@@ -204,7 +203,7 @@ int drbd_md_sync_page_io(struct drbd_device *device, struct drbd_backing_dev *bd
 
        BUG_ON(!bdev->md_bdev);
 
-       drbd_dbg(device, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n",
+       dynamic_drbd_dbg(device, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n",
             current->comm, current->pid, __func__,
             (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ",
             (void*)_RET_IP_ );
@@ -276,7 +275,6 @@ bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval
        return _al_get(device, first, true);
 }
 
-static
 bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i)
 {
        /* for bios crossing activity log extent boundaries,
@@ -846,7 +844,7 @@ void __drbd_set_in_sync(struct drbd_device *device, sector_t sector, int size,
        int wake_up = 0;
        unsigned long flags;
 
-       if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
+       if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_DISCARD_SIZE) {
                drbd_err(device, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
                                (unsigned long long)sector, size);
                return;
@@ -920,7 +918,7 @@ int __drbd_set_out_of_sync(struct drbd_device *device, sector_t sector, int size
        if (size == 0)
                return 0;
 
-       if (size < 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
+       if (size < 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_DISCARD_SIZE) {
                drbd_err(device, "sector: %llus, size: %d\n",
                        (unsigned long long)sector, size);
                return 0;
@@ -1023,8 +1021,7 @@ int drbd_rs_begin_io(struct drbd_device *device, sector_t sector)
        unsigned int enr = BM_SECT_TO_EXT(sector);
        struct bm_extent *bm_ext;
        int i, sig;
-       int sa = 200; /* Step aside 200 times, then grab the extent and let app-IO wait.
-                        200 times -> 20 seconds. */
+       bool sa;
 
 retry:
        sig = wait_event_interruptible(device->al_wait,
@@ -1035,12 +1032,15 @@ retry:
        if (test_bit(BME_LOCKED, &bm_ext->flags))
                return 0;
 
+       /* step aside only while we are above c-min-rate; unless disabled. */
+       sa = drbd_rs_c_min_rate_throttle(device);
+
        for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
                sig = wait_event_interruptible(device->al_wait,
                                               !_is_in_al(device, enr * AL_EXT_PER_BM_SECT + i) ||
-                                              test_bit(BME_PRIORITY, &bm_ext->flags));
+                                              (sa && test_bit(BME_PRIORITY, &bm_ext->flags)));
 
-               if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) {
+               if (sig || (sa && test_bit(BME_PRIORITY, &bm_ext->flags))) {
                        spin_lock_irq(&device->al_lock);
                        if (lc_put(device->resync, &bm_ext->lce) == 0) {
                                bm_ext->flags = 0; /* clears BME_NO_WRITES and eventually BME_PRIORITY */
@@ -1052,9 +1052,6 @@ retry:
                                return -EINTR;
                        if (schedule_timeout_interruptible(HZ/10))
                                return -EINTR;
-                       if (sa && --sa == 0)
-                               drbd_warn(device, "drbd_rs_begin_io() stepped aside for 20sec."
-                                        "Resync stalled?\n");
                        goto retry;
                }
        }
@@ -1288,7 +1285,7 @@ void drbd_rs_failed_io(struct drbd_device *device, sector_t sector, int size)
        sector_t esector, nr_sectors;
        int wake_up = 0;
 
-       if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
+       if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_DISCARD_SIZE) {
                drbd_err(device, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
                                (unsigned long long)sector, size);
                return;
index e7093d4291f1a850326ab2f17d6cb52ff15d0250..a76ceb344d64e9411bbfd39c4db9189e519fac72 100644 (file)
@@ -382,6 +382,12 @@ enum {
        __EE_CALL_AL_COMPLETE_IO,
        __EE_MAY_SET_IN_SYNC,
 
+       /* is this a TRIM aka REQ_DISCARD? */
+       __EE_IS_TRIM,
+       /* our lower level cannot handle trim,
+        * and we want to fall back to zeroout instead */
+       __EE_IS_TRIM_USE_ZEROOUT,
+
        /* In case a barrier failed,
         * we need to resubmit without the barrier flag. */
        __EE_RESUBMITTED,
@@ -405,7 +411,9 @@ enum {
 };
 #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
 #define EE_MAY_SET_IN_SYNC     (1<<__EE_MAY_SET_IN_SYNC)
-#define        EE_RESUBMITTED         (1<<__EE_RESUBMITTED)
+#define EE_IS_TRIM             (1<<__EE_IS_TRIM)
+#define EE_IS_TRIM_USE_ZEROOUT (1<<__EE_IS_TRIM_USE_ZEROOUT)
+#define EE_RESUBMITTED         (1<<__EE_RESUBMITTED)
 #define EE_WAS_ERROR           (1<<__EE_WAS_ERROR)
 #define EE_HAS_DIGEST          (1<<__EE_HAS_DIGEST)
 #define EE_RESTART_REQUESTS    (1<<__EE_RESTART_REQUESTS)
@@ -579,6 +587,7 @@ struct drbd_resource {
        struct list_head resources;
        struct res_opts res_opts;
        struct mutex conf_update;       /* mutex for ready-copy-update of net_conf and disk_conf */
+       struct mutex adm_mutex;         /* mutex to serialize administrative requests */
        spinlock_t req_lock;
 
        unsigned susp:1;                /* IO suspended by user */
@@ -609,6 +618,7 @@ struct drbd_connection {
        struct drbd_socket data;        /* data/barrier/cstate/parameter packets */
        struct drbd_socket meta;        /* ping/ack (metadata) packets */
        int agreed_pro_version;         /* actually used protocol version */
+       u32 agreed_features;
        unsigned long last_received;    /* in jiffies, either socket */
        unsigned int ko_count;
 
@@ -814,6 +824,28 @@ struct drbd_device {
        struct submit_worker submit;
 };
 
+struct drbd_config_context {
+       /* assigned from drbd_genlmsghdr */
+       unsigned int minor;
+       /* assigned from request attributes, if present */
+       unsigned int volume;
+#define VOLUME_UNSPECIFIED             (-1U)
+       /* pointer into the request skb,
+        * limited lifetime! */
+       char *resource_name;
+       struct nlattr *my_addr;
+       struct nlattr *peer_addr;
+
+       /* reply buffer */
+       struct sk_buff *reply_skb;
+       /* pointer into reply buffer */
+       struct drbd_genlmsghdr *reply_dh;
+       /* resolved from attributes, if possible */
+       struct drbd_device *device;
+       struct drbd_resource *resource;
+       struct drbd_connection *connection;
+};
+
 static inline struct drbd_device *minor_to_device(unsigned int minor)
 {
        return (struct drbd_device *)idr_find(&drbd_devices, minor);
@@ -821,7 +853,7 @@ static inline struct drbd_device *minor_to_device(unsigned int minor)
 
 static inline struct drbd_peer_device *first_peer_device(struct drbd_device *device)
 {
-       return list_first_entry(&device->peer_devices, struct drbd_peer_device, peer_devices);
+       return list_first_entry_or_null(&device->peer_devices, struct drbd_peer_device, peer_devices);
 }
 
 #define for_each_resource(resource, _resources) \
@@ -1139,6 +1171,12 @@ struct bm_extent {
 #define DRBD_MAX_SIZE_H80_PACKET (1U << 15) /* Header 80 only allows packets up to 32KiB data */
 #define DRBD_MAX_BIO_SIZE_P95    (1U << 17) /* Protocol 95 to 99 allows bios up to 128KiB */
 
+/* For now, don't allow more than one activity log extent worth of data
+ * to be discarded in one go. We may need to rework drbd_al_begin_io()
+ * to allow for even larger discard ranges */
+#define DRBD_MAX_DISCARD_SIZE  AL_EXTENT_SIZE
+#define DRBD_MAX_DISCARD_SECTORS (DRBD_MAX_DISCARD_SIZE >> 9)
+
 extern int  drbd_bm_init(struct drbd_device *device);
 extern int  drbd_bm_resize(struct drbd_device *device, sector_t sectors, int set_new_bits);
 extern void drbd_bm_cleanup(struct drbd_device *device);
@@ -1229,9 +1267,9 @@ extern struct bio *bio_alloc_drbd(gfp_t gfp_mask);
 extern rwlock_t global_state_lock;
 
 extern int conn_lowest_minor(struct drbd_connection *connection);
-enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr);
+extern enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor);
 extern void drbd_destroy_device(struct kref *kref);
-extern void drbd_delete_device(struct drbd_device *mdev);
+extern void drbd_delete_device(struct drbd_device *device);
 
 extern struct drbd_resource *drbd_create_resource(const char *name);
 extern void drbd_free_resource(struct drbd_resource *resource);
@@ -1257,7 +1295,7 @@ extern int is_valid_ar_handle(struct drbd_request *, sector_t);
 
 
 /* drbd_nl.c */
-extern int drbd_msg_put_info(const char *info);
+extern int drbd_msg_put_info(struct sk_buff *skb, const char *info);
 extern void drbd_suspend_io(struct drbd_device *device);
 extern void drbd_resume_io(struct drbd_device *device);
 extern char *ppsize(char *buf, unsigned long long size);
@@ -1283,6 +1321,10 @@ extern void conn_try_outdate_peer_async(struct drbd_connection *connection);
 extern int drbd_khelper(struct drbd_device *device, char *cmd);
 
 /* drbd_worker.c */
+/* bi_end_io handlers */
+extern void drbd_md_io_complete(struct bio *bio, int error);
+extern void drbd_peer_request_endio(struct bio *bio, int error);
+extern void drbd_request_endio(struct bio *bio, int error);
 extern int drbd_worker(struct drbd_thread *thi);
 enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor);
 void drbd_resync_after_changed(struct drbd_device *device);
@@ -1332,16 +1374,20 @@ extern int w_start_resync(struct drbd_work *, int);
 extern void resync_timer_fn(unsigned long data);
 extern void start_resync_timer_fn(unsigned long data);
 
+extern void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req);
+
 /* drbd_receiver.c */
 extern int drbd_receiver(struct drbd_thread *thi);
 extern int drbd_asender(struct drbd_thread *thi);
-extern int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector);
+extern bool drbd_rs_c_min_rate_throttle(struct drbd_device *device);
+extern bool drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector);
 extern int drbd_submit_peer_request(struct drbd_device *,
                                    struct drbd_peer_request *, const unsigned,
                                    const int);
 extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *);
 extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64,
                                                     sector_t, unsigned int,
+                                                    bool,
                                                     gfp_t) __must_hold(local);
 extern void __drbd_free_peer_req(struct drbd_device *, struct drbd_peer_request *,
                                 int);
@@ -1401,6 +1447,37 @@ static inline void drbd_tcp_quickack(struct socket *sock)
                        (char*)&val, sizeof(val));
 }
 
+/* sets the number of 512 byte sectors of our virtual device */
+static inline void drbd_set_my_capacity(struct drbd_device *device,
+                                       sector_t size)
+{
+       /* set_capacity(device->this_bdev->bd_disk, size); */
+       set_capacity(device->vdisk, size);
+       device->this_bdev->bd_inode->i_size = (loff_t)size << 9;
+}
+
+/*
+ * used to submit our private bio
+ */
+static inline void drbd_generic_make_request(struct drbd_device *device,
+                                            int fault_type, struct bio *bio)
+{
+       __release(local);
+       if (!bio->bi_bdev) {
+               printk(KERN_ERR "drbd%d: drbd_generic_make_request: "
+                               "bio->bi_bdev == NULL\n",
+                      device_to_minor(device));
+               dump_stack();
+               bio_endio(bio, -ENODEV);
+               return;
+       }
+
+       if (drbd_insert_fault(device, fault_type))
+               bio_endio(bio, -EIO);
+       else
+               generic_make_request(bio);
+}
+
 void drbd_bump_write_ordering(struct drbd_connection *connection, enum write_ordering_e wo);
 
 /* drbd_proc.c */
@@ -1410,6 +1487,7 @@ extern const char *drbd_conn_str(enum drbd_conns s);
 extern const char *drbd_role_str(enum drbd_role s);
 
 /* drbd_actlog.c */
+extern bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i);
 extern int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i);
 extern void drbd_al_begin_io_commit(struct drbd_device *device, bool delegate);
 extern bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval *i);
@@ -2144,7 +2222,7 @@ static inline void drbd_md_flush(struct drbd_device *device)
 
 static inline struct drbd_connection *first_connection(struct drbd_resource *resource)
 {
-       return list_first_entry(&resource->connections,
+       return list_first_entry_or_null(&resource->connections,
                                struct drbd_connection, connections);
 }
 
index 331e5cc1227ddfed1d7d78467de86d186f6d4f45..960645c26e6fc1b107e0db1ae016fd15800d3514 100644 (file)
@@ -1607,8 +1607,8 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection, unsigned long b
                return bi_rw & REQ_SYNC ? DP_RW_SYNC : 0;
 }
 
-/* Used to send write requests
- * R_PRIMARY -> Peer   (P_DATA)
+/* Used to send write or TRIM aka REQ_DISCARD requests
+ * R_PRIMARY -> Peer   (P_DATA, P_TRIM)
  */
 int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req)
 {
@@ -1640,6 +1640,16 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *
                        dp_flags |= DP_SEND_WRITE_ACK;
        }
        p->dp_flags = cpu_to_be32(dp_flags);
+
+       if (dp_flags & DP_DISCARD) {
+               struct p_trim *t = (struct p_trim*)p;
+               t->size = cpu_to_be32(req->i.size);
+               err = __send_command(peer_device->connection, device->vnr, sock, P_TRIM, sizeof(*t), NULL, 0);
+               goto out;
+       }
+
+       /* our digest is still only over the payload.
+        * TRIM does not carry any payload. */
        if (dgs)
                drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, p + 1);
        err = __send_command(peer_device->connection, device->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
@@ -1675,6 +1685,7 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *
                     ... Be noisy about digest too large ...
                } */
        }
+out:
        mutex_unlock(&sock->mutex);  /* locked by drbd_prepare_command() */
 
        return err;
@@ -2570,6 +2581,7 @@ struct drbd_resource *drbd_create_resource(const char *name)
        INIT_LIST_HEAD(&resource->connections);
        list_add_tail_rcu(&resource->resources, &drbd_resources);
        mutex_init(&resource->conf_update);
+       mutex_init(&resource->adm_mutex);
        spin_lock_init(&resource->req_lock);
        return resource;
 
@@ -2687,14 +2699,16 @@ static int init_submitter(struct drbd_device *device)
        return 0;
 }
 
-enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
+enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor)
 {
+       struct drbd_resource *resource = adm_ctx->resource;
        struct drbd_connection *connection;
        struct drbd_device *device;
        struct drbd_peer_device *peer_device, *tmp_peer_device;
        struct gendisk *disk;
        struct request_queue *q;
        int id;
+       int vnr = adm_ctx->volume;
        enum drbd_ret_code err = ERR_NOMEM;
 
        device = minor_to_device(minor);
@@ -2763,7 +2777,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
        if (id < 0) {
                if (id == -ENOSPC) {
                        err = ERR_MINOR_EXISTS;
-                       drbd_msg_put_info("requested minor exists already");
+                       drbd_msg_put_info(adm_ctx->reply_skb, "requested minor exists already");
                }
                goto out_no_minor_idr;
        }
@@ -2773,7 +2787,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
        if (id < 0) {
                if (id == -ENOSPC) {
                        err = ERR_MINOR_EXISTS;
-                       drbd_msg_put_info("requested minor exists already");
+                       drbd_msg_put_info(adm_ctx->reply_skb, "requested minor exists already");
                }
                goto out_idr_remove_minor;
        }
@@ -2794,7 +2808,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
                if (id < 0) {
                        if (id == -ENOSPC) {
                                err = ERR_INVALID_REQUEST;
-                               drbd_msg_put_info("requested volume exists already");
+                               drbd_msg_put_info(adm_ctx->reply_skb, "requested volume exists already");
                        }
                        goto out_idr_remove_from_resource;
                }
@@ -2803,7 +2817,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
 
        if (init_submitter(device)) {
                err = ERR_NOMEM;
-               drbd_msg_put_info("unable to create submit workqueue");
+               drbd_msg_put_info(adm_ctx->reply_skb, "unable to create submit workqueue");
                goto out_idr_remove_vol;
        }
 
index 526414bc2cab18db5fb290189cccfa8951af4050..1b35c45c92b75d7f01fd3fcda7a861ae099b4c7e 100644 (file)
@@ -34,7 +34,6 @@
 #include "drbd_int.h"
 #include "drbd_protocol.h"
 #include "drbd_req.h"
-#include "drbd_wrappers.h"
 #include <asm/unaligned.h>
 #include <linux/drbd_limits.h>
 #include <linux/kthread.h>
@@ -82,32 +81,6 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb);
 /* used blkdev_get_by_path, to claim our meta data device(s) */
 static char *drbd_m_holder = "Hands off! this is DRBD's meta data device.";
 
-/* Configuration is strictly serialized, because generic netlink message
- * processing is strictly serialized by the genl_lock().
- * Which means we can use one static global drbd_config_context struct.
- */
-static struct drbd_config_context {
-       /* assigned from drbd_genlmsghdr */
-       unsigned int minor;
-       /* assigned from request attributes, if present */
-       unsigned int volume;
-#define VOLUME_UNSPECIFIED             (-1U)
-       /* pointer into the request skb,
-        * limited lifetime! */
-       char *resource_name;
-       struct nlattr *my_addr;
-       struct nlattr *peer_addr;
-
-       /* reply buffer */
-       struct sk_buff *reply_skb;
-       /* pointer into reply buffer */
-       struct drbd_genlmsghdr *reply_dh;
-       /* resolved from attributes, if possible */
-       struct drbd_device *device;
-       struct drbd_resource *resource;
-       struct drbd_connection *connection;
-} adm_ctx;
-
 static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
 {
        genlmsg_end(skb, genlmsg_data(nlmsg_data(nlmsg_hdr(skb))));
@@ -117,9 +90,8 @@ static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
 
 /* Used on a fresh "drbd_adm_prepare"d reply_skb, this cannot fail: The only
  * reason it could fail was no space in skb, and there are 4k available. */
-int drbd_msg_put_info(const char *info)
+int drbd_msg_put_info(struct sk_buff *skb, const char *info)
 {
-       struct sk_buff *skb = adm_ctx.reply_skb;
        struct nlattr *nla;
        int err = -EMSGSIZE;
 
@@ -143,42 +115,46 @@ int drbd_msg_put_info(const char *info)
  * and per-family private info->pointers.
  * But we need to stay compatible with older kernels.
  * If it returns successfully, adm_ctx members are valid.
+ *
+ * At this point, we still rely on the global genl_lock().
+ * If we want to avoid that, and allow "genl_family.parallel_ops", we may need
+ * to add additional synchronization against object destruction/modification.
  */
 #define DRBD_ADM_NEED_MINOR    1
 #define DRBD_ADM_NEED_RESOURCE 2
 #define DRBD_ADM_NEED_CONNECTION 4
-static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
-               unsigned flags)
+static int drbd_adm_prepare(struct drbd_config_context *adm_ctx,
+       struct sk_buff *skb, struct genl_info *info, unsigned flags)
 {
        struct drbd_genlmsghdr *d_in = info->userhdr;
        const u8 cmd = info->genlhdr->cmd;
        int err;
 
-       memset(&adm_ctx, 0, sizeof(adm_ctx));
+       memset(adm_ctx, 0, sizeof(*adm_ctx));
 
        /* genl_rcv_msg only checks for CAP_NET_ADMIN on "GENL_ADMIN_PERM" :( */
        if (cmd != DRBD_ADM_GET_STATUS && !capable(CAP_NET_ADMIN))
               return -EPERM;
 
-       adm_ctx.reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-       if (!adm_ctx.reply_skb) {
+       adm_ctx->reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!adm_ctx->reply_skb) {
                err = -ENOMEM;
                goto fail;
        }
 
-       adm_ctx.reply_dh = genlmsg_put_reply(adm_ctx.reply_skb,
+       adm_ctx->reply_dh = genlmsg_put_reply(adm_ctx->reply_skb,
                                        info, &drbd_genl_family, 0, cmd);
        /* put of a few bytes into a fresh skb of >= 4k will always succeed.
         * but anyways */
-       if (!adm_ctx.reply_dh) {
+       if (!adm_ctx->reply_dh) {
                err = -ENOMEM;
                goto fail;
        }
 
-       adm_ctx.reply_dh->minor = d_in->minor;
-       adm_ctx.reply_dh->ret_code = NO_ERROR;
+       adm_ctx->reply_dh->minor = d_in->minor;
+       adm_ctx->reply_dh->ret_code = NO_ERROR;
 
-       adm_ctx.volume = VOLUME_UNSPECIFIED;
+       adm_ctx->volume = VOLUME_UNSPECIFIED;
        if (info->attrs[DRBD_NLA_CFG_CONTEXT]) {
                struct nlattr *nla;
                /* parse and validate only */
@@ -188,111 +164,131 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
 
                /* It was present, and valid,
                 * copy it over to the reply skb. */
-               err = nla_put_nohdr(adm_ctx.reply_skb,
+               err = nla_put_nohdr(adm_ctx->reply_skb,
                                info->attrs[DRBD_NLA_CFG_CONTEXT]->nla_len,
                                info->attrs[DRBD_NLA_CFG_CONTEXT]);
                if (err)
                        goto fail;
 
-               /* and assign stuff to the global adm_ctx */
+               /* and assign stuff to the adm_ctx */
                nla = nested_attr_tb[__nla_type(T_ctx_volume)];
                if (nla)
-                       adm_ctx.volume = nla_get_u32(nla);
+                       adm_ctx->volume = nla_get_u32(nla);
                nla = nested_attr_tb[__nla_type(T_ctx_resource_name)];
                if (nla)
-                       adm_ctx.resource_name = nla_data(nla);
-               adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
-               adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
-               if ((adm_ctx.my_addr &&
-                    nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.connection->my_addr)) ||
-                   (adm_ctx.peer_addr &&
-                    nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.connection->peer_addr))) {
+                       adm_ctx->resource_name = nla_data(nla);
+               adm_ctx->my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
+               adm_ctx->peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
+               if ((adm_ctx->my_addr &&
+                    nla_len(adm_ctx->my_addr) > sizeof(adm_ctx->connection->my_addr)) ||
+                   (adm_ctx->peer_addr &&
+                    nla_len(adm_ctx->peer_addr) > sizeof(adm_ctx->connection->peer_addr))) {
                        err = -EINVAL;
                        goto fail;
                }
        }
 
-       adm_ctx.minor = d_in->minor;
-       adm_ctx.device = minor_to_device(d_in->minor);
-       if (adm_ctx.resource_name) {
-               adm_ctx.resource = drbd_find_resource(adm_ctx.resource_name);
+       adm_ctx->minor = d_in->minor;
+       adm_ctx->device = minor_to_device(d_in->minor);
+
+       /* We are protected by the global genl_lock().
+        * But we may explicitly drop it/retake it in drbd_adm_set_role(),
+        * so make sure this object stays around. */
+       if (adm_ctx->device)
+               kref_get(&adm_ctx->device->kref);
+
+       if (adm_ctx->resource_name) {
+               adm_ctx->resource = drbd_find_resource(adm_ctx->resource_name);
        }
 
-       if (!adm_ctx.device && (flags & DRBD_ADM_NEED_MINOR)) {
-               drbd_msg_put_info("unknown minor");
+       if (!adm_ctx->device && (flags & DRBD_ADM_NEED_MINOR)) {
+               drbd_msg_put_info(adm_ctx->reply_skb, "unknown minor");
                return ERR_MINOR_INVALID;
        }
-       if (!adm_ctx.resource && (flags & DRBD_ADM_NEED_RESOURCE)) {
-               drbd_msg_put_info("unknown resource");
-               if (adm_ctx.resource_name)
+       if (!adm_ctx->resource && (flags & DRBD_ADM_NEED_RESOURCE)) {
+               drbd_msg_put_info(adm_ctx->reply_skb, "unknown resource");
+               if (adm_ctx->resource_name)
                        return ERR_RES_NOT_KNOWN;
                return ERR_INVALID_REQUEST;
        }
 
        if (flags & DRBD_ADM_NEED_CONNECTION) {
-               if (adm_ctx.resource) {
-                       drbd_msg_put_info("no resource name expected");
+               if (adm_ctx->resource) {
+                       drbd_msg_put_info(adm_ctx->reply_skb, "no resource name expected");
                        return ERR_INVALID_REQUEST;
                }
-               if (adm_ctx.device) {
-                       drbd_msg_put_info("no minor number expected");
+               if (adm_ctx->device) {
+                       drbd_msg_put_info(adm_ctx->reply_skb, "no minor number expected");
                        return ERR_INVALID_REQUEST;
                }
-               if (adm_ctx.my_addr && adm_ctx.peer_addr)
-                       adm_ctx.connection = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
-                                                         nla_len(adm_ctx.my_addr),
-                                                         nla_data(adm_ctx.peer_addr),
-                                                         nla_len(adm_ctx.peer_addr));
-               if (!adm_ctx.connection) {
-                       drbd_msg_put_info("unknown connection");
+               if (adm_ctx->my_addr && adm_ctx->peer_addr)
+                       adm_ctx->connection = conn_get_by_addrs(nla_data(adm_ctx->my_addr),
+                                                         nla_len(adm_ctx->my_addr),
+                                                         nla_data(adm_ctx->peer_addr),
+                                                         nla_len(adm_ctx->peer_addr));
+               if (!adm_ctx->connection) {
+                       drbd_msg_put_info(adm_ctx->reply_skb, "unknown connection");
                        return ERR_INVALID_REQUEST;
                }
        }
 
        /* some more paranoia, if the request was over-determined */
-       if (adm_ctx.device && adm_ctx.resource &&
-           adm_ctx.device->resource != adm_ctx.resource) {
+       if (adm_ctx->device && adm_ctx->resource &&
+           adm_ctx->device->resource != adm_ctx->resource) {
                pr_warning("request: minor=%u, resource=%s; but that minor belongs to resource %s\n",
-                               adm_ctx.minor, adm_ctx.resource->name,
-                               adm_ctx.device->resource->name);
-               drbd_msg_put_info("minor exists in different resource");
+                               adm_ctx->minor, adm_ctx->resource->name,
+                               adm_ctx->device->resource->name);
+               drbd_msg_put_info(adm_ctx->reply_skb, "minor exists in different resource");
                return ERR_INVALID_REQUEST;
        }
-       if (adm_ctx.device &&
-           adm_ctx.volume != VOLUME_UNSPECIFIED &&
-           adm_ctx.volume != adm_ctx.device->vnr) {
+       if (adm_ctx->device &&
+           adm_ctx->volume != VOLUME_UNSPECIFIED &&
+           adm_ctx->volume != adm_ctx->device->vnr) {
                pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n",
-                               adm_ctx.minor, adm_ctx.volume,
-                               adm_ctx.device->vnr,
-                               adm_ctx.device->resource->name);
-               drbd_msg_put_info("minor exists as different volume");
+                               adm_ctx->minor, adm_ctx->volume,
+                               adm_ctx->device->vnr,
+                               adm_ctx->device->resource->name);
+               drbd_msg_put_info(adm_ctx->reply_skb, "minor exists as different volume");
                return ERR_INVALID_REQUEST;
        }
 
+       /* still, provide adm_ctx->resource always, if possible. */
+       if (!adm_ctx->resource) {
+               adm_ctx->resource = adm_ctx->device ? adm_ctx->device->resource
+                       : adm_ctx->connection ? adm_ctx->connection->resource : NULL;
+               if (adm_ctx->resource)
+                       kref_get(&adm_ctx->resource->kref);
+       }
+
        return NO_ERROR;
 
 fail:
-       nlmsg_free(adm_ctx.reply_skb);
-       adm_ctx.reply_skb = NULL;
+       nlmsg_free(adm_ctx->reply_skb);
+       adm_ctx->reply_skb = NULL;
        return err;
 }
 
-static int drbd_adm_finish(struct genl_info *info, int retcode)
+static int drbd_adm_finish(struct drbd_config_context *adm_ctx,
+       struct genl_info *info, int retcode)
 {
-       if (adm_ctx.connection) {
-               kref_put(&adm_ctx.connection->kref, drbd_destroy_connection);
-               adm_ctx.connection = NULL;
+       if (adm_ctx->device) {
+               kref_put(&adm_ctx->device->kref, drbd_destroy_device);
+               adm_ctx->device = NULL;
        }
-       if (adm_ctx.resource) {
-               kref_put(&adm_ctx.resource->kref, drbd_destroy_resource);
-               adm_ctx.resource = NULL;
+       if (adm_ctx->connection) {
+               kref_put(&adm_ctx->connection->kref, &drbd_destroy_connection);
+               adm_ctx->connection = NULL;
+       }
+       if (adm_ctx->resource) {
+               kref_put(&adm_ctx->resource->kref, drbd_destroy_resource);
+               adm_ctx->resource = NULL;
        }
 
-       if (!adm_ctx.reply_skb)
+       if (!adm_ctx->reply_skb)
                return -ENOMEM;
 
-       adm_ctx.reply_dh->ret_code = retcode;
-       drbd_adm_send_reply(adm_ctx.reply_skb, info);
+       adm_ctx->reply_dh->ret_code = retcode;
+       drbd_adm_send_reply(adm_ctx->reply_skb, info);
        return 0;
 }
 
@@ -426,6 +422,14 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connec
        }
        rcu_read_unlock();
 
+       if (fp == FP_NOT_AVAIL) {
+               /* IO Suspending works on the whole resource.
+                  Do it only for one device. */
+               vnr = 0;
+               peer_device = idr_get_next(&connection->peer_devices, &vnr);
+               drbd_change_state(peer_device->device, CS_VERBOSE | CS_HARD, NS(susp_fen, 0));
+       }
+
        return fp;
 }
 
@@ -438,12 +442,13 @@ bool conn_try_outdate_peer(struct drbd_connection *connection)
        char *ex_to_string;
        int r;
 
+       spin_lock_irq(&connection->resource->req_lock);
        if (connection->cstate >= C_WF_REPORT_PARAMS) {
                drbd_err(connection, "Expected cstate < C_WF_REPORT_PARAMS\n");
+               spin_unlock_irq(&connection->resource->req_lock);
                return false;
        }
 
-       spin_lock_irq(&connection->resource->req_lock);
        connect_cnt = connection->connect_cnt;
        spin_unlock_irq(&connection->resource->req_lock);
 
@@ -654,11 +659,11 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
                        put_ldev(device);
                }
        } else {
-               mutex_lock(&device->resource->conf_update);
+               /* Called from drbd_adm_set_role only.
+                * We are still holding the conf_update mutex. */
                nc = first_peer_device(device)->connection->net_conf;
                if (nc)
                        nc->discard_my_data = 0; /* without copy; single bit op is atomic */
-               mutex_unlock(&device->resource->conf_update);
 
                set_disk_ro(device->vdisk, false);
                if (get_ldev(device)) {
@@ -700,11 +705,12 @@ static const char *from_attrs_err_to_txt(int err)
 
 int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct set_role_parms parms;
        int err;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -715,17 +721,22 @@ int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info)
                err = set_role_parms_from_attrs(&parms, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
-                       drbd_msg_put_info(from_attrs_err_to_txt(err));
+                       drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                        goto out;
                }
        }
+       genl_unlock();
+       mutex_lock(&adm_ctx.resource->adm_mutex);
 
        if (info->genlhdr->cmd == DRBD_ADM_PRIMARY)
                retcode = drbd_set_role(adm_ctx.device, R_PRIMARY, parms.assume_uptodate);
        else
                retcode = drbd_set_role(adm_ctx.device, R_SECONDARY, 0);
+
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
+       genl_lock();
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -1104,15 +1115,18 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_
        struct request_queue * const q = device->rq_queue;
        unsigned int max_hw_sectors = max_bio_size >> 9;
        unsigned int max_segments = 0;
+       struct request_queue *b = NULL;
 
        if (get_ldev_if_state(device, D_ATTACHING)) {
-               struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
+               b = device->ldev->backing_bdev->bd_disk->queue;
 
                max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
                rcu_read_lock();
                max_segments = rcu_dereference(device->ldev->disk_conf)->max_bio_bvecs;
                rcu_read_unlock();
-               put_ldev(device);
+
+               blk_set_stacking_limits(&q->limits);
+               blk_queue_max_write_same_sectors(q, 0);
        }
 
        blk_queue_logical_block_size(q, 512);
@@ -1121,8 +1135,25 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_
        blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
        blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
 
-       if (get_ldev_if_state(device, D_ATTACHING)) {
-               struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
+       if (b) {
+               struct drbd_connection *connection = first_peer_device(device)->connection;
+
+               if (blk_queue_discard(b) &&
+                   (connection->cstate < C_CONNECTED || connection->agreed_features & FF_TRIM)) {
+                       /* For now, don't allow more than one activity log extent worth of data
+                        * to be discarded in one go. We may need to rework drbd_al_begin_io()
+                        * to allow for even larger discard ranges */
+                       q->limits.max_discard_sectors = DRBD_MAX_DISCARD_SECTORS;
+
+                       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+                       /* REALLY? Is stacking secdiscard "legal"? */
+                       if (blk_queue_secdiscard(b))
+                               queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+               } else {
+                       q->limits.max_discard_sectors = 0;
+                       queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
+                       queue_flag_clear_unlocked(QUEUE_FLAG_SECDISCARD, q);
+               }
 
                blk_queue_stack_limits(q, b);
 
@@ -1164,8 +1195,14 @@ void drbd_reconsider_max_bio_size(struct drbd_device *device)
                        peer = DRBD_MAX_BIO_SIZE_P95;  /* drbd 8.3.8 onwards, before 8.4.0 */
                else
                        peer = DRBD_MAX_BIO_SIZE;
-       }
 
+               /* We may later detach and re-attach on a disconnected Primary.
+                * Avoid this setting to jump back in that case.
+                * We want to store what we know the peer DRBD can handle,
+                * not what the peer IO backend can handle. */
+               if (peer > device->peer_max_bio_size)
+                       device->peer_max_bio_size = peer;
+       }
        new = min(local, peer);
 
        if (device->state.role == R_PRIMARY && new < now)
@@ -1258,19 +1295,21 @@ static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
 
 int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        struct drbd_device *device;
        struct disk_conf *new_disk_conf, *old_disk_conf;
        struct fifo_buffer *old_plan = NULL, *new_plan = NULL;
        int err, fifo_size;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
-               goto out;
+               goto finish;
 
        device = adm_ctx.device;
+       mutex_lock(&adm_ctx.resource->adm_mutex);
 
        /* we also need a disk
         * to change the options on */
@@ -1294,7 +1333,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
        err = disk_conf_from_attrs_for_change(new_disk_conf, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
-               drbd_msg_put_info(from_attrs_err_to_txt(err));
+               drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                goto fail_unlock;
        }
 
@@ -1385,12 +1424,15 @@ fail_unlock:
 success:
        put_ldev(device);
  out:
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
+ finish:
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_device *device;
        int err;
        enum drbd_ret_code retcode;
@@ -1406,13 +1448,14 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        enum drbd_state_rv rv;
        struct net_conf *nc;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto finish;
 
        device = adm_ctx.device;
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        conn_reconfig_start(first_peer_device(device)->connection);
 
        /* if you want to reconfigure, please tear down first */
@@ -1455,7 +1498,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        err = disk_conf_from_attrs(new_disk_conf, info);
        if (err) {
                retcode = ERR_MANDATORY_TAG;
-               drbd_msg_put_info(from_attrs_err_to_txt(err));
+               drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                goto fail;
        }
 
@@ -1619,7 +1662,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (device->state.conn < C_CONNECTED &&
-           device->state.role == R_PRIMARY &&
+           device->state.role == R_PRIMARY && device->ed_uuid &&
            (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
                drbd_err(device, "Can only attach to data with current UUID=%016llX\n",
                    (unsigned long long)device->ed_uuid);
@@ -1797,7 +1840,8 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
        put_ldev(device);
        conn_reconfig_done(first_peer_device(device)->connection);
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 
  force_diskless_dec:
@@ -1819,9 +1863,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        kfree(new_disk_conf);
        lc_destroy(resync_lru);
        kfree(new_plan);
-
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
  finish:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -1860,11 +1904,12 @@ out:
  * Only then we have finally detached. */
 int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        struct detach_parms parms = { };
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -1874,14 +1919,16 @@ int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
                err = detach_parms_from_attrs(&parms, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
-                       drbd_msg_put_info(from_attrs_err_to_txt(err));
+                       drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                        goto out;
                }
        }
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        retcode = adm_detach(adm_ctx.device, parms.force_detach);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -2055,6 +2102,7 @@ static void free_crypto(struct crypto *crypto)
 
 int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        struct drbd_connection *connection;
        struct net_conf *old_net_conf, *new_net_conf = NULL;
@@ -2063,13 +2111,14 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        int rsr; /* re-sync running */
        struct crypto crypto = { };
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_CONNECTION);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
-               goto out;
+               goto finish;
 
        connection = adm_ctx.connection;
+       mutex_lock(&adm_ctx.resource->adm_mutex);
 
        new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
        if (!new_net_conf) {
@@ -2084,7 +2133,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        old_net_conf = connection->net_conf;
 
        if (!old_net_conf) {
-               drbd_msg_put_info("net conf missing, try connect");
+               drbd_msg_put_info(adm_ctx.reply_skb, "net conf missing, try connect");
                retcode = ERR_INVALID_REQUEST;
                goto fail;
        }
@@ -2096,7 +2145,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        err = net_conf_from_attrs_for_change(new_net_conf, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
-               drbd_msg_put_info(from_attrs_err_to_txt(err));
+               drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                goto fail;
        }
 
@@ -2167,12 +2216,15 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
  done:
        conn_reconfig_done(connection);
  out:
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
+ finish:
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_peer_device *peer_device;
        struct net_conf *old_net_conf, *new_net_conf = NULL;
        struct crypto crypto = { };
@@ -2182,14 +2234,14 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
        int i;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
 
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
        if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) {
-               drbd_msg_put_info("connection endpoint(s) missing");
+               drbd_msg_put_info(adm_ctx.reply_skb, "connection endpoint(s) missing");
                retcode = ERR_INVALID_REQUEST;
                goto out;
        }
@@ -2215,6 +2267,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        connection = first_connection(adm_ctx.resource);
        conn_reconfig_start(connection);
 
@@ -2235,7 +2288,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
        err = net_conf_from_attrs(new_net_conf, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
-               drbd_msg_put_info(from_attrs_err_to_txt(err));
+               drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                goto fail;
        }
 
@@ -2284,7 +2337,8 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
        retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
 
        conn_reconfig_done(connection);
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 
 fail:
@@ -2292,8 +2346,9 @@ fail:
        kfree(new_net_conf);
 
        conn_reconfig_done(connection);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -2356,13 +2411,14 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection
 
 int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct disconnect_parms parms;
        struct drbd_connection *connection;
        enum drbd_state_rv rv;
        enum drbd_ret_code retcode;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_CONNECTION);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -2374,18 +2430,20 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
                err = disconnect_parms_from_attrs(&parms, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
-                       drbd_msg_put_info(from_attrs_err_to_txt(err));
+                       drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                        goto fail;
                }
        }
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        rv = conn_try_disconnect(connection, parms.force_disconnect);
        if (rv < SS_SUCCESS)
                retcode = rv;  /* FIXME: Type mismatch. */
        else
                retcode = NO_ERROR;
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
  fail:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -2407,6 +2465,7 @@ void resync_after_online_grow(struct drbd_device *device)
 
 int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct disk_conf *old_disk_conf, *new_disk_conf = NULL;
        struct resize_parms rs;
        struct drbd_device *device;
@@ -2417,12 +2476,13 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
        sector_t u_size;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
-               goto fail;
+               goto finish;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        device = adm_ctx.device;
        if (!get_ldev(device)) {
                retcode = ERR_NO_DISK;
@@ -2436,7 +2496,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
                err = resize_parms_from_attrs(&rs, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
-                       drbd_msg_put_info(from_attrs_err_to_txt(err));
+                       drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                        goto fail_ldev;
                }
        }
@@ -2482,7 +2542,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
                        goto fail_ldev;
                }
 
-               if (device->state.conn != C_CONNECTED) {
+               if (device->state.conn != C_CONNECTED && !rs.resize_force) {
                        retcode = ERR_MD_LAYOUT_CONNECTED;
                        goto fail_ldev;
                }
@@ -2528,7 +2588,9 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
        }
 
  fail:
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
+ finish:
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 
  fail_ldev:
@@ -2538,11 +2600,12 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
 
 int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        struct res_opts res_opts;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -2555,33 +2618,37 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
        err = res_opts_from_attrs(&res_opts, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
-               drbd_msg_put_info(from_attrs_err_to_txt(err));
+               drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                goto fail;
        }
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        err = set_resource_options(adm_ctx.resource, &res_opts);
        if (err) {
                retcode = ERR_INVALID_REQUEST;
                if (err == -ENOMEM)
                        retcode = ERR_NOMEM;
        }
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 
 fail:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_device *device;
        int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        device = adm_ctx.device;
 
        /* If there is still bitmap IO pending, probably because of a previous
@@ -2605,26 +2672,29 @@ int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
        } else
                retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_T));
        drbd_resume_io(device);
-
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *info,
                union drbd_state mask, union drbd_state val)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        retcode = drbd_request_state(adm_ctx.device, mask, val);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -2639,15 +2709,17 @@ static int drbd_bmio_set_susp_al(struct drbd_device *device)
 
 int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        int retcode; /* drbd_ret_code, drbd_state_rv */
        struct drbd_device *device;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        device = adm_ctx.device;
 
        /* If there is still bitmap IO pending, probably because of a previous
@@ -2674,40 +2746,45 @@ int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
        } else
                retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_S));
        drbd_resume_io(device);
-
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        if (drbd_request_state(adm_ctx.device, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
                retcode = ERR_PAUSE_IS_SET;
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        union drbd_dev_state s;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        if (drbd_request_state(adm_ctx.device, NS(user_isp, 0)) == SS_NOTHING_TO_DO) {
                s = adm_ctx.device->state;
                if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) {
@@ -2717,9 +2794,9 @@ int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info)
                        retcode = ERR_PAUSE_IS_CLEAR;
                }
        }
-
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -2730,15 +2807,17 @@ int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info)
 
 int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_device *device;
        int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        device = adm_ctx.device;
        if (test_bit(NEW_CUR_UUID, &device->flags)) {
                drbd_uuid_new_current(device);
@@ -2753,9 +2832,9 @@ int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
                        tl_restart(first_peer_device(device)->connection, FAIL_FROZEN_DISK_IO);
        }
        drbd_resume_io(device);
-
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -2931,10 +3010,11 @@ nla_put_failure:
 
 int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -2946,7 +3026,7 @@ int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
                return err;
        }
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -3133,11 +3213,12 @@ dump:
 
 int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        struct timeout_parms tp;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -3154,17 +3235,18 @@ int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
                return err;
        }
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_device *device;
        enum drbd_ret_code retcode;
        struct start_ov_parms parms;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -3179,10 +3261,12 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
                int err = start_ov_parms_from_attrs(&parms, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
-                       drbd_msg_put_info(from_attrs_err_to_txt(err));
+                       drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                        goto out;
                }
        }
+       mutex_lock(&adm_ctx.resource->adm_mutex);
+
        /* w_make_ov_request expects position to be aligned */
        device->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1);
        device->ov_stop_sector = parms.ov_stop_sector;
@@ -3193,21 +3277,24 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
        wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
        retcode = drbd_request_state(device, NS(conn, C_VERIFY_S));
        drbd_resume_io(device);
+
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 
 int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_device *device;
        enum drbd_ret_code retcode;
        int skip_initial_sync = 0;
        int err;
        struct new_c_uuid_parms args;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -3219,11 +3306,12 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
                err = new_c_uuid_parms_from_attrs(&args, info);
                if (err) {
                        retcode = ERR_MANDATORY_TAG;
-                       drbd_msg_put_info(from_attrs_err_to_txt(err));
+                       drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                        goto out_nolock;
                }
        }
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        mutex_lock(device->state_mutex); /* Protects us against serialized state changes. */
 
        if (!get_ldev(device)) {
@@ -3268,22 +3356,24 @@ out_dec:
        put_ldev(device);
 out:
        mutex_unlock(device->state_mutex);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out_nolock:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 static enum drbd_ret_code
-drbd_check_resource_name(const char *name)
+drbd_check_resource_name(struct drbd_config_context *adm_ctx)
 {
+       const char *name = adm_ctx->resource_name;
        if (!name || !name[0]) {
-               drbd_msg_put_info("resource name missing");
+               drbd_msg_put_info(adm_ctx->reply_skb, "resource name missing");
                return ERR_MANDATORY_TAG;
        }
        /* if we want to use these in sysfs/configfs/debugfs some day,
         * we must not allow slashes */
        if (strchr(name, '/')) {
-               drbd_msg_put_info("invalid resource name");
+               drbd_msg_put_info(adm_ctx->reply_skb, "invalid resource name");
                return ERR_INVALID_REQUEST;
        }
        return NO_ERROR;
@@ -3291,11 +3381,12 @@ drbd_check_resource_name(const char *name)
 
 int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
        struct res_opts res_opts;
        int err;
 
-       retcode = drbd_adm_prepare(skb, info, 0);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, 0);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
@@ -3305,48 +3396,50 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
        err = res_opts_from_attrs(&res_opts, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
-               drbd_msg_put_info(from_attrs_err_to_txt(err));
+               drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err));
                goto out;
        }
 
-       retcode = drbd_check_resource_name(adm_ctx.resource_name);
+       retcode = drbd_check_resource_name(&adm_ctx);
        if (retcode != NO_ERROR)
                goto out;
 
        if (adm_ctx.resource) {
                if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) {
                        retcode = ERR_INVALID_REQUEST;
-                       drbd_msg_put_info("resource exists");
+                       drbd_msg_put_info(adm_ctx.reply_skb, "resource exists");
                }
                /* else: still NO_ERROR */
                goto out;
        }
 
+       /* not yet safe for genl_family.parallel_ops */
        if (!conn_create(adm_ctx.resource_name, &res_opts))
                retcode = ERR_NOMEM;
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_genlmsghdr *dh = info->userhdr;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
        if (dh->minor > MINORMASK) {
-               drbd_msg_put_info("requested minor out of range");
+               drbd_msg_put_info(adm_ctx.reply_skb, "requested minor out of range");
                retcode = ERR_INVALID_REQUEST;
                goto out;
        }
        if (adm_ctx.volume > DRBD_VOLUME_MAX) {
-               drbd_msg_put_info("requested volume id out of range");
+               drbd_msg_put_info(adm_ctx.reply_skb, "requested volume id out of range");
                retcode = ERR_INVALID_REQUEST;
                goto out;
        }
@@ -3360,9 +3453,11 @@ int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       retcode = drbd_create_device(adm_ctx.resource, dh->minor, adm_ctx.volume);
+       mutex_lock(&adm_ctx.resource->adm_mutex);
+       retcode = drbd_create_device(&adm_ctx, dh->minor);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
@@ -3383,35 +3478,40 @@ static enum drbd_ret_code adm_del_minor(struct drbd_device *device)
 
 int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
+       mutex_lock(&adm_ctx.resource->adm_mutex);
        retcode = adm_del_minor(adm_ctx.device);
+       mutex_unlock(&adm_ctx.resource->adm_mutex);
 out:
-       drbd_adm_finish(info, retcode);
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_resource *resource;
        struct drbd_connection *connection;
        struct drbd_device *device;
        int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
        unsigned i;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
-               goto out;
+               goto finish;
 
        resource = adm_ctx.resource;
+       mutex_lock(&resource->adm_mutex);
        /* demote */
        for_each_connection(connection, resource) {
                struct drbd_peer_device *peer_device;
@@ -3419,14 +3519,14 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                idr_for_each_entry(&connection->peer_devices, peer_device, i) {
                        retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
                        if (retcode < SS_SUCCESS) {
-                               drbd_msg_put_info("failed to demote");
+                               drbd_msg_put_info(adm_ctx.reply_skb, "failed to demote");
                                goto out;
                        }
                }
 
                retcode = conn_try_disconnect(connection, 0);
                if (retcode < SS_SUCCESS) {
-                       drbd_msg_put_info("failed to disconnect");
+                       drbd_msg_put_info(adm_ctx.reply_skb, "failed to disconnect");
                        goto out;
                }
        }
@@ -3435,7 +3535,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        idr_for_each_entry(&resource->devices, device, i) {
                retcode = adm_detach(device, 0);
                if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
-                       drbd_msg_put_info("failed to detach");
+                       drbd_msg_put_info(adm_ctx.reply_skb, "failed to detach");
                        goto out;
                }
        }
@@ -3453,7 +3553,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                retcode = adm_del_minor(device);
                if (retcode != NO_ERROR) {
                        /* "can not happen" */
-                       drbd_msg_put_info("failed to delete volume");
+                       drbd_msg_put_info(adm_ctx.reply_skb, "failed to delete volume");
                        goto out;
                }
        }
@@ -3462,25 +3562,28 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        synchronize_rcu();
        drbd_free_resource(resource);
        retcode = NO_ERROR;
-
 out:
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&resource->adm_mutex);
+finish:
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
 int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_config_context adm_ctx;
        struct drbd_resource *resource;
        struct drbd_connection *connection;
        enum drbd_ret_code retcode;
 
-       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
+       retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
-               goto out;
+               goto finish;
 
        resource = adm_ctx.resource;
+       mutex_lock(&resource->adm_mutex);
        for_each_connection(connection, resource) {
                if (connection->cstate > C_STANDALONE) {
                        retcode = ERR_NET_CONFIGURED;
@@ -3499,7 +3602,9 @@ int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
        drbd_free_resource(resource);
        retcode = NO_ERROR;
 out:
-       drbd_adm_finish(info, retcode);
+       mutex_unlock(&resource->adm_mutex);
+finish:
+       drbd_adm_finish(&adm_ctx, info, retcode);
        return 0;
 }
 
index fa672b6df8d6b145e9e62ca6c803b4c40739cc52..b2d4791498a660618aa6f603db35fd0c0b5a94e7 100644 (file)
@@ -1,4 +1,3 @@
-#include "drbd_wrappers.h"
 #include <linux/kernel.h>
 #include <net/netlink.h>
 #include <linux/drbd_genl_api.h>
index 2f26e8ffa45b0fa8348dba8f1823ee4e1753c161..89736bdbbc7044aedaaacbd5dc9c858ca3933596 100644 (file)
@@ -116,7 +116,7 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se
        /* ------------------------ ~18s average ------------------------ */
        i = (device->rs_last_mark + 2) % DRBD_SYNC_MARKS;
        dt = (jiffies - device->rs_mark_time[i]) / HZ;
-       if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
+       if (dt > 180)
                stalled = 1;
 
        if (!dt)
index 3c04ec0ea3330cb56302fd3367f04e850ea2055f..2da9104a3851813010eae268fa778c82ac5b2d4c 100644 (file)
@@ -54,6 +54,11 @@ enum drbd_packet {
        P_CONN_ST_CHG_REPLY   = 0x2b, /* meta sock: Connection side state req reply */
        P_RETRY_WRITE         = 0x2c, /* Protocol C: retry conflicting write request */
        P_PROTOCOL_UPDATE     = 0x2d, /* data sock: is used in established connections */
+        /* 0x2e to 0x30 reserved, used in drbd 9 */
+
+       /* REQ_DISCARD. We used "discard" in different contexts before,
+        * which is why I chose TRIM here, to disambiguate. */
+       P_TRIM                = 0x31,
 
        P_MAY_IGNORE          = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
        P_MAX_OPT_CMD         = 0x101,
@@ -119,6 +124,11 @@ struct p_data {
        u32         dp_flags;
 } __packed;
 
+struct p_trim {
+       struct p_data p_data;
+       u32         size;       /* == bio->bi_size */
+} __packed;
+
 /*
  * commands which share a struct:
  *  p_block_ack:
@@ -150,6 +160,8 @@ struct p_block_req {
  *   ReportParams
  */
 
+#define FF_TRIM      1
+
 struct p_connection_features {
        u32 protocol_min;
        u32 feature_flags;
index 68e3992e88381cd4974ebfa2da3400708ab4afa0..b6c8aaf4931bc8434635e74efa004f9ddf8c0304 100644 (file)
 #include "drbd_int.h"
 #include "drbd_protocol.h"
 #include "drbd_req.h"
-
 #include "drbd_vli.h"
 
+#define PRO_FEATURES (FF_TRIM)
+
 struct packet_info {
        enum drbd_packet cmd;
        unsigned int size;
@@ -65,7 +66,7 @@ enum finish_epoch {
 static int drbd_do_features(struct drbd_connection *connection);
 static int drbd_do_auth(struct drbd_connection *connection);
 static int drbd_disconnected(struct drbd_peer_device *);
-
+static void conn_wait_active_ee_empty(struct drbd_connection *connection);
 static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *, struct drbd_epoch *, enum epoch_event);
 static int e_end_block(struct drbd_work *, int);
 
@@ -234,9 +235,17 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_device *device)
  * @retry:     whether to retry, if not enough pages are available right now
  *
  * Tries to allocate number pages, first from our own page pool, then from
- * the kernel, unless this allocation would exceed the max_buffers setting.
+ * the kernel.
  * Possibly retry until DRBD frees sufficient pages somewhere else.
  *
+ * If this allocation would exceed the max_buffers setting, we throttle
+ * allocation (schedule_timeout) to give the system some room to breathe.
+ *
+ * We do not use max-buffers as hard limit, because it could lead to
+ * congestion and further to a distributed deadlock during online-verify or
+ * (checksum based) resync, if the max-buffers, socket buffer sizes and
+ * resync-rate settings are mis-configured.
+ *
  * Returns a page chain linked via page->private.
  */
 struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int number,
@@ -246,10 +255,8 @@ struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int
        struct page *page = NULL;
        struct net_conf *nc;
        DEFINE_WAIT(wait);
-       int mxb;
+       unsigned int mxb;
 
-       /* Yes, we may run up to @number over max_buffers. If we
-        * follow it strictly, the admin will get it wrong anyways. */
        rcu_read_lock();
        nc = rcu_dereference(peer_device->connection->net_conf);
        mxb = nc ? nc->max_buffers : 1000000;
@@ -277,7 +284,8 @@ struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int
                        break;
                }
 
-               schedule();
+               if (schedule_timeout(HZ/10) == 0)
+                       mxb = UINT_MAX;
        }
        finish_wait(&drbd_pp_wait, &wait);
 
@@ -331,7 +339,7 @@ You must not have the req_lock:
 
 struct drbd_peer_request *
 drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
-                   unsigned int data_size, gfp_t gfp_mask) __must_hold(local)
+                   unsigned int data_size, bool has_payload, gfp_t gfp_mask) __must_hold(local)
 {
        struct drbd_device *device = peer_device->device;
        struct drbd_peer_request *peer_req;
@@ -348,7 +356,7 @@ drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t secto
                return NULL;
        }
 
-       if (data_size) {
+       if (has_payload && data_size) {
                page = drbd_alloc_pages(peer_device, nr_pages, (gfp_mask & __GFP_WAIT));
                if (!page)
                        goto fail;
@@ -1026,24 +1034,27 @@ randomize:
        if (drbd_send_protocol(connection) == -EOPNOTSUPP)
                return -1;
 
+       /* Prevent a race between resync-handshake and
+        * being promoted to Primary.
+        *
+        * Grab and release the state mutex, so we know that any current
+        * drbd_set_role() is finished, and any incoming drbd_set_role
+        * will see the STATE_SENT flag, and wait for it to be cleared.
+        */
+       idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+               mutex_lock(peer_device->device->state_mutex);
+
        set_bit(STATE_SENT, &connection->flags);
 
+       idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+               mutex_unlock(peer_device->device->state_mutex);
+
        rcu_read_lock();
        idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
                struct drbd_device *device = peer_device->device;
                kref_get(&device->kref);
                rcu_read_unlock();
 
-               /* Prevent a race between resync-handshake and
-                * being promoted to Primary.
-                *
-                * Grab and release the state mutex, so we know that any current
-                * drbd_set_role() is finished, and any incoming drbd_set_role
-                * will see the STATE_SENT flag, and wait for it to be cleared.
-                */
-               mutex_lock(device->state_mutex);
-               mutex_unlock(device->state_mutex);
-
                if (discard_my_data)
                        set_bit(DISCARD_MY_DATA, &device->flags);
                else
@@ -1315,6 +1326,20 @@ int drbd_submit_peer_request(struct drbd_device *device,
        unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT;
        int err = -ENOMEM;
 
+       if (peer_req->flags & EE_IS_TRIM_USE_ZEROOUT) {
+               /* wait for all pending IO completions, before we start
+                * zeroing things out. */
+               conn_wait_active_ee_empty(first_peer_device(device)->connection);
+               if (blkdev_issue_zeroout(device->ldev->backing_bdev,
+                       sector, ds >> 9, GFP_NOIO))
+                       peer_req->flags |= EE_WAS_ERROR;
+               drbd_endio_write_sec_final(peer_req);
+               return 0;
+       }
+
+       if (peer_req->flags & EE_IS_TRIM)
+               nr_pages = 0; /* discards don't have any payload. */
+
        /* In most cases, we will only need one bio.  But in case the lower
         * level restrictions happen to be different at this offset on this
         * side than those of the sending peer, we may need to submit the
@@ -1326,7 +1351,7 @@ int drbd_submit_peer_request(struct drbd_device *device,
 next_bio:
        bio = bio_alloc(GFP_NOIO, nr_pages);
        if (!bio) {
-               drbd_err(device, "submit_ee: Allocation of a bio failed\n");
+               drbd_err(device, "submit_ee: Allocation of a bio failed (nr_pages=%u)\n", nr_pages);
                goto fail;
        }
        /* > peer_req->i.sector, unless this is the first bio */
@@ -1340,6 +1365,11 @@ next_bio:
        bios = bio;
        ++n_bios;
 
+       if (rw & REQ_DISCARD) {
+               bio->bi_iter.bi_size = ds;
+               goto submit;
+       }
+
        page_chain_for_each(page) {
                unsigned len = min_t(unsigned, ds, PAGE_SIZE);
                if (!bio_add_page(bio, page, len, 0)) {
@@ -1360,8 +1390,9 @@ next_bio:
                sector += len >> 9;
                --nr_pages;
        }
-       D_ASSERT(device, page == NULL);
        D_ASSERT(device, ds == 0);
+submit:
+       D_ASSERT(device, page == NULL);
 
        atomic_set(&peer_req->pending_bios, n_bios);
        do {
@@ -1490,19 +1521,21 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf
  * and from receive_Data */
 static struct drbd_peer_request *
 read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
-             int data_size) __must_hold(local)
+             struct packet_info *pi) __must_hold(local)
 {
        struct drbd_device *device = peer_device->device;
        const sector_t capacity = drbd_get_capacity(device->this_bdev);
        struct drbd_peer_request *peer_req;
        struct page *page;
        int dgs, ds, err;
+       int data_size = pi->size;
        void *dig_in = peer_device->connection->int_dig_in;
        void *dig_vv = peer_device->connection->int_dig_vv;
        unsigned long *data;
+       struct p_trim *trim = (pi->cmd == P_TRIM) ? pi->data : NULL;
 
        dgs = 0;
-       if (peer_device->connection->peer_integrity_tfm) {
+       if (!trim && peer_device->connection->peer_integrity_tfm) {
                dgs = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
                /*
                 * FIXME: Receive the incoming digest into the receive buffer
@@ -1514,9 +1547,15 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
                data_size -= dgs;
        }
 
+       if (trim) {
+               D_ASSERT(peer_device, data_size == 0);
+               data_size = be32_to_cpu(trim->size);
+       }
+
        if (!expect(IS_ALIGNED(data_size, 512)))
                return NULL;
-       if (!expect(data_size <= DRBD_MAX_BIO_SIZE))
+       /* prepare for larger trim requests. */
+       if (!trim && !expect(data_size <= DRBD_MAX_BIO_SIZE))
                return NULL;
 
        /* even though we trust out peer,
@@ -1532,11 +1571,11 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
        /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
         * "criss-cross" setup, that might cause write-out on some other DRBD,
         * which in turn might block on the other node at this very place.  */
-       peer_req = drbd_alloc_peer_req(peer_device, id, sector, data_size, GFP_NOIO);
+       peer_req = drbd_alloc_peer_req(peer_device, id, sector, data_size, trim == NULL, GFP_NOIO);
        if (!peer_req)
                return NULL;
 
-       if (!data_size)
+       if (trim)
                return peer_req;
 
        ds = data_size;
@@ -1676,12 +1715,12 @@ static int e_end_resync_block(struct drbd_work *w, int unused)
 }
 
 static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector,
-                           int data_size) __releases(local)
+                           struct packet_info *pi) __releases(local)
 {
        struct drbd_device *device = peer_device->device;
        struct drbd_peer_request *peer_req;
 
-       peer_req = read_in_block(peer_device, ID_SYNCER, sector, data_size);
+       peer_req = read_in_block(peer_device, ID_SYNCER, sector, pi);
        if (!peer_req)
                goto fail;
 
@@ -1697,7 +1736,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto
        list_add(&peer_req->w.list, &device->sync_ee);
        spin_unlock_irq(&device->resource->req_lock);
 
-       atomic_add(data_size >> 9, &device->rs_sect_ev);
+       atomic_add(pi->size >> 9, &device->rs_sect_ev);
        if (drbd_submit_peer_request(device, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0)
                return 0;
 
@@ -1785,7 +1824,7 @@ static int receive_RSDataReply(struct drbd_connection *connection, struct packet
                /* data is submitted to disk within recv_resync_read.
                 * corresponding put_ldev done below on error,
                 * or in drbd_peer_request_endio. */
-               err = recv_resync_read(peer_device, sector, pi->size);
+               err = recv_resync_read(peer_device, sector, pi);
        } else {
                if (__ratelimit(&drbd_ratelimit_state))
                        drbd_err(device, "Can not write resync data to local disk.\n");
@@ -2196,7 +2235,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
         */
 
        sector = be64_to_cpu(p->sector);
-       peer_req = read_in_block(peer_device, p->block_id, sector, pi->size);
+       peer_req = read_in_block(peer_device, p->block_id, sector, pi);
        if (!peer_req) {
                put_ldev(device);
                return -EIO;
@@ -2206,7 +2245,15 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
 
        dp_flags = be32_to_cpu(p->dp_flags);
        rw |= wire_flags_to_bio(dp_flags);
-       if (peer_req->pages == NULL) {
+       if (pi->cmd == P_TRIM) {
+               struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev);
+               peer_req->flags |= EE_IS_TRIM;
+               if (!blk_queue_discard(q))
+                       peer_req->flags |= EE_IS_TRIM_USE_ZEROOUT;
+               D_ASSERT(peer_device, peer_req->i.size > 0);
+               D_ASSERT(peer_device, rw & REQ_DISCARD);
+               D_ASSERT(peer_device, peer_req->pages == NULL);
+       } else if (peer_req->pages == NULL) {
                D_ASSERT(device, peer_req->i.size == 0);
                D_ASSERT(device, dp_flags & DP_FLUSH);
        }
@@ -2242,7 +2289,12 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
                update_peer_seq(peer_device, peer_seq);
                spin_lock_irq(&device->resource->req_lock);
        }
-       list_add(&peer_req->w.list, &device->active_ee);
+       /* if we use the zeroout fallback code, we process synchronously
+        * and we wait for all pending requests, respectively wait for
+        * active_ee to become empty in drbd_submit_peer_request();
+        * better not add ourselves here. */
+       if ((peer_req->flags & EE_IS_TRIM_USE_ZEROOUT) == 0)
+               list_add(&peer_req->w.list, &device->active_ee);
        spin_unlock_irq(&device->resource->req_lock);
 
        if (device->state.conn == C_SYNC_TARGET)
@@ -2313,39 +2365,45 @@ out_interrupted:
  * The current sync rate used here uses only the most recent two step marks,
  * to have a short time average so we can react faster.
  */
-int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector)
+bool drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector)
 {
-       struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk;
-       unsigned long db, dt, dbdt;
        struct lc_element *tmp;
-       int curr_events;
-       int throttle = 0;
-       unsigned int c_min_rate;
-
-       rcu_read_lock();
-       c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate;
-       rcu_read_unlock();
+       bool throttle = true;
 
-       /* feature disabled? */
-       if (c_min_rate == 0)
-               return 0;
+       if (!drbd_rs_c_min_rate_throttle(device))
+               return false;
 
        spin_lock_irq(&device->al_lock);
        tmp = lc_find(device->resync, BM_SECT_TO_EXT(sector));
        if (tmp) {
                struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
-               if (test_bit(BME_PRIORITY, &bm_ext->flags)) {
-                       spin_unlock_irq(&device->al_lock);
-                       return 0;
-               }
+               if (test_bit(BME_PRIORITY, &bm_ext->flags))
+                       throttle = false;
                /* Do not slow down if app IO is already waiting for this extent */
        }
        spin_unlock_irq(&device->al_lock);
 
+       return throttle;
+}
+
+bool drbd_rs_c_min_rate_throttle(struct drbd_device *device)
+{
+       struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk;
+       unsigned long db, dt, dbdt;
+       unsigned int c_min_rate;
+       int curr_events;
+
+       rcu_read_lock();
+       c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate;
+       rcu_read_unlock();
+
+       /* feature disabled? */
+       if (c_min_rate == 0)
+               return false;
+
        curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
                      (int)part_stat_read(&disk->part0, sectors[1]) -
                        atomic_read(&device->rs_sect_ev);
-
        if (!device->rs_last_events || curr_events - device->rs_last_events > 64) {
                unsigned long rs_left;
                int i;
@@ -2368,12 +2426,11 @@ int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector)
                dbdt = Bit2KB(db/dt);
 
                if (dbdt > c_min_rate)
-                       throttle = 1;
+                       return true;
        }
-       return throttle;
+       return false;
 }
 
-
 static int receive_DataRequest(struct drbd_connection *connection, struct packet_info *pi)
 {
        struct drbd_peer_device *peer_device;
@@ -2436,7 +2493,8 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
        /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
         * "criss-cross" setup, that might cause write-out on some other DRBD,
         * which in turn might block on the other node at this very place.  */
-       peer_req = drbd_alloc_peer_req(peer_device, p->block_id, sector, size, GFP_NOIO);
+       peer_req = drbd_alloc_peer_req(peer_device, p->block_id, sector, size,
+                       true /* has real payload */, GFP_NOIO);
        if (!peer_req) {
                put_ldev(device);
                return -ENOMEM;
@@ -3648,6 +3706,13 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
                put_ldev(device);
        }
 
+       device->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+       drbd_reconsider_max_bio_size(device);
+       /* Leave drbd_reconsider_max_bio_size() before drbd_determine_dev_size().
+          In case we cleared the QUEUE_FLAG_DISCARD from our queue in
+          drbd_reconsider_max_bio_size(), we can be sure that after
+          drbd_determine_dev_size() no REQ_DISCARDs are in the queue. */
+
        ddsf = be16_to_cpu(p->dds_flags);
        if (get_ldev(device)) {
                dd = drbd_determine_dev_size(device, ddsf, NULL);
@@ -3660,9 +3725,6 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
                drbd_set_my_capacity(device, p_size);
        }
 
-       device->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
-       drbd_reconsider_max_bio_size(device);
-
        if (get_ldev(device)) {
                if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev)) {
                        device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
@@ -4423,6 +4485,7 @@ static struct data_cmd drbd_cmd_handler[] = {
        [P_OUT_OF_SYNC]     = { 0, sizeof(struct p_block_desc), receive_out_of_sync },
        [P_CONN_ST_CHG_REQ] = { 0, sizeof(struct p_req_state), receive_req_conn_state },
        [P_PROTOCOL_UPDATE] = { 1, sizeof(struct p_protocol), receive_protocol },
+       [P_TRIM]            = { 0, sizeof(struct p_trim), receive_Data },
 };
 
 static void drbdd(struct drbd_connection *connection)
@@ -4630,6 +4693,7 @@ static int drbd_send_features(struct drbd_connection *connection)
        memset(p, 0, sizeof(*p));
        p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
        p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
+       p->feature_flags = cpu_to_be32(PRO_FEATURES);
        return conn_send_command(connection, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0);
 }
 
@@ -4683,10 +4747,14 @@ static int drbd_do_features(struct drbd_connection *connection)
                goto incompat;
 
        connection->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
+       connection->agreed_features = PRO_FEATURES & be32_to_cpu(p->feature_flags);
 
        drbd_info(connection, "Handshake successful: "
             "Agreed network protocol version %d\n", connection->agreed_pro_version);
 
+       drbd_info(connection, "Agreed to%ssupport TRIM on protocol level\n",
+                 connection->agreed_features & FF_TRIM ? " " : " not ");
+
        return 1;
 
  incompat:
@@ -4778,6 +4846,12 @@ static int drbd_do_auth(struct drbd_connection *connection)
                goto fail;
        }
 
+       if (pi.size < CHALLENGE_LEN) {
+               drbd_err(connection, "AuthChallenge payload too small.\n");
+               rv = -1;
+               goto fail;
+       }
+
        peers_ch = kmalloc(pi.size, GFP_NOIO);
        if (peers_ch == NULL) {
                drbd_err(connection, "kmalloc of peers_ch failed\n");
@@ -4791,6 +4865,12 @@ static int drbd_do_auth(struct drbd_connection *connection)
                goto fail;
        }
 
+       if (!memcmp(my_challenge, peers_ch, CHALLENGE_LEN)) {
+               drbd_err(connection, "Peer presented the same challenge!\n");
+               rv = -1;
+               goto fail;
+       }
+
        resp_size = crypto_hash_digestsize(connection->cram_hmac_tfm);
        response = kmalloc(resp_size, GFP_NOIO);
        if (response == NULL) {
index 3779c8d2875bb00529853e1e2c4d6f6a5a083b17..09803d0d5207ce7fccffc5c4a3cb0229071566cd 100644 (file)
@@ -522,6 +522,13 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED);
                break;
 
+       case DISCARD_COMPLETED_NOTSUPP:
+       case DISCARD_COMPLETED_WITH_ERROR:
+               /* I'd rather not detach from local disk just because it
+                * failed a REQ_DISCARD. */
+               mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED);
+               break;
+
        case QUEUE_FOR_NET_READ:
                /* READ or READA, and
                 * no local disk,
@@ -1235,6 +1242,7 @@ void do_submit(struct work_struct *ws)
                if (list_empty(&incoming))
                        break;
 
+skip_fast_path:
                wait_event(device->al_wait, prepare_al_transaction_nonblock(device, &incoming, &pending));
                /* Maybe more was queued, while we prepared the transaction?
                 * Try to stuff them into this transaction as well.
@@ -1273,6 +1281,25 @@ void do_submit(struct work_struct *ws)
                        list_del_init(&req->tl_requests);
                        drbd_send_and_submit(device, req);
                }
+
+               /* If all currently hot activity log extents are kept busy by
+                * incoming requests, we still must not totally starve new
+                * requests to cold extents. In that case, prepare one request
+                * in blocking mode. */
+               list_for_each_entry_safe(req, tmp, &incoming, tl_requests) {
+                       list_del_init(&req->tl_requests);
+                       req->rq_state |= RQ_IN_ACT_LOG;
+                       if (!drbd_al_begin_io_prepare(device, &req->i)) {
+                               /* Corresponding extent was hot after all? */
+                               drbd_send_and_submit(device, req);
+                       } else {
+                               /* Found a request to a cold extent.
+                                * Put on "pending" list,
+                                * and try to cumulate with more. */
+                               list_add(&req->tl_requests, &pending);
+                               goto skip_fast_path;
+                       }
+               }
        }
 }
 
@@ -1326,23 +1353,35 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct
        return limit;
 }
 
-static struct drbd_request *find_oldest_request(struct drbd_connection *connection)
+static void find_oldest_requests(
+               struct drbd_connection *connection,
+               struct drbd_device *device,
+               struct drbd_request **oldest_req_waiting_for_peer,
+               struct drbd_request **oldest_req_waiting_for_disk)
 {
-       /* Walk the transfer log,
-        * and find the oldest not yet completed request */
        struct drbd_request *r;
+       *oldest_req_waiting_for_peer = NULL;
+       *oldest_req_waiting_for_disk = NULL;
        list_for_each_entry(r, &connection->transfer_log, tl_requests) {
-               if (atomic_read(&r->completion_ref))
-                       return r;
+               const unsigned s = r->rq_state;
+               if (!*oldest_req_waiting_for_peer
+               && ((s & RQ_NET_MASK) && !(s & RQ_NET_DONE)))
+                       *oldest_req_waiting_for_peer = r;
+
+               if (!*oldest_req_waiting_for_disk
+               && (s & RQ_LOCAL_PENDING) && r->device == device)
+                       *oldest_req_waiting_for_disk = r;
+
+               if (*oldest_req_waiting_for_peer && *oldest_req_waiting_for_disk)
+                       break;
        }
-       return NULL;
 }
 
 void request_timer_fn(unsigned long data)
 {
        struct drbd_device *device = (struct drbd_device *) data;
        struct drbd_connection *connection = first_peer_device(device)->connection;
-       struct drbd_request *req; /* oldest request */
+       struct drbd_request *req_disk, *req_peer; /* oldest request */
        struct net_conf *nc;
        unsigned long ent = 0, dt = 0, et, nt; /* effective timeout = ko_count * timeout */
        unsigned long now;
@@ -1366,8 +1405,8 @@ void request_timer_fn(unsigned long data)
        now = jiffies;
 
        spin_lock_irq(&device->resource->req_lock);
-       req = find_oldest_request(connection);
-       if (!req) {
+       find_oldest_requests(connection, device, &req_peer, &req_disk);
+       if (req_peer == NULL && req_disk == NULL) {
                spin_unlock_irq(&device->resource->req_lock);
                mod_timer(&device->request_timer, now + et);
                return;
@@ -1389,19 +1428,26 @@ void request_timer_fn(unsigned long data)
         * ~198 days with 250 HZ, we have a window where the timeout would need
         * to expire twice (worst case) to become effective. Good enough.
         */
-       if (ent && req->rq_state & RQ_NET_PENDING &&
-                time_after(now, req->start_time + ent) &&
+       if (ent && req_peer &&
+                time_after(now, req_peer->start_time + ent) &&
                !time_in_range(now, connection->last_reconnect_jif, connection->last_reconnect_jif + ent)) {
                drbd_warn(device, "Remote failed to finish a request within ko-count * timeout\n");
                _drbd_set_state(_NS(device, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL);
        }
-       if (dt && req->rq_state & RQ_LOCAL_PENDING && req->device == device &&
-                time_after(now, req->start_time + dt) &&
+       if (dt && req_disk &&
+                time_after(now, req_disk->start_time + dt) &&
                !time_in_range(now, device->last_reattach_jif, device->last_reattach_jif + dt)) {
                drbd_warn(device, "Local backing device failed to meet the disk-timeout\n");
                __drbd_chk_io_error(device, DRBD_FORCE_DETACH);
        }
-       nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et;
+
+       /* Reschedule timer for the nearest not already expired timeout.
+        * Fallback to now + min(effective network timeout, disk timeout). */
+       ent = (ent && req_peer && time_before(now, req_peer->start_time + ent))
+               ? req_peer->start_time + ent : now + et;
+       dt = (dt && req_disk && time_before(now, req_disk->start_time + dt))
+               ? req_disk->start_time + dt : now + et;
+       nt = time_before(ent, dt) ? ent : dt;
        spin_unlock_irq(&connection->resource->req_lock);
        mod_timer(&device->request_timer, nt);
 }
index c684c963538ea85ce949525fb031aa89a8e1e0f2..8566cd5866b4e2388cdb441439f25eecf6071443 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/slab.h>
 #include <linux/drbd.h>
 #include "drbd_int.h"
-#include "drbd_wrappers.h"
 
 /* The request callbacks will be called in irq context by the IDE drivers,
    and in Softirqs/Tasklets/BH context by the SCSI drivers,
@@ -111,11 +110,14 @@ enum drbd_req_event {
        BARRIER_ACKED, /* in protocol A and B */
        DATA_RECEIVED, /* (remote read) */
 
+       COMPLETED_OK,
        READ_COMPLETED_WITH_ERROR,
        READ_AHEAD_COMPLETED_WITH_ERROR,
        WRITE_COMPLETED_WITH_ERROR,
+       DISCARD_COMPLETED_NOTSUPP,
+       DISCARD_COMPLETED_WITH_ERROR,
+
        ABORT_DISK_IO,
-       COMPLETED_OK,
        RESEND,
        FAIL_FROZEN_DISK_IO,
        RESTART_FROZEN_DISK_IO,
index 1a84345a3868b90e79425a7770884192b1e54b85..a5d8aae00e04c9515d4a684caaeabb079ada6dc5 100644 (file)
@@ -54,8 +54,8 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
 static enum drbd_state_rv is_valid_state(struct drbd_device *, union drbd_state);
 static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_connection *);
 static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns);
-static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns,
-                                      enum sanitize_state_warnings *warn);
+static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os,
+                                      union drbd_state ns, enum sanitize_state_warnings *warn);
 
 static inline bool is_susp(union drbd_state s)
 {
@@ -287,7 +287,7 @@ _req_st_cond(struct drbd_device *device, union drbd_state mask,
 
        spin_lock_irqsave(&device->resource->req_lock, flags);
        os = drbd_read_state(device);
-       ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
+       ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL);
        rv = is_valid_transition(os, ns);
        if (rv >= SS_SUCCESS)
                rv = SS_UNKNOWN_ERROR;  /* cont waiting, otherwise fail. */
@@ -333,7 +333,7 @@ drbd_req_state(struct drbd_device *device, union drbd_state mask,
 
        spin_lock_irqsave(&device->resource->req_lock, flags);
        os = drbd_read_state(device);
-       ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
+       ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL);
        rv = is_valid_transition(os, ns);
        if (rv < SS_SUCCESS) {
                spin_unlock_irqrestore(&device->resource->req_lock, flags);
@@ -740,8 +740,8 @@ static void print_sanitize_warnings(struct drbd_device *device, enum sanitize_st
  * When we loose connection, we have to set the state of the peers disk (pdsk)
  * to D_UNKNOWN. This rule and many more along those lines are in this function.
  */
-static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns,
-                                      enum sanitize_state_warnings *warn)
+static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os,
+                                      union drbd_state ns, enum sanitize_state_warnings *warn)
 {
        enum drbd_fencing_p fp;
        enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max;
@@ -882,11 +882,13 @@ static union drbd_state sanitize_state(struct drbd_device *device, union drbd_st
        }
 
        if (fp == FP_STONITH &&
-           (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED))
+           (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) &&
+           !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED))
                ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */
 
        if (device->resource->res_opts.on_no_data == OND_SUSPEND_IO &&
-           (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
+           (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) &&
+           !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE))
                ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */
 
        if (ns.aftr_isp || ns.peer_isp || ns.user_isp) {
@@ -958,7 +960,7 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
 
        os = drbd_read_state(device);
 
-       ns = sanitize_state(device, ns, &ssw);
+       ns = sanitize_state(device, os, ns, &ssw);
        if (ns.i == os.i)
                return SS_NOTHING_TO_DO;
 
@@ -1656,7 +1658,7 @@ conn_is_valid_transition(struct drbd_connection *connection, union drbd_state ma
        idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
                struct drbd_device *device = peer_device->device;
                os = drbd_read_state(device);
-               ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
+               ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL);
 
                if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
                        ns.disk = os.disk;
@@ -1718,7 +1720,7 @@ conn_set_state(struct drbd_connection *connection, union drbd_state mask, union
                number_of_volumes++;
                os = drbd_read_state(device);
                ns = apply_mask_val(os, mask, val);
-               ns = sanitize_state(device, ns, NULL);
+               ns = sanitize_state(device, os, ns, NULL);
 
                if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
                        ns.disk = os.disk;
@@ -1763,19 +1765,19 @@ conn_set_state(struct drbd_connection *connection, union drbd_state mask, union
 static enum drbd_state_rv
 _conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union drbd_state val)
 {
-       enum drbd_state_rv rv;
+       enum drbd_state_rv err, rv = SS_UNKNOWN_ERROR; /* continue waiting */;
 
        if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &connection->flags))
-               return SS_CW_SUCCESS;
+               rv = SS_CW_SUCCESS;
 
        if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &connection->flags))
-               return SS_CW_FAILED_BY_PEER;
+               rv = SS_CW_FAILED_BY_PEER;
 
-       rv = conn_is_valid_transition(connection, mask, val, 0);
-       if (rv == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS)
-               rv = SS_UNKNOWN_ERROR; /* continue waiting */
+       err = conn_is_valid_transition(connection, mask, val, 0);
+       if (err == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS)
+               return rv;
 
-       return rv;
+       return err;
 }
 
 enum drbd_state_rv
index 2c4ce42c3657882cfaf07dfdef97ed95bf4e513b..d8f57b6305cd6f84ec0be24309512fe5b25a8e92 100644 (file)
@@ -118,7 +118,7 @@ static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __rele
 
 /* writes on behalf of the partner, or resync writes,
  * "submitted" by the receiver, final stage.  */
-static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local)
+void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local)
 {
        unsigned long flags = 0;
        struct drbd_peer_device *peer_device = peer_req->peer_device;
@@ -150,7 +150,9 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel
 
        do_wake = list_empty(block_id == ID_SYNCER ? &device->sync_ee : &device->active_ee);
 
-       if (test_bit(__EE_WAS_ERROR, &peer_req->flags))
+       /* FIXME do we want to detach for failed REQ_DISCARD?
+        * ((peer_req->flags & (EE_WAS_ERROR|EE_IS_TRIM)) == EE_WAS_ERROR) */
+       if (peer_req->flags & EE_WAS_ERROR)
                __drbd_chk_io_error(device, DRBD_WRITE_ERROR);
        spin_unlock_irqrestore(&device->resource->req_lock, flags);
 
@@ -176,10 +178,12 @@ void drbd_peer_request_endio(struct bio *bio, int error)
        struct drbd_device *device = peer_req->peer_device->device;
        int uptodate = bio_flagged(bio, BIO_UPTODATE);
        int is_write = bio_data_dir(bio) == WRITE;
+       int is_discard = !!(bio->bi_rw & REQ_DISCARD);
 
        if (error && __ratelimit(&drbd_ratelimit_state))
                drbd_warn(device, "%s: error=%d s=%llus\n",
-                               is_write ? "write" : "read", error,
+                               is_write ? (is_discard ? "discard" : "write")
+                                       : "read", error,
                                (unsigned long long)peer_req->i.sector);
        if (!error && !uptodate) {
                if (__ratelimit(&drbd_ratelimit_state))
@@ -263,7 +267,12 @@ void drbd_request_endio(struct bio *bio, int error)
 
        /* to avoid recursion in __req_mod */
        if (unlikely(error)) {
-               what = (bio_data_dir(bio) == WRITE)
+               if (bio->bi_rw & REQ_DISCARD)
+                       what = (error == -EOPNOTSUPP)
+                               ? DISCARD_COMPLETED_NOTSUPP
+                               : DISCARD_COMPLETED_WITH_ERROR;
+               else
+                       what = (bio_data_dir(bio) == WRITE)
                        ? WRITE_COMPLETED_WITH_ERROR
                        : (bio_rw(bio) == READ)
                          ? READ_COMPLETED_WITH_ERROR
@@ -395,7 +404,7 @@ static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector,
        /* GFP_TRY, because if there is no memory available right now, this may
         * be rescheduled for later. It is "only" background resync, after all. */
        peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER /* unused */, sector,
-                                      size, GFP_TRY);
+                                      size, true /* has real payload */, GFP_TRY);
        if (!peer_req)
                goto defer;
 
@@ -492,10 +501,9 @@ struct fifo_buffer *fifo_alloc(int fifo_size)
        return fb;
 }
 
-static int drbd_rs_controller(struct drbd_device *device)
+static int drbd_rs_controller(struct drbd_device *device, unsigned int sect_in)
 {
        struct disk_conf *dc;
-       unsigned int sect_in;  /* Number of sectors that came in since the last turn */
        unsigned int want;     /* The number of sectors we want in the proxy */
        int req_sect; /* Number of sectors to request in this turn */
        int correction; /* Number of sectors more we need in the proxy*/
@@ -505,9 +513,6 @@ static int drbd_rs_controller(struct drbd_device *device)
        int max_sect;
        struct fifo_buffer *plan;
 
-       sect_in = atomic_xchg(&device->rs_sect_in, 0); /* Number of sectors that came in */
-       device->rs_in_flight -= sect_in;
-
        dc = rcu_dereference(device->ldev->disk_conf);
        plan = rcu_dereference(device->rs_plan_s);
 
@@ -550,11 +555,16 @@ static int drbd_rs_controller(struct drbd_device *device)
 
 static int drbd_rs_number_requests(struct drbd_device *device)
 {
-       int number;
+       unsigned int sect_in;  /* Number of sectors that came in since the last turn */
+       int number, mxb;
+
+       sect_in = atomic_xchg(&device->rs_sect_in, 0);
+       device->rs_in_flight -= sect_in;
 
        rcu_read_lock();
+       mxb = drbd_get_max_buffers(device) / 2;
        if (rcu_dereference(device->rs_plan_s)->size) {
-               number = drbd_rs_controller(device) >> (BM_BLOCK_SHIFT - 9);
+               number = drbd_rs_controller(device, sect_in) >> (BM_BLOCK_SHIFT - 9);
                device->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME;
        } else {
                device->c_sync_rate = rcu_dereference(device->ldev->disk_conf)->resync_rate;
@@ -562,8 +572,14 @@ static int drbd_rs_number_requests(struct drbd_device *device)
        }
        rcu_read_unlock();
 
-       /* ignore the amount of pending requests, the resync controller should
-        * throttle down to incoming reply rate soon enough anyways. */
+       /* Don't have more than "max-buffers"/2 in-flight.
+        * Otherwise we may cause the remote site to stall on drbd_alloc_pages(),
+        * potentially causing a distributed deadlock on congestion during
+        * online-verify or (checksum-based) resync, if max-buffers,
+        * socket buffer sizes and resync rate settings are mis-configured. */
+       if (mxb - device->rs_in_flight < number)
+               number = mxb - device->rs_in_flight;
+
        return number;
 }
 
@@ -597,7 +613,7 @@ static int make_resync_request(struct drbd_device *device, int cancel)
 
        max_bio_size = queue_max_hw_sectors(device->rq_queue) << 9;
        number = drbd_rs_number_requests(device);
-       if (number == 0)
+       if (number <= 0)
                goto requeue;
 
        for (i = 0; i < number; i++) {
@@ -647,7 +663,7 @@ next_sector:
                 */
                align = 1;
                rollback_i = i;
-               for (;;) {
+               while (i < number) {
                        if (size + BM_BLOCK_SIZE > max_bio_size)
                                break;
 
@@ -1670,11 +1686,15 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
        }
        clear_bit(B_RS_H_DONE, &device->flags);
 
-       write_lock_irq(&global_state_lock);
+       /* req_lock: serialize with drbd_send_and_submit() and others
+        * global_state_lock: for stable sync-after dependencies */
+       spin_lock_irq(&device->resource->req_lock);
+       write_lock(&global_state_lock);
        /* Did some connection breakage or IO error race with us? */
        if (device->state.conn < C_CONNECTED
        || !get_ldev_if_state(device, D_NEGOTIATING)) {
-               write_unlock_irq(&global_state_lock);
+               write_unlock(&global_state_lock);
+               spin_unlock_irq(&device->resource->req_lock);
                mutex_unlock(device->state_mutex);
                return;
        }
@@ -1714,7 +1734,8 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
                }
                _drbd_pause_after(device);
        }
-       write_unlock_irq(&global_state_lock);
+       write_unlock(&global_state_lock);
+       spin_unlock_irq(&device->resource->req_lock);
 
        if (r == SS_SUCCESS) {
                /* reset rs_last_bcast when a resync or verify is started,
@@ -1778,34 +1799,6 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
        mutex_unlock(device->state_mutex);
 }
 
-/* If the resource already closed the current epoch, but we did not
- * (because we have not yet seen new requests), we should send the
- * corresponding barrier now.  Must be checked within the same spinlock
- * that is used to check for new requests. */
-static bool need_to_send_barrier(struct drbd_connection *connection)
-{
-       if (!connection->send.seen_any_write_yet)
-               return false;
-
-       /* Skip barriers that do not contain any writes.
-        * This may happen during AHEAD mode. */
-       if (!connection->send.current_epoch_writes)
-               return false;
-
-       /* ->req_lock is held when requests are queued on
-        * connection->sender_work, and put into ->transfer_log.
-        * It is also held when ->current_tle_nr is increased.
-        * So either there are already new requests queued,
-        * and corresponding barriers will be send there.
-        * Or nothing new is queued yet, so the difference will be 1.
-        */
-       if (atomic_read(&connection->current_tle_nr) !=
-           connection->send.current_epoch_nr + 1)
-               return false;
-
-       return true;
-}
-
 static bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list)
 {
        spin_lock_irq(&queue->q_lock);
@@ -1864,12 +1857,22 @@ static void wait_for_work(struct drbd_connection *connection, struct list_head *
                        spin_unlock_irq(&connection->resource->req_lock);
                        break;
                }
-               send_barrier = need_to_send_barrier(connection);
+
+               /* We found nothing new to do, no to-be-communicated request,
+                * no other work item.  We may still need to close the last
+                * epoch.  Next incoming request epoch will be connection ->
+                * current transfer log epoch number.  If that is different
+                * from the epoch of the last request we communicated, it is
+                * safe to send the epoch separating barrier now.
+                */
+               send_barrier =
+                       atomic_read(&connection->current_tle_nr) !=
+                       connection->send.current_epoch_nr;
                spin_unlock_irq(&connection->resource->req_lock);
-               if (send_barrier) {
-                       drbd_send_barrier(connection);
-                       connection->send.current_epoch_nr++;
-               }
+
+               if (send_barrier)
+                       maybe_send_barrier(connection,
+                                       connection->send.current_epoch_nr + 1);
                schedule();
                /* may be woken up for other things but new work, too,
                 * e.g. if the current epoch got closed.
diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h
deleted file mode 100644 (file)
index 3db9eba..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _DRBD_WRAPPERS_H
-#define _DRBD_WRAPPERS_H
-
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include "drbd_int.h"
-
-/* see get_sb_bdev and bd_claim */
-extern char *drbd_sec_holder;
-
-/* sets the number of 512 byte sectors of our virtual device */
-static inline void drbd_set_my_capacity(struct drbd_device *device,
-                                       sector_t size)
-{
-       /* set_capacity(device->this_bdev->bd_disk, size); */
-       set_capacity(device->vdisk, size);
-       device->this_bdev->bd_inode->i_size = (loff_t)size << 9;
-}
-
-#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE)
-
-/* bi_end_io handlers */
-extern void drbd_md_io_complete(struct bio *bio, int error);
-extern void drbd_peer_request_endio(struct bio *bio, int error);
-extern void drbd_request_endio(struct bio *bio, int error);
-
-/*
- * used to submit our private bio
- */
-static inline void drbd_generic_make_request(struct drbd_device *device,
-                                            int fault_type, struct bio *bio)
-{
-       __release(local);
-       if (!bio->bi_bdev) {
-               printk(KERN_ERR "drbd%d: drbd_generic_make_request: "
-                               "bio->bi_bdev == NULL\n",
-                      device_to_minor(device));
-               dump_stack();
-               bio_endio(bio, -ENODEV);
-               return;
-       }
-
-       if (drbd_insert_fault(device, fault_type))
-               bio_endio(bio, -EIO);
-       else
-               generic_make_request(bio);
-}
-
-#ifndef __CHECKER__
-# undef __cond_lock
-# define __cond_lock(x,c) (c)
-#endif
-
-#endif
index 8f5565bf34cda31504e526ccc3d79d4e7fe20fd2..dc3a41c82b38a155a92af438ed7e21c77f8654ec 100644 (file)
@@ -2351,7 +2351,7 @@ static void rw_interrupt(void)
        }
 
        if (CT(COMMAND) != FD_READ ||
-           raw_cmd->kernel_data == current_req->buffer) {
+           raw_cmd->kernel_data == bio_data(current_req->bio)) {
                /* transfer directly from buffer */
                cont->done(1);
        } else if (CT(COMMAND) == FD_READ) {
@@ -2640,7 +2640,7 @@ static int make_raw_rw_request(void)
                raw_cmd->flags &= ~FD_RAW_WRITE;
                raw_cmd->flags |= FD_RAW_READ;
                COMMAND = FM_MODE(_floppy, FD_READ);
-       } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
+       } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
                unsigned long dma_limit;
                int direct, indirect;
 
@@ -2654,13 +2654,13 @@ static int make_raw_rw_request(void)
                 */
                max_size = buffer_chain_size();
                dma_limit = (MAX_DMA_ADDRESS -
-                            ((unsigned long)current_req->buffer)) >> 9;
+                            ((unsigned long)bio_data(current_req->bio))) >> 9;
                if ((unsigned long)max_size > dma_limit)
                        max_size = dma_limit;
                /* 64 kb boundaries */
-               if (CROSS_64KB(current_req->buffer, max_size << 9))
+               if (CROSS_64KB(bio_data(current_req->bio), max_size << 9))
                        max_size = (K_64 -
-                                   ((unsigned long)current_req->buffer) %
+                                   ((unsigned long)bio_data(current_req->bio)) %
                                    K_64) >> 9;
                direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
                /*
@@ -2677,7 +2677,7 @@ static int make_raw_rw_request(void)
                       (DP->read_track & (1 << DRS->probed_format)))))) {
                        max_size = blk_rq_sectors(current_req);
                } else {
-                       raw_cmd->kernel_data = current_req->buffer;
+                       raw_cmd->kernel_data = bio_data(current_req->bio);
                        raw_cmd->length = current_count_sectors << 9;
                        if (raw_cmd->length == 0) {
                                DPRINT("%s: zero dma transfer attempted\n", __func__);
@@ -2731,7 +2731,7 @@ static int make_raw_rw_request(void)
        raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
        raw_cmd->length <<= 9;
        if ((raw_cmd->length < current_count_sectors << 9) ||
-           (raw_cmd->kernel_data != current_req->buffer &&
+           (raw_cmd->kernel_data != bio_data(current_req->bio) &&
             CT(COMMAND) == FD_WRITE &&
             (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
              aligned_sector_t < buffer_min)) ||
@@ -2739,7 +2739,7 @@ static int make_raw_rw_request(void)
            raw_cmd->length <= 0 || current_count_sectors <= 0) {
                DPRINT("fractionary current count b=%lx s=%lx\n",
                       raw_cmd->length, current_count_sectors);
-               if (raw_cmd->kernel_data != current_req->buffer)
+               if (raw_cmd->kernel_data != bio_data(current_req->bio))
                        pr_info("addr=%d, length=%ld\n",
                                (int)((raw_cmd->kernel_data -
                                       floppy_track_buffer) >> 9),
@@ -2756,7 +2756,7 @@ static int make_raw_rw_request(void)
                return 0;
        }
 
-       if (raw_cmd->kernel_data != current_req->buffer) {
+       if (raw_cmd->kernel_data != bio_data(current_req->bio)) {
                if (raw_cmd->kernel_data < floppy_track_buffer ||
                    current_count_sectors < 0 ||
                    raw_cmd->length < 0 ||
@@ -3067,7 +3067,10 @@ static int raw_cmd_copyout(int cmd, void __user *param,
        int ret;
 
        while (ptr) {
-               ret = copy_to_user(param, ptr, sizeof(*ptr));
+               struct floppy_raw_cmd cmd = *ptr;
+               cmd.next = NULL;
+               cmd.kernel_data = NULL;
+               ret = copy_to_user(param, &cmd, sizeof(cmd));
                if (ret)
                        return -EFAULT;
                param += sizeof(struct floppy_raw_cmd);
@@ -3121,10 +3124,11 @@ loop:
                return -ENOMEM;
        *rcmd = ptr;
        ret = copy_from_user(ptr, param, sizeof(*ptr));
-       if (ret)
-               return -EFAULT;
        ptr->next = NULL;
        ptr->buffer_length = 0;
+       ptr->kernel_data = NULL;
+       if (ret)
+               return -EFAULT;
        param += sizeof(struct floppy_raw_cmd);
        if (ptr->cmd_count > 33)
                        /* the command may now also take up the space
@@ -3140,7 +3144,6 @@ loop:
        for (i = 0; i < 16; i++)
                ptr->reply[i] = 0;
        ptr->resultcode = 0;
-       ptr->kernel_data = NULL;
 
        if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
                if (ptr->length <= 0)
index bf397bf108b75de4ef302dc7b8f66f45303b891f..8a290c08262f26079ecd53235b3ee8c5bc43f681 100644 (file)
@@ -464,11 +464,11 @@ static void read_intr(void)
 
 ok_to_read:
        req = hd_req;
-       insw(HD_DATA, req->buffer, 256);
+       insw(HD_DATA, bio_data(req->bio), 256);
 #ifdef DEBUG
        printk("%s: read: sector %ld, remaining = %u, buffer=%p\n",
               req->rq_disk->disk_name, blk_rq_pos(req) + 1,
-              blk_rq_sectors(req) - 1, req->buffer+512);
+              blk_rq_sectors(req) - 1, bio_data(req->bio)+512);
 #endif
        if (hd_end_request(0, 512)) {
                SET_HANDLER(&read_intr);
@@ -505,7 +505,7 @@ static void write_intr(void)
 ok_to_write:
        if (hd_end_request(0, 512)) {
                SET_HANDLER(&write_intr);
-               outsw(HD_DATA, req->buffer, 256);
+               outsw(HD_DATA, bio_data(req->bio), 256);
                return;
        }
 
@@ -624,7 +624,7 @@ repeat:
        printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n",
                req->rq_disk->disk_name,
                req_data_dir(req) == READ ? "read" : "writ",
-               cyl, head, sec, nsect, req->buffer);
+               cyl, head, sec, nsect, bio_data(req->bio));
 #endif
        if (req->cmd_type == REQ_TYPE_FS) {
                switch (rq_data_dir(req)) {
@@ -643,7 +643,7 @@ repeat:
                                bad_rw_intr();
                                goto repeat;
                        }
-                       outsw(HD_DATA, req->buffer, 256);
+                       outsw(HD_DATA, bio_data(req->bio), 256);
                        break;
                default:
                        printk("unknown hd-command\n");
index eb59b124136690e217897dd6003473e09e5bd64a..e352cac707e82f5193324c1feafc6296d86bd219 100644 (file)
@@ -479,7 +479,7 @@ static unsigned int mg_out(struct mg_host *host,
 
 static void mg_read_one(struct mg_host *host, struct request *req)
 {
-       u16 *buff = (u16 *)req->buffer;
+       u16 *buff = (u16 *)bio_data(req->bio);
        u32 i;
 
        for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
@@ -496,7 +496,7 @@ static void mg_read(struct request *req)
                mg_bad_rw_intr(host);
 
        MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
-              blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
+              blk_rq_sectors(req), blk_rq_pos(req), bio_data(req->bio));
 
        do {
                if (mg_wait(host, ATA_DRQ,
@@ -514,7 +514,7 @@ static void mg_read(struct request *req)
 
 static void mg_write_one(struct mg_host *host, struct request *req)
 {
-       u16 *buff = (u16 *)req->buffer;
+       u16 *buff = (u16 *)bio_data(req->bio);
        u32 i;
 
        for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
@@ -534,7 +534,7 @@ static void mg_write(struct request *req)
        }
 
        MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
-              rem, blk_rq_pos(req), req->buffer);
+              rem, blk_rq_pos(req), bio_data(req->bio));
 
        if (mg_wait(host, ATA_DRQ,
                    MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
@@ -585,7 +585,7 @@ ok_to_read:
        mg_read_one(host, req);
 
        MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
-              blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer);
+              blk_rq_pos(req), blk_rq_sectors(req) - 1, bio_data(req->bio));
 
        /* send read confirm */
        outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
@@ -624,7 +624,7 @@ ok_to_write:
                /* write 1 sector and set handler if remains */
                mg_write_one(host, req);
                MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
-                      blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
+                      blk_rq_pos(req), blk_rq_sectors(req), bio_data(req->bio));
                host->mg_do_intr = mg_write_intr;
                mod_timer(&host->timer, jiffies + 3 * HZ);
        }
index 59c5abe32f06f055e939e5290e56055d66bd4c05..fb624469d0eeb0b63f5ff9acae2f2600f416813d 100644 (file)
@@ -1529,6 +1529,37 @@ static inline void ata_swap_string(u16 *buf, unsigned int len)
                be16_to_cpus(&buf[i]);
 }
 
+static void mtip_set_timeout(struct driver_data *dd,
+                                       struct host_to_dev_fis *fis,
+                                       unsigned int *timeout, u8 erasemode)
+{
+       switch (fis->command) {
+       case ATA_CMD_DOWNLOAD_MICRO:
+               *timeout = 120000; /* 2 minutes */
+               break;
+       case ATA_CMD_SEC_ERASE_UNIT:
+       case 0xFC:
+               if (erasemode)
+                       *timeout = ((*(dd->port->identify + 90) * 2) * 60000);
+               else
+                       *timeout = ((*(dd->port->identify + 89) * 2) * 60000);
+               break;
+       case ATA_CMD_STANDBYNOW1:
+               *timeout = 120000;  /* 2 minutes */
+               break;
+       case 0xF7:
+       case 0xFA:
+               *timeout = 60000;  /* 60 seconds */
+               break;
+       case ATA_CMD_SMART:
+               *timeout = 15000;  /* 15 seconds */
+               break;
+       default:
+               *timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS;
+               break;
+       }
+}
+
 /*
  * Request the device identity information.
  *
@@ -1644,6 +1675,7 @@ static int mtip_standby_immediate(struct mtip_port *port)
        int rv;
        struct host_to_dev_fis  fis;
        unsigned long start;
+       unsigned int timeout;
 
        /* Build the FIS. */
        memset(&fis, 0, sizeof(struct host_to_dev_fis));
@@ -1651,6 +1683,8 @@ static int mtip_standby_immediate(struct mtip_port *port)
        fis.opts        = 1 << 7;
        fis.command     = ATA_CMD_STANDBYNOW1;
 
+       mtip_set_timeout(port->dd, &fis, &timeout, 0);
+
        start = jiffies;
        rv = mtip_exec_internal_command(port,
                                        &fis,
@@ -1659,7 +1693,7 @@ static int mtip_standby_immediate(struct mtip_port *port)
                                        0,
                                        0,
                                        GFP_ATOMIC,
-                                       15000);
+                                       timeout);
        dbg_printk(MTIP_DRV_NAME "Time taken to complete standby cmd: %d ms\n",
                        jiffies_to_msecs(jiffies - start));
        if (rv)
@@ -2202,36 +2236,6 @@ static unsigned int implicit_sector(unsigned char command,
        }
        return rv;
 }
-static void mtip_set_timeout(struct driver_data *dd,
-                                       struct host_to_dev_fis *fis,
-                                       unsigned int *timeout, u8 erasemode)
-{
-       switch (fis->command) {
-       case ATA_CMD_DOWNLOAD_MICRO:
-               *timeout = 120000; /* 2 minutes */
-               break;
-       case ATA_CMD_SEC_ERASE_UNIT:
-       case 0xFC:
-               if (erasemode)
-                       *timeout = ((*(dd->port->identify + 90) * 2) * 60000);
-               else
-                       *timeout = ((*(dd->port->identify + 89) * 2) * 60000);
-               break;
-       case ATA_CMD_STANDBYNOW1:
-               *timeout = 120000;  /* 2 minutes */
-               break;
-       case 0xF7:
-       case 0xFA:
-               *timeout = 60000;  /* 60 seconds */
-               break;
-       case ATA_CMD_SMART:
-               *timeout = 15000;  /* 15 seconds */
-               break;
-       default:
-               *timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS;
-               break;
-       }
-}
 
 /*
  * Executes a taskfile
@@ -4479,6 +4483,57 @@ static DEFINE_HANDLER(5);
 static DEFINE_HANDLER(6);
 static DEFINE_HANDLER(7);
 
+static void mtip_disable_link_opts(struct driver_data *dd, struct pci_dev *pdev)
+{
+       int pos;
+       unsigned short pcie_dev_ctrl;
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (pos) {
+               pci_read_config_word(pdev,
+                       pos + PCI_EXP_DEVCTL,
+                       &pcie_dev_ctrl);
+               if (pcie_dev_ctrl & (1 << 11) ||
+                   pcie_dev_ctrl & (1 << 4)) {
+                       dev_info(&dd->pdev->dev,
+                               "Disabling ERO/No-Snoop on bridge device %04x:%04x\n",
+                                       pdev->vendor, pdev->device);
+                       pcie_dev_ctrl &= ~(PCI_EXP_DEVCTL_NOSNOOP_EN |
+                                               PCI_EXP_DEVCTL_RELAX_EN);
+                       pci_write_config_word(pdev,
+                               pos + PCI_EXP_DEVCTL,
+                               pcie_dev_ctrl);
+               }
+       }
+}
+
+static void mtip_fix_ero_nosnoop(struct driver_data *dd, struct pci_dev *pdev)
+{
+       /*
+        * This workaround is specific to AMD/ATI chipset with a PCI upstream
+        * device with device id 0x5aXX
+        */
+       if (pdev->bus && pdev->bus->self) {
+               if (pdev->bus->self->vendor == PCI_VENDOR_ID_ATI &&
+                   ((pdev->bus->self->device & 0xff00) == 0x5a00)) {
+                       mtip_disable_link_opts(dd, pdev->bus->self);
+               } else {
+                       /* Check further up the topology */
+                       struct pci_dev *parent_dev = pdev->bus->self;
+                       if (parent_dev->bus &&
+                               parent_dev->bus->parent &&
+                               parent_dev->bus->parent->self &&
+                               parent_dev->bus->parent->self->vendor ==
+                                        PCI_VENDOR_ID_ATI &&
+                               (parent_dev->bus->parent->self->device &
+                                       0xff00) == 0x5a00) {
+                               mtip_disable_link_opts(dd,
+                                       parent_dev->bus->parent->self);
+                       }
+               }
+       }
+}
+
 /*
  * Called for each supported PCI device detected.
  *
@@ -4630,6 +4685,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
                goto msi_initialize_err;
        }
 
+       mtip_fix_ero_nosnoop(dd, pdev);
+
        /* Initialize the block layer. */
        rv = mtip_block_initialize(dd);
        if (rv < 0) {
@@ -4935,13 +4992,13 @@ static int __init mtip_init(void)
  */
 static void __exit mtip_exit(void)
 {
-       debugfs_remove_recursive(dfs_parent);
-
        /* Release the allocated major block device number. */
        unregister_blkdev(mtip_major, MTIP_DRV_NAME);
 
        /* Unregister the PCI driver. */
        pci_unregister_driver(&mtip_pci_driver);
+
+       debugfs_remove_recursive(dfs_parent);
 }
 
 MODULE_AUTHOR("Micron Technology, Inc");
index 091b9ea14feb5856ceada49671197dfac567376c..e932398588aa187fda13a728c48b67c2cd9c64f5 100644 (file)
@@ -32,6 +32,7 @@ struct nullb {
        unsigned int index;
        struct request_queue *q;
        struct gendisk *disk;
+       struct blk_mq_tag_set tag_set;
        struct hrtimer timer;
        unsigned int queue_depth;
        spinlock_t lock;
@@ -202,8 +203,8 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
                entry = llist_reverse_order(entry);
                do {
                        cmd = container_of(entry, struct nullb_cmd, ll_list);
-                       end_cmd(cmd);
                        entry = entry->next;
+                       end_cmd(cmd);
                } while (entry);
        }
 
@@ -226,7 +227,7 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd)
 
 static void null_softirq_done_fn(struct request *rq)
 {
-       end_cmd(rq->special);
+       end_cmd(blk_mq_rq_to_pdu(rq));
 }
 
 static inline void null_handle_cmd(struct nullb_cmd *cmd)
@@ -311,7 +312,7 @@ static void null_request_fn(struct request_queue *q)
 
 static int null_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq)
 {
-       struct nullb_cmd *cmd = rq->special;
+       struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
 
        cmd->rq = rq;
        cmd->nq = hctx->driver_data;
@@ -320,10 +321,11 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq)
        return BLK_MQ_RQ_QUEUE_OK;
 }
 
-static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_reg *reg, unsigned int hctx_index)
+static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_tag_set *set,
+               unsigned int hctx_index)
 {
-       int b_size = DIV_ROUND_UP(reg->nr_hw_queues, nr_online_nodes);
-       int tip = (reg->nr_hw_queues % nr_online_nodes);
+       int b_size = DIV_ROUND_UP(set->nr_hw_queues, nr_online_nodes);
+       int tip = (set->nr_hw_queues % nr_online_nodes);
        int node = 0, i, n;
 
        /*
@@ -338,7 +340,7 @@ static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_reg *reg, unsigned in
 
                        tip--;
                        if (!tip)
-                               b_size = reg->nr_hw_queues / nr_online_nodes;
+                               b_size = set->nr_hw_queues / nr_online_nodes;
                }
        }
 
@@ -387,13 +389,17 @@ static struct blk_mq_ops null_mq_ops = {
        .map_queue      = blk_mq_map_queue,
        .init_hctx      = null_init_hctx,
        .complete       = null_softirq_done_fn,
+       .alloc_hctx     = blk_mq_alloc_single_hw_queue,
+       .free_hctx      = blk_mq_free_single_hw_queue,
 };
 
-static struct blk_mq_reg null_mq_reg = {
-       .ops            = &null_mq_ops,
-       .queue_depth    = 64,
-       .cmd_size       = sizeof(struct nullb_cmd),
-       .flags          = BLK_MQ_F_SHOULD_MERGE,
+static struct blk_mq_ops null_mq_ops_pernode = {
+       .queue_rq       = null_queue_rq,
+       .map_queue      = blk_mq_map_queue,
+       .init_hctx      = null_init_hctx,
+       .complete       = null_softirq_done_fn,
+       .alloc_hctx     = null_alloc_hctx,
+       .free_hctx      = null_free_hctx,
 };
 
 static void null_del_dev(struct nullb *nullb)
@@ -402,6 +408,8 @@ static void null_del_dev(struct nullb *nullb)
 
        del_gendisk(nullb->disk);
        blk_cleanup_queue(nullb->q);
+       if (queue_mode == NULL_Q_MQ)
+               blk_mq_free_tag_set(&nullb->tag_set);
        put_disk(nullb->disk);
        kfree(nullb);
 }
@@ -506,7 +514,7 @@ static int null_add_dev(void)
 
        nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, home_node);
        if (!nullb)
-               return -ENOMEM;
+               goto out;
 
        spin_lock_init(&nullb->lock);
 
@@ -514,49 +522,47 @@ static int null_add_dev(void)
                submit_queues = nr_online_nodes;
 
        if (setup_queues(nullb))
-               goto err;
+               goto out_free_nullb;
 
        if (queue_mode == NULL_Q_MQ) {
-               null_mq_reg.numa_node = home_node;
-               null_mq_reg.queue_depth = hw_queue_depth;
-               null_mq_reg.nr_hw_queues = submit_queues;
-
-               if (use_per_node_hctx) {
-                       null_mq_reg.ops->alloc_hctx = null_alloc_hctx;
-                       null_mq_reg.ops->free_hctx = null_free_hctx;
-               } else {
-                       null_mq_reg.ops->alloc_hctx = blk_mq_alloc_single_hw_queue;
-                       null_mq_reg.ops->free_hctx = blk_mq_free_single_hw_queue;
-               }
-
-               nullb->q = blk_mq_init_queue(&null_mq_reg, nullb);
+               if (use_per_node_hctx)
+                       nullb->tag_set.ops = &null_mq_ops_pernode;
+               else
+                       nullb->tag_set.ops = &null_mq_ops;
+               nullb->tag_set.nr_hw_queues = submit_queues;
+               nullb->tag_set.queue_depth = hw_queue_depth;
+               nullb->tag_set.numa_node = home_node;
+               nullb->tag_set.cmd_size = sizeof(struct nullb_cmd);
+               nullb->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+               nullb->tag_set.driver_data = nullb;
+
+               if (blk_mq_alloc_tag_set(&nullb->tag_set))
+                       goto out_cleanup_queues;
+
+               nullb->q = blk_mq_init_queue(&nullb->tag_set);
+               if (!nullb->q)
+                       goto out_cleanup_tags;
        } else if (queue_mode == NULL_Q_BIO) {
                nullb->q = blk_alloc_queue_node(GFP_KERNEL, home_node);
+               if (!nullb->q)
+                       goto out_cleanup_queues;
                blk_queue_make_request(nullb->q, null_queue_bio);
                init_driver_queues(nullb);
        } else {
                nullb->q = blk_init_queue_node(null_request_fn, &nullb->lock, home_node);
+               if (!nullb->q)
+                       goto out_cleanup_queues;
                blk_queue_prep_rq(nullb->q, null_rq_prep_fn);
-               if (nullb->q)
-                       blk_queue_softirq_done(nullb->q, null_softirq_done_fn);
+               blk_queue_softirq_done(nullb->q, null_softirq_done_fn);
                init_driver_queues(nullb);
        }
 
-       if (!nullb->q)
-               goto queue_fail;
-
        nullb->q->queuedata = nullb;
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q);
 
        disk = nullb->disk = alloc_disk_node(1, home_node);
-       if (!disk) {
-queue_fail:
-               blk_cleanup_queue(nullb->q);
-               cleanup_queues(nullb);
-err:
-               kfree(nullb);
-               return -ENOMEM;
-       }
+       if (!disk)
+               goto out_cleanup_blk_queue;
 
        mutex_lock(&lock);
        list_add_tail(&nullb->list, &nullb_list);
@@ -579,6 +585,18 @@ err:
        sprintf(disk->disk_name, "nullb%d", nullb->index);
        add_disk(disk);
        return 0;
+
+out_cleanup_blk_queue:
+       blk_cleanup_queue(nullb->q);
+out_cleanup_tags:
+       if (queue_mode == NULL_Q_MQ)
+               blk_mq_free_tag_set(&nullb->tag_set);
+out_cleanup_queues:
+       cleanup_queues(nullb);
+out_free_nullb:
+       kfree(nullb);
+out:
+       return -ENOMEM;
 }
 
 static int __init null_init(void)
index e76bdc074dbe5678e52a33463a743a8b55335555..719cb1bc16401640a535ee1a0c3ae65de7f08e1c 100644 (file)
@@ -747,7 +747,7 @@ static void do_pcd_request(struct request_queue * q)
                        pcd_current = cd;
                        pcd_sector = blk_rq_pos(pcd_req);
                        pcd_count = blk_rq_cur_sectors(pcd_req);
-                       pcd_buf = pcd_req->buffer;
+                       pcd_buf = bio_data(pcd_req->bio);
                        pcd_busy = 1;
                        ps_set_intr(do_pcd_read, NULL, 0, nice);
                        return;
index 19ad8f0c83efe6942eb2dbabc95a978a41f05cd9..fea7e76a00de66e7d20dd6859ad851d8ecb40a35 100644 (file)
@@ -454,7 +454,7 @@ static enum action do_pd_io_start(void)
                if (pd_block + pd_count > get_capacity(pd_req->rq_disk))
                        return Fail;
                pd_run = blk_rq_sectors(pd_req);
-               pd_buf = pd_req->buffer;
+               pd_buf = bio_data(pd_req->bio);
                pd_retries = 0;
                if (pd_cmd == READ)
                        return do_pd_read_start();
@@ -485,7 +485,7 @@ static int pd_next_buf(void)
        spin_lock_irqsave(&pd_lock, saved_flags);
        __blk_end_request_cur(pd_req, 0);
        pd_count = blk_rq_cur_sectors(pd_req);
-       pd_buf = pd_req->buffer;
+       pd_buf = bio_data(pd_req->bio);
        spin_unlock_irqrestore(&pd_lock, saved_flags);
        return 0;
 }
index f5c86d523ba0c8fe3a6154737f010246d67540d0..9a15fd3c9349403a19c518e278cf547d63733504 100644 (file)
@@ -795,7 +795,7 @@ repeat:
        }
 
        pf_cmd = rq_data_dir(pf_req);
-       pf_buf = pf_req->buffer;
+       pf_buf = bio_data(pf_req->bio);
        pf_retries = 0;
 
        pf_busy = 1;
@@ -827,7 +827,7 @@ static int pf_next_buf(void)
                if (!pf_req)
                        return 1;
                pf_count = blk_rq_cur_sectors(pf_req);
-               pf_buf = pf_req->buffer;
+               pf_buf = bio_data(pf_req->bio);
        }
        return 0;
 }
index a69dd93d1bd553d0b756407ea9cbb83df4f22c88..608532d3f8c910111093c2125e3aa385dbf2e604 100644 (file)
@@ -563,7 +563,6 @@ skd_prep_discard_cdb(struct skd_scsi_request *scsi_req,
 
        req = skreq->req;
        blk_add_request_payload(req, page, len);
-       req->buffer = buf;
 }
 
 static void skd_request_fn_not_online(struct request_queue *q);
@@ -744,6 +743,7 @@ static void skd_request_fn(struct request_queue *q)
                                break;
                        }
                        skreq->discard_page = 1;
+                       req->completion_data = page;
                        skd_prep_discard_cdb(scsi_req, skreq, page, lba, count);
 
                } else if (flush == SKD_FLUSH_ZERO_SIZE_FIRST) {
@@ -858,8 +858,7 @@ static void skd_end_request(struct skd_device *skdev,
                (skreq->discard_page == 1)) {
                pr_debug("%s:%s:%d, free the page!",
                         skdev->name, __func__, __LINE__);
-               free_page((unsigned long)req->buffer);
-               req->buffer = NULL;
+               __free_page(req->completion_data);
        }
 
        if (unlikely(error)) {
@@ -3945,15 +3944,14 @@ static int skd_acquire_msix(struct skd_device *skdev)
        for (i = 0; i < SKD_MAX_MSIX_COUNT; i++)
                entries[i].entry = i;
 
-       rc = pci_enable_msix_range(pdev, entries,
-                                  SKD_MIN_MSIX_COUNT, SKD_MAX_MSIX_COUNT);
-       if (rc < 0) {
+       rc = pci_enable_msix_exact(pdev, entries, SKD_MAX_MSIX_COUNT);
+       if (rc) {
                pr_err("(%s): failed to enable MSI-X %d\n",
                       skd_name(skdev), rc);
                goto msix_out;
        }
 
-       skdev->msix_count = rc;
+       skdev->msix_count = SKD_MAX_MSIX_COUNT;
        skdev->msix_entries = kzalloc(sizeof(struct skd_msix_entry) *
                                      skdev->msix_count, GFP_KERNEL);
        if (!skdev->msix_entries) {
index b02d53a399f37818f58950fd50e2184b43c216ba..6b44bbe528b7b1089296f52d54d9c6aa8ed90f81 100644 (file)
@@ -549,7 +549,7 @@ static void redo_fd_request(struct request_queue *q)
                case READ:
                        err = floppy_read_sectors(fs, blk_rq_pos(req),
                                                  blk_rq_cur_sectors(req),
-                                                 req->buffer);
+                                                 bio_data(req->bio));
                        break;
                }
        done:
index c74f7b56e7c40106ddd5ebde357d161cf7929361..523ee8fd4c150e7671ab776368e8a0a017d3287e 100644 (file)
@@ -342,7 +342,7 @@ static void start_request(struct floppy_state *fs)
                swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n",
                          req->rq_disk->disk_name, req->cmd,
                          (long)blk_rq_pos(req), blk_rq_sectors(req),
-                         req->buffer);
+                         bio_data(req->bio));
                swim3_dbg("           errors=%d current_nr_sectors=%u\n",
                          req->errors, blk_rq_cur_sectors(req));
 #endif
@@ -479,11 +479,11 @@ static inline void setup_transfer(struct floppy_state *fs)
                /* Set up 3 dma commands: write preamble, data, postamble */
                init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble));
                ++cp;
-               init_dma(cp, OUTPUT_MORE, req->buffer, 512);
+               init_dma(cp, OUTPUT_MORE, bio_data(req->bio), 512);
                ++cp;
                init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble));
        } else {
-               init_dma(cp, INPUT_LAST, req->buffer, n * 512);
+               init_dma(cp, INPUT_LAST, bio_data(req->bio), n * 512);
        }
        ++cp;
        out_le16(&cp->command, DBDMA_STOP);
index 6d8a87f252de563f1251872e5bccbd25e2e64cf7..7a51f065edcd94b685b0921689a7efa548f69f75 100644 (file)
@@ -30,6 +30,9 @@ struct virtio_blk
        /* The disk structure for the kernel. */
        struct gendisk *disk;
 
+       /* Block layer tags. */
+       struct blk_mq_tag_set tag_set;
+
        /* Process context for config space updates */
        struct work_struct config_work;
 
@@ -112,7 +115,7 @@ static int __virtblk_add_req(struct virtqueue *vq,
 
 static inline void virtblk_request_done(struct request *req)
 {
-       struct virtblk_req *vbr = req->special;
+       struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
        int error = virtblk_result(vbr);
 
        if (req->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -148,13 +151,13 @@ static void virtblk_done(struct virtqueue *vq)
 
        /* In case queue is stopped waiting for more buffers. */
        if (req_done)
-               blk_mq_start_stopped_hw_queues(vblk->disk->queue);
+               blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
 }
 
 static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
 {
        struct virtio_blk *vblk = hctx->queue->queuedata;
-       struct virtblk_req *vbr = req->special;
+       struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
        unsigned long flags;
        unsigned int num;
        const bool last = (req->cmd_flags & REQ_END) != 0;
@@ -480,32 +483,28 @@ static const struct device_attribute dev_attr_cache_type_rw =
        __ATTR(cache_type, S_IRUGO|S_IWUSR,
               virtblk_cache_type_show, virtblk_cache_type_store);
 
+static int virtblk_init_request(void *data, struct request *rq,
+               unsigned int hctx_idx, unsigned int request_idx,
+               unsigned int numa_node)
+{
+       struct virtio_blk *vblk = data;
+       struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq);
+
+       sg_init_table(vbr->sg, vblk->sg_elems);
+       return 0;
+}
+
 static struct blk_mq_ops virtio_mq_ops = {
        .queue_rq       = virtio_queue_rq,
        .map_queue      = blk_mq_map_queue,
        .alloc_hctx     = blk_mq_alloc_single_hw_queue,
        .free_hctx      = blk_mq_free_single_hw_queue,
        .complete       = virtblk_request_done,
+       .init_request   = virtblk_init_request,
 };
 
-static struct blk_mq_reg virtio_mq_reg = {
-       .ops            = &virtio_mq_ops,
-       .nr_hw_queues   = 1,
-       .queue_depth    = 0, /* Set in virtblk_probe */
-       .numa_node      = NUMA_NO_NODE,
-       .flags          = BLK_MQ_F_SHOULD_MERGE,
-};
-module_param_named(queue_depth, virtio_mq_reg.queue_depth, uint, 0444);
-
-static int virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
-                            struct request *rq, unsigned int nr)
-{
-       struct virtio_blk *vblk = data;
-       struct virtblk_req *vbr = rq->special;
-
-       sg_init_table(vbr->sg, vblk->sg_elems);
-       return 0;
-}
+static unsigned int virtblk_queue_depth;
+module_param_named(queue_depth, virtblk_queue_depth, uint, 0444);
 
 static int virtblk_probe(struct virtio_device *vdev)
 {
@@ -561,24 +560,34 @@ static int virtblk_probe(struct virtio_device *vdev)
        }
 
        /* Default queue sizing is to fill the ring. */
-       if (!virtio_mq_reg.queue_depth) {
-               virtio_mq_reg.queue_depth = vblk->vq->num_free;
+       if (!virtblk_queue_depth) {
+               virtblk_queue_depth = vblk->vq->num_free;
                /* ... but without indirect descs, we use 2 descs per req */
                if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
-                       virtio_mq_reg.queue_depth /= 2;
+                       virtblk_queue_depth /= 2;
        }
-       virtio_mq_reg.cmd_size =
+
+       memset(&vblk->tag_set, 0, sizeof(vblk->tag_set));
+       vblk->tag_set.ops = &virtio_mq_ops;
+       vblk->tag_set.nr_hw_queues = 1;
+       vblk->tag_set.queue_depth = virtblk_queue_depth;
+       vblk->tag_set.numa_node = NUMA_NO_NODE;
+       vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+       vblk->tag_set.cmd_size =
                sizeof(struct virtblk_req) +
                sizeof(struct scatterlist) * sg_elems;
+       vblk->tag_set.driver_data = vblk;
 
-       q = vblk->disk->queue = blk_mq_init_queue(&virtio_mq_reg, vblk);
+       err = blk_mq_alloc_tag_set(&vblk->tag_set);
+       if (err)
+               goto out_put_disk;
+
+       q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
        if (!q) {
                err = -ENOMEM;
-               goto out_put_disk;
+               goto out_free_tags;
        }
 
-       blk_mq_init_commands(q, virtblk_init_vbr, vblk);
-
        q->queuedata = vblk;
 
        virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN);
@@ -679,6 +688,8 @@ static int virtblk_probe(struct virtio_device *vdev)
 out_del_disk:
        del_gendisk(vblk->disk);
        blk_cleanup_queue(vblk->disk->queue);
+out_free_tags:
+       blk_mq_free_tag_set(&vblk->tag_set);
 out_put_disk:
        put_disk(vblk->disk);
 out_free_vq:
@@ -705,6 +716,8 @@ static void virtblk_remove(struct virtio_device *vdev)
        del_gendisk(vblk->disk);
        blk_cleanup_queue(vblk->disk->queue);
 
+       blk_mq_free_tag_set(&vblk->tag_set);
+
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
@@ -749,7 +762,7 @@ static int virtblk_restore(struct virtio_device *vdev)
        vblk->config_enable = true;
        ret = init_vq(vdev->priv);
        if (!ret)
-               blk_mq_start_stopped_hw_queues(vblk->disk->queue);
+               blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
 
        return ret;
 }
index efe1b4761735a79faa30867ad625fdd51e043081..283a30e88287b6bbec1be6b683a87d52fc997b59 100644 (file)
@@ -612,10 +612,10 @@ static void do_blkif_request(struct request_queue *rq)
                }
 
                pr_debug("do_blk_req %p: cmd %p, sec %lx, "
-                        "(%u/%u) buffer:%p [%s]\n",
+                        "(%u/%u) [%s]\n",
                         req, req->cmd, (unsigned long)blk_rq_pos(req),
                         blk_rq_cur_sectors(req), blk_rq_sectors(req),
-                        req->buffer, rq_data_dir(req) ? "write" : "read");
+                        rq_data_dir(req) ? "write" : "read");
 
                if (blkif_queue_request(req)) {
                        blk_requeue_request(rq, req);
index 1393b8871a281a82ef4e613fc096ce4f0e933cfa..ab3ea62e5dfc70dc0e62488290688f468d69cbcc 100644 (file)
@@ -661,7 +661,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
                        rq_data_dir(req));
 
                ace->req = req;
-               ace->data_ptr = req->buffer;
+               ace->data_ptr = bio_data(req->bio);
                ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR;
                ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF);
 
@@ -733,7 +733,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
                         *      blk_rq_sectors(ace->req),
                         *      blk_rq_cur_sectors(ace->req));
                         */
-                       ace->data_ptr = ace->req->buffer;
+                       ace->data_ptr = bio_data(ace->req->bio);
                        ace->data_count = blk_rq_cur_sectors(ace->req) * 16;
                        ace_fsm_yieldirq(ace);
                        break;
index 27de5046708a233cbc99e42a4349387f9f5157cb..968f9e52effa8c401a66e11b4de8bae9f23756ec 100644 (file)
@@ -87,13 +87,15 @@ static void do_z2_request(struct request_queue *q)
                while (len) {
                        unsigned long addr = start & Z2RAM_CHUNKMASK;
                        unsigned long size = Z2RAM_CHUNKSIZE - addr;
+                       void *buffer = bio_data(req->bio);
+
                        if (len < size)
                                size = len;
                        addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ];
                        if (rq_data_dir(req) == READ)
-                               memcpy(req->buffer, (char *)addr, size);
+                               memcpy(buffer, (char *)addr, size);
                        else
-                               memcpy((char *)addr, req->buffer, size);
+                               memcpy((char *)addr, buffer, size);
                        start += size;
                        len -= size;
                }
index be571fef185da6a597fcdac3d15093ed8e47fb5b..a83b57e57b6370572d53325638355a0d94ce24bf 100644 (file)
@@ -82,6 +82,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x3004) },
        { USB_DEVICE(0x04CA, 0x3005) },
        { USB_DEVICE(0x04CA, 0x3006) },
+       { USB_DEVICE(0x04CA, 0x3007) },
        { USB_DEVICE(0x04CA, 0x3008) },
        { USB_DEVICE(0x04CA, 0x300b) },
        { USB_DEVICE(0x0930, 0x0219) },
@@ -131,6 +132,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
index 7399303d7d9978447ff722d823c1dcece408029a..dc79f88f8717f478c8d8ab6d0a7d45849f772ac1 100644 (file)
@@ -59,6 +59,8 @@ struct btmrvl_device {
 };
 
 struct btmrvl_adapter {
+       void *hw_regs_buf;
+       u8 *hw_regs;
        u32 int_count;
        struct sk_buff_head tx_queue;
        u8 psmode;
@@ -140,7 +142,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv);
 bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
 int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
 
-int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd);
 int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
 int btmrvl_enable_ps(struct btmrvl_private *priv);
 int btmrvl_prepare_command(struct btmrvl_private *priv);
index 2c4997ce248484703a1b859c5e518396fcdbfa64..e9dbddb0b8f1efb1f15ede65f50d80390ca370c3 100644 (file)
@@ -24,6 +24,7 @@
 #include <net/bluetooth/hci_core.h>
 
 #include "btmrvl_drv.h"
+#include "btmrvl_sdio.h"
 
 #define VERSION "1.0"
 
@@ -201,7 +202,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
        return 0;
 }
 
-int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
 {
        int ret;
 
@@ -337,10 +338,25 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
 
 static void btmrvl_init_adapter(struct btmrvl_private *priv)
 {
+       int buf_size;
+
        skb_queue_head_init(&priv->adapter->tx_queue);
 
        priv->adapter->ps_state = PS_AWAKE;
 
+       buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN);
+       priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!priv->adapter->hw_regs_buf) {
+               priv->adapter->hw_regs = NULL;
+               BT_ERR("Unable to allocate buffer for hw_regs.");
+       } else {
+               priv->adapter->hw_regs =
+                       (u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf,
+                                        BTSDIO_DMA_ALIGN);
+               BT_DBG("hw_regs_buf=%p hw_regs=%p",
+                      priv->adapter->hw_regs_buf, priv->adapter->hw_regs);
+       }
+
        init_waitqueue_head(&priv->adapter->cmd_wait_q);
 }
 
@@ -348,6 +364,7 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv)
 {
        skb_queue_purge(&priv->adapter->tx_queue);
 
+       kfree(priv->adapter->hw_regs_buf);
        kfree(priv->adapter);
 
        priv->adapter = NULL;
index 1b52c9f5230d324d0476a2d7dd3f308e7fd723d8..9dedca516ff50567a278fb9a511dbcdfd7a1980c 100644 (file)
@@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
        .io_port_0 = 0x00,
        .io_port_1 = 0x01,
        .io_port_2 = 0x02,
+       .int_read_to_clear = false,
 };
 static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
        .cfg = 0x00,
@@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
        .io_port_0 = 0x78,
        .io_port_1 = 0x79,
        .io_port_2 = 0x7a,
+       .int_read_to_clear = false,
 };
 
 static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
@@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
        .io_port_0 = 0xd8,
        .io_port_1 = 0xd9,
        .io_port_2 = 0xda,
+       .int_read_to_clear = true,
+       .host_int_rsr = 0x01,
+       .card_misc_cfg = 0xcc,
 };
 
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
@@ -667,46 +672,78 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
        return 0;
 }
 
-static void btmrvl_sdio_interrupt(struct sdio_func *func)
+static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
 {
-       struct btmrvl_private *priv;
-       struct btmrvl_sdio_card *card;
-       ulong flags;
-       u8 ireg = 0;
+       struct btmrvl_adapter *adapter = card->priv->adapter;
        int ret;
 
-       card = sdio_get_drvdata(func);
-       if (!card || !card->priv) {
-               BT_ERR("sbi_interrupt(%p) card or priv is "
-                               "NULL, card=%p\n", func, card);
-               return;
+       ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE);
+       if (ret) {
+               BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret);
+               return ret;
        }
 
-       priv = card->priv;
+       *ireg = adapter->hw_regs[card->reg->host_intstatus];
+       BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg);
+
+       return 0;
+}
 
-       ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
+static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
+{
+       int ret;
+
+       *ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
        if (ret) {
-               BT_ERR("sdio_readb: read int status register failed");
-               return;
+               BT_ERR("sdio_readb: read int status failed: %d", ret);
+               return ret;
        }
 
-       if (ireg != 0) {
+       if (*ireg) {
                /*
                 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
                 * Clear the interrupt status register and re-enable the
                 * interrupt.
                 */
-               BT_DBG("ireg = 0x%x", ireg);
+               BT_DBG("int_status = 0x%x", *ireg);
 
-               sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
-                                       UP_LD_HOST_INT_STATUS),
-                               card->reg->host_intstatus, &ret);
+               sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS |
+                                                   UP_LD_HOST_INT_STATUS),
+                           card->reg->host_intstatus, &ret);
                if (ret) {
-                       BT_ERR("sdio_writeb: clear int status register failed");
-                       return;
+                       BT_ERR("sdio_writeb: clear int status failed: %d", ret);
+                       return ret;
                }
        }
 
+       return 0;
+}
+
+static void btmrvl_sdio_interrupt(struct sdio_func *func)
+{
+       struct btmrvl_private *priv;
+       struct btmrvl_sdio_card *card;
+       ulong flags;
+       u8 ireg = 0;
+       int ret;
+
+       card = sdio_get_drvdata(func);
+       if (!card || !card->priv) {
+               BT_ERR("sbi_interrupt(%p) card or priv is "
+                               "NULL, card=%p\n", func, card);
+               return;
+       }
+
+       priv = card->priv;
+
+       if (card->reg->int_read_to_clear)
+               ret = btmrvl_sdio_read_to_clear(card, &ireg);
+       else
+               ret = btmrvl_sdio_write_to_clear(card, &ireg);
+
+       if (ret)
+               return;
+
        spin_lock_irqsave(&priv->driver_lock, flags);
        sdio_ireg |= ireg;
        spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
 
        BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
 
+       if (card->reg->int_read_to_clear) {
+               reg = sdio_readb(func, card->reg->host_int_rsr, &ret);
+               if (ret < 0) {
+                       ret = -EIO;
+                       goto release_irq;
+               }
+               sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret);
+               if (ret < 0) {
+                       ret = -EIO;
+                       goto release_irq;
+               }
+
+               reg = sdio_readb(func, card->reg->card_misc_cfg, &ret);
+               if (ret < 0) {
+                       ret = -EIO;
+                       goto release_irq;
+               }
+               sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret);
+               if (ret < 0) {
+                       ret = -EIO;
+                       goto release_irq;
+               }
+       }
+
        sdio_set_drvdata(func, card);
 
        sdio_release_host(func);
index 43d35a609ca9a94795afb731d230fa88ca109bef..d4dd3b0fa53d16d68da0101494e43ca4664716c2 100644 (file)
@@ -78,6 +78,9 @@ struct btmrvl_sdio_card_reg {
        u8 io_port_0;
        u8 io_port_1;
        u8 io_port_2;
+       bool int_read_to_clear;
+       u8 host_int_rsr;
+       u8 card_misc_cfg;
 };
 
 struct btmrvl_sdio_card {
index f338b0c5a8de507a153b6761886b943c702176a4..a7dfbf9a3afb6be53e372f78d9ee8202bdb17d08 100644 (file)
@@ -152,6 +152,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
@@ -1485,10 +1486,8 @@ static int btusb_probe(struct usb_interface *intf,
        if (id->driver_info & BTUSB_BCM92035)
                hdev->setup = btusb_setup_bcm92035;
 
-       if (id->driver_info & BTUSB_INTEL) {
-               usb_enable_autosuspend(data->udev);
+       if (id->driver_info & BTUSB_INTEL)
                hdev->setup = btusb_setup_intel;
-       }
 
        /* Interface numbers are hardcoded in the specification */
        data->isoc = usb_ifnum_to_if(data->udev, 1);
index 7048a583fe51a695a044ad541a0f894e3bf7c510..66db9a803373efb92c8966c9f69fdb6b8ec7aa59 100644 (file)
@@ -55,13 +55,6 @@ struct h4_struct {
        struct sk_buff_head txq;
 };
 
-/* H4 receiver States */
-#define H4_W4_PACKET_TYPE      0
-#define H4_W4_EVENT_HDR                1
-#define H4_W4_ACL_HDR          2
-#define H4_W4_SCO_HDR          3
-#define H4_W4_DATA             4
-
 /* Initialize protocol */
 static int h4_open(struct hci_uart *hu)
 {
index 293e2e0a0a87c7d9877c27524fd98503ba16c1cf..26c3779d871da61ee7976dbfc180eb6ac2999b14 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/debugfs.h>
+#include <linux/log2.h>
 
 /*
  * DDR target is the same on all platforms.
@@ -222,12 +223,6 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
                 */
                if ((u64)base < wend && end > wbase)
                        return 0;
-
-               /*
-                * Check if target/attribute conflicts
-                */
-               if (target == wtarget && attr == wattr)
-                       return 0;
        }
 
        return 1;
@@ -266,6 +261,17 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
                mbus->soc->win_cfg_offset(win);
        u32 ctrl, remap_addr;
 
+       if (!is_power_of_2(size)) {
+               WARN(true, "Invalid MBus window size: 0x%zx\n", size);
+               return -EINVAL;
+       }
+
+       if ((base & (phys_addr_t)(size - 1)) != 0) {
+               WARN(true, "Invalid MBus base/size: %pa len 0x%zx\n", &base,
+                    size);
+               return -EINVAL;
+       }
+
        ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
                (attr << WIN_CTRL_ATTR_SHIFT)    |
                (target << WIN_CTRL_TGT_SHIFT)   |
@@ -413,6 +419,10 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v)
                           win, (unsigned long long)wbase,
                           (unsigned long long)(wbase + wsize), wtarget, wattr);
 
+               if (!is_power_of_2(wsize) ||
+                   ((wbase & (u64)(wsize - 1)) != 0))
+                       seq_puts(seq, " (Invalid base/size!!)");
+
                if (win < mbus->soc->num_remappable_wins) {
                        seq_printf(seq, " (remap %016llx)\n",
                                   (unsigned long long)wremap);
@@ -694,7 +704,6 @@ 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);
@@ -707,12 +716,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
                return -ENOMEM;
        }
 
-       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);
 
@@ -882,7 +885,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
        }
 }
 
-int __init mvebu_mbus_dt_init(void)
+int __init mvebu_mbus_dt_init(bool is_coherent)
 {
        struct resource mbuswins_res, sdramwins_res;
        struct device_node *np, *controller;
@@ -920,6 +923,8 @@ int __init mvebu_mbus_dt_init(void)
                return -EINVAL;
        }
 
+       mbus_state.hw_io_coherency = is_coherent;
+
        /* Get optional pcie-{mem,io}-aperture properties */
        mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture,
                                          &mbus_state.pcie_io_aperture);
index 8a3aff724d989c331f5de1596f3064cbbe72c271..49ac5662585b8d665ab6b6b6b659f2984e7bc5ad 100644 (file)
@@ -312,36 +312,24 @@ static const char *mrw_format_status[] = {
 
 static const char *mrw_address_space[] = { "DMA", "GAA" };
 
-#if (ERRLOGMASK!=CD_NOTHING)
-#define cdinfo(type, fmt, args...)                     \
+#if (ERRLOGMASK != CD_NOTHING)
+#define cd_dbg(type, fmt, ...)                         \
 do {                                                   \
        if ((ERRLOGMASK & type) || debug == 1)          \
-               pr_info(fmt, ##args);                   \
+               pr_debug(fmt, ##__VA_ARGS__);           \
 } while (0)
 #else
-#define cdinfo(type, fmt, args...)                     \
+#define cd_dbg(type, fmt, ...)                         \
 do {                                                   \
        if (0 && (ERRLOGMASK & type) || debug == 1)     \
-               pr_info(fmt, ##args);                   \
+               pr_debug(fmt, ##__VA_ARGS__);           \
 } while (0)
 #endif
 
-/* These are used to simplify getting data in from and back to user land */
-#define IOCTL_IN(arg, type, in)                                        \
-       if (copy_from_user(&(in), (type __user *) (arg), sizeof (in)))  \
-               return -EFAULT;
-
-#define IOCTL_OUT(arg, type, out) \
-       if (copy_to_user((type __user *) (arg), &(out), sizeof (out)))  \
-               return -EFAULT;
-
 /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in
    a lot of places. This macro makes the code more clear. */
 #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type))
 
-/* used in the audio ioctls */
-#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
-
 /*
  * Another popular OS uses 7 seconds as the hard timeout for default
  * commands, so it is a good choice for us as well.
@@ -349,21 +337,6 @@ do {                                                       \
 #define CDROM_DEF_TIMEOUT      (7 * HZ)
 
 /* Not-exported routines. */
-static int open_for_data(struct cdrom_device_info * cdi);
-static int check_for_audio_disc(struct cdrom_device_info * cdi,
-                        struct cdrom_device_ops * cdo);
-static void sanitize_format(union cdrom_addr *addr, 
-               u_char * curr, u_char requested);
-static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-                    unsigned long arg);
-
-int cdrom_get_last_written(struct cdrom_device_info *, long *);
-static int cdrom_get_next_writable(struct cdrom_device_info *, long *);
-static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*);
-
-static int cdrom_mrw_exit(struct cdrom_device_info *cdi);
-
-static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di);
 
 static void cdrom_sysctl_register(void);
 
@@ -382,113 +355,65 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
        return -EIO;
 }
 
-/* This macro makes sure we don't have to check on cdrom_device_ops
- * existence in the run-time routines below. Change_capability is a
- * hack to have the capability flags defined const, while we can still
- * change it here without gcc complaining at every line.
- */
-#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
-
-int register_cdrom(struct cdrom_device_info *cdi)
-{
-       static char banner_printed;
-        struct cdrom_device_ops *cdo = cdi->ops;
-        int *change_capability = (int *)&cdo->capability; /* hack */
-
-       cdinfo(CD_OPEN, "entering register_cdrom\n"); 
-
-       if (cdo->open == NULL || cdo->release == NULL)
-               return -EINVAL;
-       if (!banner_printed) {
-               pr_info("Uniform CD-ROM driver " REVISION "\n");
-               banner_printed = 1;
-               cdrom_sysctl_register();
-       }
-
-       ENSURE(drive_status, CDC_DRIVE_STATUS );
-       if (cdo->check_events == NULL && cdo->media_changed == NULL)
-               *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
-       ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
-       ENSURE(lock_door, CDC_LOCK);
-       ENSURE(select_speed, CDC_SELECT_SPEED);
-       ENSURE(get_last_session, CDC_MULTI_SESSION);
-       ENSURE(get_mcn, CDC_MCN);
-       ENSURE(reset, CDC_RESET);
-       ENSURE(generic_packet, CDC_GENERIC_PACKET);
-       cdi->mc_flags = 0;
-       cdo->n_minors = 0;
-        cdi->options = CDO_USE_FFLAGS;
-       
-       if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY))
-               cdi->options |= (int) CDO_AUTO_CLOSE;
-       if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY))
-               cdi->options |= (int) CDO_AUTO_EJECT;
-       if (lockdoor==1)
-               cdi->options |= (int) CDO_LOCK;
-       if (check_media_type==1)
-               cdi->options |= (int) CDO_CHECK_TYPE;
-
-       if (CDROM_CAN(CDC_MRW_W))
-               cdi->exit = cdrom_mrw_exit;
-
-       if (cdi->disk)
-               cdi->cdda_method = CDDA_BPC_FULL;
-       else
-               cdi->cdda_method = CDDA_OLD;
-
-       if (!cdo->generic_packet)
-               cdo->generic_packet = cdrom_dummy_generic_packet;
-
-       cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
-       mutex_lock(&cdrom_mutex);
-       list_add(&cdi->list, &cdrom_list);
-       mutex_unlock(&cdrom_mutex);
-       return 0;
-}
-#undef ENSURE
-
-void unregister_cdrom(struct cdrom_device_info *cdi)
+static int cdrom_flush_cache(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
+       struct packet_command cgc;
 
-       mutex_lock(&cdrom_mutex);
-       list_del(&cdi->list);
-       mutex_unlock(&cdrom_mutex);
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+       cgc.cmd[0] = GPCMD_FLUSH_CACHE;
 
-       if (cdi->exit)
-               cdi->exit(cdi);
+       cgc.timeout = 5 * 60 * HZ;
 
-       cdi->ops->n_minors--;
-       cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
+       return cdi->ops->generic_packet(cdi, &cgc);
 }
 
-int cdrom_get_media_event(struct cdrom_device_info *cdi,
-                         struct media_event_desc *med)
+/* requires CD R/RW */
+static int cdrom_get_disc_info(struct cdrom_device_info *cdi,
+                              disc_information *di)
 {
+       struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
-       unsigned char buffer[8];
-       struct event_header *eh = (struct event_header *) buffer;
+       int ret, buflen;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
-       cgc.cmd[1] = 1;         /* IMMED */
-       cgc.cmd[4] = 1 << 4;    /* media event */
-       cgc.cmd[8] = sizeof(buffer);
+       /* set up command and get the disc info */
+       init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_READ_DISC_INFO;
+       cgc.cmd[8] = cgc.buflen = 2;
        cgc.quiet = 1;
 
-       if (cdi->ops->generic_packet(cdi, &cgc))
-               return 1;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
 
-       if (be16_to_cpu(eh->data_len) < sizeof(*med))
-               return 1;
+       /* not all drives have the same disc_info length, so requeue
+        * packet with the length the drive tells us it can supply
+        */
+       buflen = be16_to_cpu(di->disc_information_length) +
+               sizeof(di->disc_information_length);
 
-       if (eh->nea || eh->notification_class != 0x4)
-               return 1;
+       if (buflen > sizeof(disc_information))
+               buflen = sizeof(disc_information);
 
-       memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
-       return 0;
+       cgc.cmd[8] = cgc.buflen = buflen;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
+
+       /* return actual fill size */
+       return buflen;
 }
 
+/* This macro makes sure we don't have to check on cdrom_device_ops
+ * existence in the run-time routines below. Change_capability is a
+ * hack to have the capability flags defined const, while we can still
+ * change it here without gcc complaining at every line.
+ */
+#define ENSURE(call, bits)                     \
+do {                                           \
+       if (cdo->call == NULL)                  \
+               *change_capability &= ~(bits);  \
+} while (0)
+
 /*
  * the first prototypes used 0x2c as the page code for the mrw mode page,
  * subsequently this was changed to 0x03. probe the one used by this drive
@@ -605,18 +530,6 @@ static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed)
        return cdi->ops->generic_packet(cdi, &cgc);
 }
 
-static int cdrom_flush_cache(struct cdrom_device_info *cdi)
-{
-       struct packet_command cgc;
-
-       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
-       cgc.cmd[0] = GPCMD_FLUSH_CACHE;
-
-       cgc.timeout = 5 * 60 * HZ;
-
-       return cdi->ops->generic_packet(cdi, &cgc);
-}
-
 static int cdrom_mrw_exit(struct cdrom_device_info *cdi)
 {
        disc_information di;
@@ -650,17 +563,19 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
        cgc.buffer = buffer;
        cgc.buflen = sizeof(buffer);
 
-       if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0)))
+       ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0);
+       if (ret)
                return ret;
 
-       mph = (struct mode_page_header *) buffer;
+       mph = (struct mode_page_header *)buffer;
        offset = be16_to_cpu(mph->desc_length);
        size = be16_to_cpu(mph->mode_data_length) + 2;
 
        buffer[offset + 3] = space;
        cgc.buflen = size;
 
-       if ((ret = cdrom_mode_select(cdi, &cgc)))
+       ret = cdrom_mode_select(cdi, &cgc);
+       if (ret)
                return ret;
 
        pr_info("%s: mrw address space %s selected\n",
@@ -668,6 +583,106 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
        return 0;
 }
 
+int register_cdrom(struct cdrom_device_info *cdi)
+{
+       static char banner_printed;
+       struct cdrom_device_ops *cdo = cdi->ops;
+       int *change_capability = (int *)&cdo->capability; /* hack */
+
+       cd_dbg(CD_OPEN, "entering register_cdrom\n");
+
+       if (cdo->open == NULL || cdo->release == NULL)
+               return -EINVAL;
+       if (!banner_printed) {
+               pr_info("Uniform CD-ROM driver " REVISION "\n");
+               banner_printed = 1;
+               cdrom_sysctl_register();
+       }
+
+       ENSURE(drive_status, CDC_DRIVE_STATUS);
+       if (cdo->check_events == NULL && cdo->media_changed == NULL)
+               *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
+       ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+       ENSURE(lock_door, CDC_LOCK);
+       ENSURE(select_speed, CDC_SELECT_SPEED);
+       ENSURE(get_last_session, CDC_MULTI_SESSION);
+       ENSURE(get_mcn, CDC_MCN);
+       ENSURE(reset, CDC_RESET);
+       ENSURE(generic_packet, CDC_GENERIC_PACKET);
+       cdi->mc_flags = 0;
+       cdo->n_minors = 0;
+       cdi->options = CDO_USE_FFLAGS;
+
+       if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY))
+               cdi->options |= (int) CDO_AUTO_CLOSE;
+       if (autoeject == 1 && CDROM_CAN(CDC_OPEN_TRAY))
+               cdi->options |= (int) CDO_AUTO_EJECT;
+       if (lockdoor == 1)
+               cdi->options |= (int) CDO_LOCK;
+       if (check_media_type == 1)
+               cdi->options |= (int) CDO_CHECK_TYPE;
+
+       if (CDROM_CAN(CDC_MRW_W))
+               cdi->exit = cdrom_mrw_exit;
+
+       if (cdi->disk)
+               cdi->cdda_method = CDDA_BPC_FULL;
+       else
+               cdi->cdda_method = CDDA_OLD;
+
+       if (!cdo->generic_packet)
+               cdo->generic_packet = cdrom_dummy_generic_packet;
+
+       cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
+       mutex_lock(&cdrom_mutex);
+       list_add(&cdi->list, &cdrom_list);
+       mutex_unlock(&cdrom_mutex);
+       return 0;
+}
+#undef ENSURE
+
+void unregister_cdrom(struct cdrom_device_info *cdi)
+{
+       cd_dbg(CD_OPEN, "entering unregister_cdrom\n");
+
+       mutex_lock(&cdrom_mutex);
+       list_del(&cdi->list);
+       mutex_unlock(&cdrom_mutex);
+
+       if (cdi->exit)
+               cdi->exit(cdi);
+
+       cdi->ops->n_minors--;
+       cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
+}
+
+int cdrom_get_media_event(struct cdrom_device_info *cdi,
+                         struct media_event_desc *med)
+{
+       struct packet_command cgc;
+       unsigned char buffer[8];
+       struct event_header *eh = (struct event_header *)buffer;
+
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
+       cgc.cmd[1] = 1;         /* IMMED */
+       cgc.cmd[4] = 1 << 4;    /* media event */
+       cgc.cmd[8] = sizeof(buffer);
+       cgc.quiet = 1;
+
+       if (cdi->ops->generic_packet(cdi, &cgc))
+               return 1;
+
+       if (be16_to_cpu(eh->data_len) < sizeof(*med))
+               return 1;
+
+       if (eh->nea || eh->notification_class != 0x4)
+               return 1;
+
+       memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
+       return 0;
+}
+
 static int cdrom_get_random_writable(struct cdrom_device_info *cdi,
                              struct rwrt_feature_desc *rfd)
 {
@@ -839,7 +854,7 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
        else if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
                ret = !rfd.curr;
 
-       cdinfo(CD_OPEN, "can open for random write\n");
+       cd_dbg(CD_OPEN, "can open for random write\n");
        return ret;
 }
 
@@ -928,12 +943,12 @@ static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi)
        struct packet_command cgc;
 
        if (cdi->mmc3_profile != 0x1a) {
-               cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);
+               cd_dbg(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);
                return;
        }
 
        if (!cdi->media_written) {
-               cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);
+               cd_dbg(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);
                return;
        }
 
@@ -969,82 +984,74 @@ static int cdrom_close_write(struct cdrom_device_info *cdi)
 #endif
 }
 
-/* We use the open-option O_NONBLOCK to indicate that the
- * purpose of opening is only for subsequent ioctl() calls; no device
- * integrity checks are performed.
- *
- * We hope that all cd-player programs will adopt this convention. It
- * is in their own interest: device control becomes a lot easier
- * this way.
- */
-int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t mode)
+/* badly broken, I know. Is due for a fixup anytime. */
+static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks)
 {
-       int ret;
-
-       cdinfo(CD_OPEN, "entering cdrom_open\n"); 
-
-       /* open is event synchronization point, check events first */
-       check_disk_change(bdev);
-
-       /* if this was a O_NONBLOCK open and we should honor the flags,
-        * do a quick open without drive/disc integrity checks. */
-       cdi->use_count++;
-       if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) {
-               ret = cdi->ops->open(cdi, 1);
-       } else {
-               ret = open_for_data(cdi);
-               if (ret)
-                       goto err;
-               cdrom_mmc3_profile(cdi);
-               if (mode & FMODE_WRITE) {
-                       ret = -EROFS;
-                       if (cdrom_open_write(cdi))
-                               goto err_release;
-                       if (!CDROM_CAN(CDC_RAM))
-                               goto err_release;
-                       ret = 0;
-                       cdi->media_written = 0;
-               }
+       struct cdrom_tochdr header;
+       struct cdrom_tocentry entry;
+       int ret, i;
+       tracks->data = 0;
+       tracks->audio = 0;
+       tracks->cdi = 0;
+       tracks->xa = 0;
+       tracks->error = 0;
+       cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n");
+       /* Grab the TOC header so we can see how many tracks there are */
+       ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
+       if (ret) {
+               if (ret == -ENOMEDIUM)
+                       tracks->error = CDS_NO_DISC;
+               else
+                       tracks->error = CDS_NO_INFO;
+               return;
        }
-
-       if (ret)
-               goto err;
-
-       cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n",
-                       cdi->name, cdi->use_count);
-       return 0;
-err_release:
-       if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
-               cdi->ops->lock_door(cdi, 0);
-               cdinfo(CD_OPEN, "door unlocked.\n");
+       /* check what type of tracks are on this disc */
+       entry.cdte_format = CDROM_MSF;
+       for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) {
+               entry.cdte_track = i;
+               if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) {
+                       tracks->error = CDS_NO_INFO;
+                       return;
+               }
+               if (entry.cdte_ctrl & CDROM_DATA_TRACK) {
+                       if (entry.cdte_format == 0x10)
+                               tracks->cdi++;
+                       else if (entry.cdte_format == 0x20)
+                               tracks->xa++;
+                       else
+                               tracks->data++;
+               } else {
+                       tracks->audio++;
+               }
+               cd_dbg(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n",
+                      i, entry.cdte_format, entry.cdte_ctrl);
        }
-       cdi->ops->release(cdi);
-err:
-       cdi->use_count--;
-       return ret;
+       cd_dbg(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n",
+              header.cdth_trk1, tracks->audio, tracks->data,
+              tracks->cdi, tracks->xa);
 }
 
 static
-int open_for_data(struct cdrom_device_info * cdi)
+int open_for_data(struct cdrom_device_info *cdi)
 {
        int ret;
        struct cdrom_device_ops *cdo = cdi->ops;
        tracktype tracks;
-       cdinfo(CD_OPEN, "entering open_for_data\n");
+       cd_dbg(CD_OPEN, "entering open_for_data\n");
        /* Check if the driver can report drive status.  If it can, we
           can do clever things.  If it can't, well, we at least tried! */
        if (cdo->drive_status != NULL) {
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
-               cdinfo(CD_OPEN, "drive_status=%d\n", ret); 
+               cd_dbg(CD_OPEN, "drive_status=%d\n", ret);
                if (ret == CDS_TRAY_OPEN) {
-                       cdinfo(CD_OPEN, "the tray is open...\n"); 
+                       cd_dbg(CD_OPEN, "the tray is open...\n");
                        /* can/may i close it? */
                        if (CDROM_CAN(CDC_CLOSE_TRAY) &&
                            cdi->options & CDO_AUTO_CLOSE) {
-                               cdinfo(CD_OPEN, "trying to close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "trying to close the tray\n");
                                ret=cdo->tray_move(cdi,0);
                                if (ret) {
-                                       cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n"); 
+                                       cd_dbg(CD_OPEN, "bummer. tried to close the tray but failed.\n");
                                        /* Ignore the error from the low
                                        level driver.  We don't care why it
                                        couldn't close the tray.  We only care 
@@ -1054,19 +1061,19 @@ int open_for_data(struct cdrom_device_info * cdi)
                                        goto clean_up_and_return;
                                }
                        } else {
-                               cdinfo(CD_OPEN, "bummer. this drive can't close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. this drive can't close the tray.\n");
                                ret=-ENOMEDIUM;
                                goto clean_up_and_return;
                        }
                        /* Ok, the door should be closed now.. Check again */
                        ret = cdo->drive_status(cdi, CDSL_CURRENT);
                        if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
-                               cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 
-                               cdinfo(CD_OPEN, "tray might not contain a medium.\n");
+                               cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n");
+                               cd_dbg(CD_OPEN, "tray might not contain a medium\n");
                                ret=-ENOMEDIUM;
                                goto clean_up_and_return;
                        }
-                       cdinfo(CD_OPEN, "the tray is now closed.\n"); 
+                       cd_dbg(CD_OPEN, "the tray is now closed\n");
                }
                /* the door should be closed now, check for the disc */
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
@@ -1077,7 +1084,7 @@ int open_for_data(struct cdrom_device_info * cdi)
        }
        cdrom_count_tracks(cdi, &tracks);
        if (tracks.error == CDS_NO_DISC) {
-               cdinfo(CD_OPEN, "bummer. no disc.\n");
+               cd_dbg(CD_OPEN, "bummer. no disc.\n");
                ret=-ENOMEDIUM;
                goto clean_up_and_return;
        }
@@ -1087,34 +1094,34 @@ int open_for_data(struct cdrom_device_info * cdi)
                if (cdi->options & CDO_CHECK_TYPE) {
                    /* give people a warning shot, now that CDO_CHECK_TYPE
                       is the default case! */
-                   cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
-                   cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
-                                       (unsigned int)task_pid_nr(current));
+                   cd_dbg(CD_OPEN, "bummer. wrong media type.\n");
+                   cd_dbg(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
+                          (unsigned int)task_pid_nr(current));
                    ret=-EMEDIUMTYPE;
                    goto clean_up_and_return;
                }
                else {
-                   cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n");
+                   cd_dbg(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set\n");
                }
        }
 
-       cdinfo(CD_OPEN, "all seems well, opening the device.\n"); 
+       cd_dbg(CD_OPEN, "all seems well, opening the devicen");
 
        /* all seems well, we can open the device */
        ret = cdo->open(cdi, 0); /* open for data */
-       cdinfo(CD_OPEN, "opening the device gave me %d.\n", ret); 
+       cd_dbg(CD_OPEN, "opening the device gave me %d\n", ret);
        /* After all this careful checking, we shouldn't have problems
           opening the device, but we don't want the device locked if 
           this somehow fails... */
        if (ret) {
-               cdinfo(CD_OPEN, "open device failed.\n"); 
+               cd_dbg(CD_OPEN, "open device failed\n");
                goto clean_up_and_return;
        }
        if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) {
                        cdo->lock_door(cdi, 1);
-                       cdinfo(CD_OPEN, "door locked.\n");
+                       cd_dbg(CD_OPEN, "door locked\n");
        }
-       cdinfo(CD_OPEN, "device opened successfully.\n"); 
+       cd_dbg(CD_OPEN, "device opened successfully\n");
        return ret;
 
        /* Something failed.  Try to unlock the drive, because some drivers
@@ -1123,11 +1130,67 @@ int open_for_data(struct cdrom_device_info * cdi)
        This ensures that the drive gets unlocked after a mount fails.  This 
        is a goto to avoid bloating the driver with redundant code. */ 
 clean_up_and_return:
-       cdinfo(CD_OPEN, "open failed.\n"); 
+       cd_dbg(CD_OPEN, "open failed\n");
        if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
                        cdo->lock_door(cdi, 0);
-                       cdinfo(CD_OPEN, "door unlocked.\n");
+                       cd_dbg(CD_OPEN, "door unlocked\n");
+       }
+       return ret;
+}
+
+/* We use the open-option O_NONBLOCK to indicate that the
+ * purpose of opening is only for subsequent ioctl() calls; no device
+ * integrity checks are performed.
+ *
+ * We hope that all cd-player programs will adopt this convention. It
+ * is in their own interest: device control becomes a lot easier
+ * this way.
+ */
+int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev,
+              fmode_t mode)
+{
+       int ret;
+
+       cd_dbg(CD_OPEN, "entering cdrom_open\n");
+
+       /* open is event synchronization point, check events first */
+       check_disk_change(bdev);
+
+       /* if this was a O_NONBLOCK open and we should honor the flags,
+        * do a quick open without drive/disc integrity checks. */
+       cdi->use_count++;
+       if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) {
+               ret = cdi->ops->open(cdi, 1);
+       } else {
+               ret = open_for_data(cdi);
+               if (ret)
+                       goto err;
+               cdrom_mmc3_profile(cdi);
+               if (mode & FMODE_WRITE) {
+                       ret = -EROFS;
+                       if (cdrom_open_write(cdi))
+                               goto err_release;
+                       if (!CDROM_CAN(CDC_RAM))
+                               goto err_release;
+                       ret = 0;
+                       cdi->media_written = 0;
+               }
+       }
+
+       if (ret)
+               goto err;
+
+       cd_dbg(CD_OPEN, "Use count for \"/dev/%s\" now %d\n",
+              cdi->name, cdi->use_count);
+       return 0;
+err_release:
+       if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
+               cdi->ops->lock_door(cdi, 0);
+               cd_dbg(CD_OPEN, "door unlocked\n");
        }
+       cdi->ops->release(cdi);
+err:
+       cdi->use_count--;
        return ret;
 }
 
@@ -1139,21 +1202,21 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
 {
         int ret;
        tracktype tracks;
-       cdinfo(CD_OPEN, "entering check_for_audio_disc\n");
+       cd_dbg(CD_OPEN, "entering check_for_audio_disc\n");
        if (!(cdi->options & CDO_CHECK_TYPE))
                return 0;
        if (cdo->drive_status != NULL) {
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
-               cdinfo(CD_OPEN, "drive_status=%d\n", ret); 
+               cd_dbg(CD_OPEN, "drive_status=%d\n", ret);
                if (ret == CDS_TRAY_OPEN) {
-                       cdinfo(CD_OPEN, "the tray is open...\n"); 
+                       cd_dbg(CD_OPEN, "the tray is open...\n");
                        /* can/may i close it? */
                        if (CDROM_CAN(CDC_CLOSE_TRAY) &&
                            cdi->options & CDO_AUTO_CLOSE) {
-                               cdinfo(CD_OPEN, "trying to close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "trying to close the tray\n");
                                ret=cdo->tray_move(cdi,0);
                                if (ret) {
-                                       cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n"); 
+                                       cd_dbg(CD_OPEN, "bummer. tried to close tray but failed.\n");
                                        /* Ignore the error from the low
                                        level driver.  We don't care why it
                                        couldn't close the tray.  We only care 
@@ -1162,20 +1225,20 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
                                        return -ENOMEDIUM;
                                }
                        } else {
-                               cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. this driver can't close the tray.\n");
                                return -ENOMEDIUM;
                        }
                        /* Ok, the door should be closed now.. Check again */
                        ret = cdo->drive_status(cdi, CDSL_CURRENT);
                        if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
-                               cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n");
                                return -ENOMEDIUM;
                        }       
                        if (ret!=CDS_DISC_OK) {
-                               cdinfo(CD_OPEN, "bummer. disc isn't ready.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. disc isn't ready.\n");
                                return -EIO;
                        }       
-                       cdinfo(CD_OPEN, "the tray is now closed.\n"); 
+                       cd_dbg(CD_OPEN, "the tray is now closed\n");
                }       
        }
        cdrom_count_tracks(cdi, &tracks);
@@ -1193,17 +1256,18 @@ void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)
        struct cdrom_device_ops *cdo = cdi->ops;
        int opened_for_data;
 
-       cdinfo(CD_CLOSE, "entering cdrom_release\n");
+       cd_dbg(CD_CLOSE, "entering cdrom_release\n");
 
        if (cdi->use_count > 0)
                cdi->use_count--;
 
        if (cdi->use_count == 0) {
-               cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
+               cd_dbg(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n",
+                      cdi->name);
                cdrom_dvd_rw_close_write(cdi);
 
                if ((cdo->capability & CDC_LOCK) && !cdi->keeplocked) {
-                       cdinfo(CD_CLOSE, "Unlocking door!\n");
+                       cd_dbg(CD_CLOSE, "Unlocking door!\n");
                        cdo->lock_door(cdi, 0);
                }
        }
@@ -1262,7 +1326,7 @@ static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot)
        struct cdrom_changer_info *info;
        int ret;
 
-       cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_slot_status()\n");
        if (cdi->sanyo_slot)
                return CDS_NO_INFO;
        
@@ -1292,7 +1356,7 @@ int cdrom_number_of_slots(struct cdrom_device_info *cdi)
        int nslots = 1;
        struct cdrom_changer_info *info;
 
-       cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_number_of_slots()\n");
        /* cdrom_read_mech_status requires a valid value for capacity: */
        cdi->capacity = 0; 
 
@@ -1313,7 +1377,7 @@ static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot)
 {
        struct packet_command cgc;
 
-       cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_load_unload()\n");
        if (cdi->sanyo_slot && slot < 0)
                return 0;
 
@@ -1342,7 +1406,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
        int curslot;
        int ret;
 
-       cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_select_disc()\n");
        if (!CDROM_CAN(CDC_SELECT_DISC))
                return -EDRIVE_CANT_DO_THIS;
 
@@ -1476,51 +1540,6 @@ int cdrom_media_changed(struct cdrom_device_info *cdi)
        return media_changed(cdi, 0);
 }
 
-/* badly broken, I know. Is due for a fixup anytime. */
-static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks)
-{
-       struct cdrom_tochdr header;
-       struct cdrom_tocentry entry;
-       int ret, i;
-       tracks->data=0;
-       tracks->audio=0;
-       tracks->cdi=0;
-       tracks->xa=0;
-       tracks->error=0;
-       cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); 
-       /* Grab the TOC header so we can see how many tracks there are */
-       if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) {
-               if (ret == -ENOMEDIUM)
-                       tracks->error = CDS_NO_DISC;
-               else
-                       tracks->error = CDS_NO_INFO;
-               return;
-       }       
-       /* check what type of tracks are on this disc */
-       entry.cdte_format = CDROM_MSF;
-       for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) {
-               entry.cdte_track  = i;
-               if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) {
-                       tracks->error=CDS_NO_INFO;
-                       return;
-               }       
-               if (entry.cdte_ctrl & CDROM_DATA_TRACK) {
-                   if (entry.cdte_format == 0x10)
-                       tracks->cdi++;
-                   else if (entry.cdte_format == 0x20) 
-                       tracks->xa++;
-                   else
-                       tracks->data++;
-               } else
-                   tracks->audio++;
-               cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n",
-                      i, entry.cdte_format, entry.cdte_ctrl);
-       }       
-       cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", 
-               header.cdth_trk1, tracks->audio, tracks->data, 
-               tracks->cdi, tracks->xa);
-}      
-
 /* Requests to the low-level drivers will /always/ be done in the
    following format convention:
 
@@ -1632,7 +1651,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        switch (ai->type) {
        /* LU data send */
        case DVD_LU_SEND_AGID:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_AGID\n");
                cgc.quiet = 1;
                setup_report_key(&cgc, ai->lsa.agid, 0);
 
@@ -1644,7 +1663,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_LU_SEND_KEY1:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_KEY1\n");
                setup_report_key(&cgc, ai->lsk.agid, 2);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
@@ -1655,7 +1674,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_LU_SEND_CHALLENGE:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n");
                setup_report_key(&cgc, ai->lsc.agid, 1);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
@@ -1667,7 +1686,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* Post-auth key */
        case DVD_LU_SEND_TITLE_KEY:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n");
                cgc.quiet = 1;
                setup_report_key(&cgc, ai->lstk.agid, 4);
                cgc.cmd[5] = ai->lstk.lba;
@@ -1686,7 +1705,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_LU_SEND_ASF:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_ASF\n");
                setup_report_key(&cgc, ai->lsasf.agid, 5);
                
                if ((ret = cdo->generic_packet(cdi, &cgc)))
@@ -1697,7 +1716,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* LU data receive (LU changes state) */
        case DVD_HOST_SEND_CHALLENGE:
-               cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); 
+               cd_dbg(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n");
                setup_send_key(&cgc, ai->hsc.agid, 1);
                buf[1] = 0xe;
                copy_chal(&buf[4], ai->hsc.chal);
@@ -1709,7 +1728,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_HOST_SEND_KEY2:
-               cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); 
+               cd_dbg(CD_DVD, "entering DVD_HOST_SEND_KEY2\n");
                setup_send_key(&cgc, ai->hsk.agid, 3);
                buf[1] = 0xa;
                copy_key(&buf[4], ai->hsk.key);
@@ -1724,7 +1743,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        /* Misc */
        case DVD_INVALIDATE_AGID:
                cgc.quiet = 1;
-               cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); 
+               cd_dbg(CD_DVD, "entering DVD_INVALIDATE_AGID\n");
                setup_report_key(&cgc, ai->lsa.agid, 0x3f);
                if ((ret = cdo->generic_packet(cdi, &cgc)))
                        return ret;
@@ -1732,7 +1751,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* Get region settings */
        case DVD_LU_SEND_RPC_STATE:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
                setup_report_key(&cgc, 0, 8);
                memset(&rpc_state, 0, sizeof(rpc_state_t));
                cgc.buffer = (char *) &rpc_state;
@@ -1749,7 +1768,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* Set region settings */
        case DVD_HOST_SEND_RPC_STATE:
-               cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");
+               cd_dbg(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");
                setup_send_key(&cgc, 0, 6);
                buf[1] = 6;
                buf[4] = ai->hrpcs.pdrc;
@@ -1759,7 +1778,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        default:
-               cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
+               cd_dbg(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
                return -ENOTTY;
        }
 
@@ -1891,7 +1910,8 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s,
 
        s->bca.len = buf[0] << 8 | buf[1];
        if (s->bca.len < 12 || s->bca.len > 188) {
-               cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len);
+               cd_dbg(CD_WARNING, "Received invalid BCA length (%d)\n",
+                      s->bca.len);
                ret = -EIO;
                goto out;
        }
@@ -1927,14 +1947,13 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
 
        s->manufact.len = buf[0] << 8 | buf[1];
        if (s->manufact.len < 0) {
-               cdinfo(CD_WARNING, "Received invalid manufacture info length"
-                                  " (%d)\n", s->manufact.len);
+               cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d)\n",
+                      s->manufact.len);
                ret = -EIO;
        } else {
                if (s->manufact.len > 2048) {
-                       cdinfo(CD_WARNING, "Received invalid manufacture info "
-                                       "length (%d): truncating to 2048\n",
-                                       s->manufact.len);
+                       cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d): truncating to 2048\n",
+                              s->manufact.len);
                        s->manufact.len = 2048;
                }
                memcpy(s->manufact.value, &buf[4], s->manufact.len);
@@ -1965,8 +1984,8 @@ static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s,
                return dvd_read_manufact(cdi, s, cgc);
                
        default:
-               cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n",
-                                       s->type);
+               cd_dbg(CD_WARNING, ": Invalid DVD structure read requested (%d)\n",
+                      s->type);
                return -EINVAL;
        }
 }
@@ -2255,7 +2274,7 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
        u8 requested_format;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
 
        if (!(cdi->ops->capability & CDC_MULTI_SESSION))
                return -ENOSYS;
@@ -2277,13 +2296,13 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
        if (copy_to_user(argp, &ms_info, sizeof(ms_info)))
                return -EFAULT;
 
-       cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
+       cd_dbg(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
        return 0;
 }
 
 static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT\n");
 
        if (!CDROM_CAN(CDC_OPEN_TRAY))
                return -ENOSYS;
@@ -2300,7 +2319,7 @@ static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
 
 static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
 
        if (!CDROM_CAN(CDC_CLOSE_TRAY))
                return -ENOSYS;
@@ -2310,7 +2329,7 @@ static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
 static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
 
        if (!CDROM_CAN(CDC_OPEN_TRAY))
                return -ENOSYS;
@@ -2329,7 +2348,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
        struct cdrom_changer_info *info;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
 
        if (!CDROM_CAN(CDC_MEDIA_CHANGED))
                return -ENOSYS;
@@ -2355,7 +2374,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
 
        /*
         * Options need to be in sync with capability.
@@ -2383,7 +2402,7 @@ static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
 
        cdi->options &= ~(int) arg;
        return cdi->options;
@@ -2392,7 +2411,7 @@ static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
 
        if (!CDROM_CAN(CDC_SELECT_SPEED))
                return -ENOSYS;
@@ -2402,7 +2421,7 @@ static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
 
        if (!CDROM_CAN(CDC_SELECT_DISC))
                return -ENOSYS;
@@ -2420,14 +2439,14 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
        if (cdi->ops->select_disc)
                return cdi->ops->select_disc(cdi, arg);
 
-       cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
+       cd_dbg(CD_CHANGER, "Using generic cdrom_select_disc()\n");
        return cdrom_select_disc(cdi, arg);
 }
 
 static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
                struct block_device *bdev)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_RESET\n");
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -2440,7 +2459,7 @@ static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
+       cd_dbg(CD_DO_IOCTL, "%socking door\n", arg ? "L" : "Unl");
 
        if (!CDROM_CAN(CDC_LOCK))
                return -EDRIVE_CANT_DO_THIS;
@@ -2459,7 +2478,7 @@ static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
+       cd_dbg(CD_DO_IOCTL, "%sabling debug\n", arg ? "En" : "Dis");
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -2469,7 +2488,7 @@ static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
 
 static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
        return (cdi->ops->capability & ~cdi->mask);
 }
 
@@ -2485,7 +2504,7 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
        struct cdrom_mcn mcn;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
 
        if (!(cdi->ops->capability & CDC_MCN))
                return -ENOSYS;
@@ -2495,14 +2514,14 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &mcn, sizeof(mcn)))
                return -EFAULT;
-       cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
+       cd_dbg(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
        return 0;
 }
 
 static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
 
        if (!(cdi->ops->capability & CDC_DRIVE_STATUS))
                return -ENOSYS;
@@ -2535,7 +2554,7 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
 {
        tracktype tracks;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
 
        cdrom_count_tracks(cdi, &tracks);
        if (tracks.error)
@@ -2557,13 +2576,13 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
                return CDS_DATA_1;
        /* Policy mode off */
 
-       cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
+       cd_dbg(CD_WARNING, "This disc doesn't have any tracks I recognize!\n");
        return CDS_NO_INFO;
 }
 
 static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
        return cdi->capacity;
 }
 
@@ -2574,7 +2593,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
        u8 requested, back;
        int ret;
 
-       /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
+       /* cd_dbg(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
 
        if (copy_from_user(&q, argp, sizeof(q)))
                return -EFAULT;
@@ -2594,7 +2613,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &q, sizeof(q)))
                return -EFAULT;
-       /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
        return 0;
 }
 
@@ -2604,7 +2623,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
        struct cdrom_tochdr header;
        int ret;
 
-       /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
 
        if (copy_from_user(&header, argp, sizeof(header)))
                return -EFAULT;
@@ -2615,7 +2634,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &header, sizeof(header)))
                return -EFAULT;
-       /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
        return 0;
 }
 
@@ -2626,7 +2645,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
        u8 requested_format;
        int ret;
 
-       /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
 
        if (copy_from_user(&entry, argp, sizeof(entry)))
                return -EFAULT;
@@ -2643,7 +2662,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &entry, sizeof(entry)))
                return -EFAULT;
-       /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
        return 0;
 }
 
@@ -2652,7 +2671,7 @@ static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,
 {
        struct cdrom_msf msf;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2667,7 +2686,7 @@ static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,
        struct cdrom_ti ti;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2684,7 +2703,7 @@ static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,
 {
        struct cdrom_volctrl volume;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2699,7 +2718,7 @@ static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,
        struct cdrom_volctrl volume;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2718,7 +2737,7 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
 {
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
+       cd_dbg(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2728,103 +2747,6 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
        return cdi->ops->audio_ioctl(cdi, cmd, NULL);
 }
 
-/*
- * Just about every imaginable ioctl is supported in the Uniform layer
- * these days.
- * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
- */
-int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
-               fmode_t mode, unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int ret;
-
-       /*
-        * Try the generic SCSI command ioctl's first.
-        */
-       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-       if (ret != -ENOTTY)
-               return ret;
-
-       switch (cmd) {
-       case CDROMMULTISESSION:
-               return cdrom_ioctl_multisession(cdi, argp);
-       case CDROMEJECT:
-               return cdrom_ioctl_eject(cdi);
-       case CDROMCLOSETRAY:
-               return cdrom_ioctl_closetray(cdi);
-       case CDROMEJECT_SW:
-               return cdrom_ioctl_eject_sw(cdi, arg);
-       case CDROM_MEDIA_CHANGED:
-               return cdrom_ioctl_media_changed(cdi, arg);
-       case CDROM_SET_OPTIONS:
-               return cdrom_ioctl_set_options(cdi, arg);
-       case CDROM_CLEAR_OPTIONS:
-               return cdrom_ioctl_clear_options(cdi, arg);
-       case CDROM_SELECT_SPEED:
-               return cdrom_ioctl_select_speed(cdi, arg);
-       case CDROM_SELECT_DISC:
-               return cdrom_ioctl_select_disc(cdi, arg);
-       case CDROMRESET:
-               return cdrom_ioctl_reset(cdi, bdev);
-       case CDROM_LOCKDOOR:
-               return cdrom_ioctl_lock_door(cdi, arg);
-       case CDROM_DEBUG:
-               return cdrom_ioctl_debug(cdi, arg);
-       case CDROM_GET_CAPABILITY:
-               return cdrom_ioctl_get_capability(cdi);
-       case CDROM_GET_MCN:
-               return cdrom_ioctl_get_mcn(cdi, argp);
-       case CDROM_DRIVE_STATUS:
-               return cdrom_ioctl_drive_status(cdi, arg);
-       case CDROM_DISC_STATUS:
-               return cdrom_ioctl_disc_status(cdi);
-       case CDROM_CHANGER_NSLOTS:
-               return cdrom_ioctl_changer_nslots(cdi);
-       }
-
-       /*
-        * Use the ioctls that are implemented through the generic_packet()
-        * interface. this may look at bit funny, but if -ENOTTY is
-        * returned that particular ioctl is not implemented and we
-        * let it go through the device specific ones.
-        */
-       if (CDROM_CAN(CDC_GENERIC_PACKET)) {
-               ret = mmc_ioctl(cdi, cmd, arg);
-               if (ret != -ENOTTY)
-                       return ret;
-       }
-
-       /*
-        * Note: most of the cdinfo() calls are commented out here,
-        * because they fill up the sys log when CD players poll
-        * the drive.
-        */
-       switch (cmd) {
-       case CDROMSUBCHNL:
-               return cdrom_ioctl_get_subchnl(cdi, argp);
-       case CDROMREADTOCHDR:
-               return cdrom_ioctl_read_tochdr(cdi, argp);
-       case CDROMREADTOCENTRY:
-               return cdrom_ioctl_read_tocentry(cdi, argp);
-       case CDROMPLAYMSF:
-               return cdrom_ioctl_play_msf(cdi, argp);
-       case CDROMPLAYTRKIND:
-               return cdrom_ioctl_play_trkind(cdi, argp);
-       case CDROMVOLCTRL:
-               return cdrom_ioctl_volctrl(cdi, argp);
-       case CDROMVOLREAD:
-               return cdrom_ioctl_volread(cdi, argp);
-       case CDROMSTART:
-       case CDROMSTOP:
-       case CDROMPAUSE:
-       case CDROMRESUME:
-               return cdrom_ioctl_audioctl(cdi, cmd);
-       }
-
-       return -ENOSYS;
-}
-
 /*
  * Required when we need to use READ_10 to issue other than 2048 block
  * reads
@@ -2854,71 +2776,222 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
        return cdo->generic_packet(cdi, &cgc);
 }
 
-static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc,
-                                       int cmd)
+static int cdrom_get_track_info(struct cdrom_device_info *cdi,
+                               __u16 track, __u8 type, track_information *ti)
 {
-       struct request_sense sense;
-       struct cdrom_msf msf;
-       int blocksize = 0, format = 0, lba;
-       int ret;
+       struct cdrom_device_ops *cdo = cdi->ops;
+       struct packet_command cgc;
+       int ret, buflen;
 
-       switch (cmd) {
-       case CDROMREADRAW:
-               blocksize = CD_FRAMESIZE_RAW;
-               break;
-       case CDROMREADMODE1:
-               blocksize = CD_FRAMESIZE;
-               format = 2;
-               break;
-       case CDROMREADMODE2:
-               blocksize = CD_FRAMESIZE_RAW0;
-               break;
-       }
-       IOCTL_IN(arg, struct cdrom_msf, msf);
-       lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0);
-       /* FIXME: we need upper bound checking, too!! */
-       if (lba < 0)
-               return -EINVAL;
+       init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
+       cgc.cmd[1] = type & 3;
+       cgc.cmd[4] = (track & 0xff00) >> 8;
+       cgc.cmd[5] = track & 0xff;
+       cgc.cmd[8] = 8;
+       cgc.quiet = 1;
 
-       cgc->buffer = kzalloc(blocksize, GFP_KERNEL);
-       if (cgc->buffer == NULL)
-               return -ENOMEM;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
 
-       memset(&sense, 0, sizeof(sense));
-       cgc->sense = &sense;
-       cgc->data_direction = CGC_DATA_READ;
-       ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize);
-       if (ret && sense.sense_key == 0x05 &&
-                  sense.asc == 0x20 &&
-                  sense.ascq == 0x00) {
-               /*
-                * SCSI-II devices are not required to support
-                * READ_CD, so let's try switching block size
-                */
-               /* FIXME: switch back again... */
-               ret = cdrom_switch_blocksize(cdi, blocksize);
-               if (ret)
-                       goto out;
-               cgc->sense = NULL;
-               ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1);
-               ret |= cdrom_switch_blocksize(cdi, blocksize);
-       }
-       if (!ret && copy_to_user(arg, cgc->buffer, blocksize))
-               ret = -EFAULT;
+       buflen = be16_to_cpu(ti->track_information_length) +
+               sizeof(ti->track_information_length);
+
+       if (buflen > sizeof(track_information))
+               buflen = sizeof(track_information);
+
+       cgc.cmd[8] = cgc.buflen = buflen;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
+
+       /* return actual fill size */
+       return buflen;
+}
+
+/* return the last written block on the CD-R media. this is for the udf
+   file system. */
+int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written)
+{
+       struct cdrom_tocentry toc;
+       disc_information di;
+       track_information ti;
+       __u32 last_track;
+       int ret = -1, ti_size;
+
+       if (!CDROM_CAN(CDC_GENERIC_PACKET))
+               goto use_toc;
+
+       ret = cdrom_get_disc_info(cdi, &di);
+       if (ret < (int)(offsetof(typeof(di), last_track_lsb)
+                       + sizeof(di.last_track_lsb)))
+               goto use_toc;
+
+       /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
+       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
+       ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+       if (ti_size < (int)offsetof(typeof(ti), track_start))
+               goto use_toc;
+
+       /* if this track is blank, try the previous. */
+       if (ti.blank) {
+               if (last_track == 1)
+                       goto use_toc;
+               last_track--;
+               ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+       }
+
+       if (ti_size < (int)(offsetof(typeof(ti), track_size)
+                               + sizeof(ti.track_size)))
+               goto use_toc;
+
+       /* if last recorded field is valid, return it. */
+       if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address)
+                               + sizeof(ti.last_rec_address))) {
+               *last_written = be32_to_cpu(ti.last_rec_address);
+       } else {
+               /* make it up instead */
+               *last_written = be32_to_cpu(ti.track_start) +
+                               be32_to_cpu(ti.track_size);
+               if (ti.free_blocks)
+                       *last_written -= (be32_to_cpu(ti.free_blocks) + 7);
+       }
+       return 0;
+
+       /* this is where we end up if the drive either can't do a
+          GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if
+          it doesn't give enough information or fails. then we return
+          the toc contents. */
+use_toc:
+       toc.cdte_format = CDROM_MSF;
+       toc.cdte_track = CDROM_LEADOUT;
+       if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)))
+               return ret;
+       sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA);
+       *last_written = toc.cdte_addr.lba;
+       return 0;
+}
+
+/* return the next writable block. also for udf file system. */
+static int cdrom_get_next_writable(struct cdrom_device_info *cdi,
+                                  long *next_writable)
+{
+       disc_information di;
+       track_information ti;
+       __u16 last_track;
+       int ret, ti_size;
+
+       if (!CDROM_CAN(CDC_GENERIC_PACKET))
+               goto use_last_written;
+
+       ret = cdrom_get_disc_info(cdi, &di);
+       if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb)
+                               + sizeof(di.last_track_lsb))
+               goto use_last_written;
+
+       /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
+       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
+       ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+       if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start))
+               goto use_last_written;
+
+       /* if this track is blank, try the previous. */
+       if (ti.blank) {
+               if (last_track == 1)
+                       goto use_last_written;
+               last_track--;
+               ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+               if (ti_size < 0)
+                       goto use_last_written;
+       }
+
+       /* if next recordable address field is valid, use it. */
+       if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable)
+                               + sizeof(ti.next_writable)) {
+               *next_writable = be32_to_cpu(ti.next_writable);
+               return 0;
+       }
+
+use_last_written:
+       ret = cdrom_get_last_written(cdi, next_writable);
+       if (ret) {
+               *next_writable = 0;
+               return ret;
+       } else {
+               *next_writable += 7;
+               return 0;
+       }
+}
+
+static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
+                                             void __user *arg,
+                                             struct packet_command *cgc,
+                                             int cmd)
+{
+       struct request_sense sense;
+       struct cdrom_msf msf;
+       int blocksize = 0, format = 0, lba;
+       int ret;
+
+       switch (cmd) {
+       case CDROMREADRAW:
+               blocksize = CD_FRAMESIZE_RAW;
+               break;
+       case CDROMREADMODE1:
+               blocksize = CD_FRAMESIZE;
+               format = 2;
+               break;
+       case CDROMREADMODE2:
+               blocksize = CD_FRAMESIZE_RAW0;
+               break;
+       }
+       if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf)))
+               return -EFAULT;
+       lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0);
+       /* FIXME: we need upper bound checking, too!! */
+       if (lba < 0)
+               return -EINVAL;
+
+       cgc->buffer = kzalloc(blocksize, GFP_KERNEL);
+       if (cgc->buffer == NULL)
+               return -ENOMEM;
+
+       memset(&sense, 0, sizeof(sense));
+       cgc->sense = &sense;
+       cgc->data_direction = CGC_DATA_READ;
+       ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize);
+       if (ret && sense.sense_key == 0x05 &&
+           sense.asc == 0x20 &&
+           sense.ascq == 0x00) {
+               /*
+                * SCSI-II devices are not required to support
+                * READ_CD, so let's try switching block size
+                */
+               /* FIXME: switch back again... */
+               ret = cdrom_switch_blocksize(cdi, blocksize);
+               if (ret)
+                       goto out;
+               cgc->sense = NULL;
+               ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1);
+               ret |= cdrom_switch_blocksize(cdi, blocksize);
+       }
+       if (!ret && copy_to_user(arg, cgc->buffer, blocksize))
+               ret = -EFAULT;
 out:
        kfree(cgc->buffer);
        return ret;
 }
 
 static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
-                                       void __user *arg)
+                                              void __user *arg)
 {
        struct cdrom_read_audio ra;
        int lba;
 
-       IOCTL_IN(arg, struct cdrom_read_audio, ra);
+       if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
+                          sizeof(ra)))
+               return -EFAULT;
 
        if (ra.addr_format == CDROM_MSF)
                lba = msf_to_lba(ra.addr.msf.minute,
@@ -2937,12 +3010,13 @@ static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,
-                                       void __user *arg)
+                                              void __user *arg)
 {
        int ret;
        struct cdrom_subchnl q;
        u_char requested, back;
-       IOCTL_IN(arg, struct cdrom_subchnl, q);
+       if (copy_from_user(&q, (struct cdrom_subchnl __user *)arg, sizeof(q)))
+               return -EFAULT;
        requested = q.cdsc_format;
        if (!((requested == CDROM_MSF) ||
              (requested == CDROM_LBA)))
@@ -2954,19 +3028,21 @@ static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,
        back = q.cdsc_format; /* local copy */
        sanitize_format(&q.cdsc_absaddr, &back, requested);
        sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
-       IOCTL_OUT(arg, struct cdrom_subchnl, q);
-       /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+       if (copy_to_user((struct cdrom_subchnl __user *)arg, &q, sizeof(q)))
+               return -EFAULT;
+       /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
        return 0;
 }
 
 static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc)
+                                            void __user *arg,
+                                            struct packet_command *cgc)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_msf msf;
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
-       IOCTL_IN(arg, struct cdrom_msf, msf);
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+       if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf)))
+               return -EFAULT;
        cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF;
        cgc->cmd[3] = msf.cdmsf_min0;
        cgc->cmd[4] = msf.cdmsf_sec0;
@@ -2979,13 +3055,14 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc)
+                                            void __user *arg,
+                                            struct packet_command *cgc)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_blk blk;
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
-       IOCTL_IN(arg, struct cdrom_blk, blk);
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
+       if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk)))
+               return -EFAULT;
        cgc->cmd[0] = GPCMD_PLAY_AUDIO_10;
        cgc->cmd[2] = (blk.from >> 24) & 0xff;
        cgc->cmd[3] = (blk.from >> 16) & 0xff;
@@ -2998,9 +3075,9 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc,
-                                       unsigned int cmd)
+                                          void __user *arg,
+                                          struct packet_command *cgc,
+                                          unsigned int cmd)
 {
        struct cdrom_volctrl volctrl;
        unsigned char buffer[32];
@@ -3008,9 +3085,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
        unsigned short offset;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMVOLUME\n");
 
-       IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
+       if (copy_from_user(&volctrl, (struct cdrom_volctrl __user *)arg,
+                          sizeof(volctrl)))
+               return -EFAULT;
 
        cgc->buffer = buffer;
        cgc->buflen = 24;
@@ -3030,14 +3109,14 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
        if (offset + 16 > cgc->buflen) {
                cgc->buflen = offset + 16;
                ret = cdrom_mode_sense(cdi, cgc,
-                                       GPMODE_AUDIO_CTL_PAGE, 0);
+                                      GPMODE_AUDIO_CTL_PAGE, 0);
                if (ret)
                        return ret;
        }
 
        /* sanity check */
        if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE ||
-                       buffer[offset + 1] < 14)
+           buffer[offset + 1] < 14)
                return -EINVAL;
 
        /* now we have the current volume settings. if it was only
@@ -3047,7 +3126,9 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
                volctrl.channel1 = buffer[offset+11];
                volctrl.channel2 = buffer[offset+13];
                volctrl.channel3 = buffer[offset+15];
-               IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);
+               if (copy_to_user((struct cdrom_volctrl __user *)arg, &volctrl,
+                                sizeof(volctrl)))
+                       return -EFAULT;
                return 0;
        }
                
@@ -3069,11 +3150,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
-                                       struct packet_command *cgc,
-                                       int cmd)
+                                              struct packet_command *cgc,
+                                              int cmd)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
-       cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
        cgc->cmd[0] = GPCMD_START_STOP_UNIT;
        cgc->cmd[1] = 1;
        cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
@@ -3082,11 +3163,11 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
-                                       struct packet_command *cgc,
-                                       int cmd)
+                                                struct packet_command *cgc,
+                                                int cmd)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
-       cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
        cgc->cmd[0] = GPCMD_PAUSE_RESUME;
        cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
        cgc->data_direction = CGC_DATA_NONE;
@@ -3094,8 +3175,8 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
-                                               void __user *arg,
-                                               struct packet_command *cgc)
+                                             void __user *arg,
+                                             struct packet_command *cgc)
 {
        int ret;
        dvd_struct *s;
@@ -3108,7 +3189,7 @@ static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
        if (!s)
                return -ENOMEM;
 
-       cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
+       cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
        if (copy_from_user(s, arg, size)) {
                kfree(s);
                return -EFAULT;
@@ -3126,44 +3207,48 @@ out:
 }
 
 static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi,
-                                       void __user *arg)
+                                      void __user *arg)
 {
        int ret;
        dvd_authinfo ai;
        if (!CDROM_CAN(CDC_DVD))
                return -ENOSYS;
-       cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n");
-       IOCTL_IN(arg, dvd_authinfo, ai);
+       cd_dbg(CD_DO_IOCTL, "entering DVD_AUTH\n");
+       if (copy_from_user(&ai, (dvd_authinfo __user *)arg, sizeof(ai)))
+               return -EFAULT;
        ret = dvd_do_auth(cdi, &ai);
        if (ret)
                return ret;
-       IOCTL_OUT(arg, dvd_authinfo, ai);
+       if (copy_to_user((dvd_authinfo __user *)arg, &ai, sizeof(ai)))
+               return -EFAULT;
        return 0;
 }
 
 static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi,
-                                               void __user *arg)
+                                                 void __user *arg)
 {
        int ret;
        long next = 0;
-       cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
        ret = cdrom_get_next_writable(cdi, &next);
        if (ret)
                return ret;
-       IOCTL_OUT(arg, long, next);
+       if (copy_to_user((long __user *)arg, &next, sizeof(next)))
+               return -EFAULT;
        return 0;
 }
 
 static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi,
-                                               void __user *arg)
+                                                void __user *arg)
 {
        int ret;
        long last = 0;
-       cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
        ret = cdrom_get_last_written(cdi, &last);
        if (ret)
                return ret;
-       IOCTL_OUT(arg, long, last);
+       if (copy_to_user((long __user *)arg, &last, sizeof(last)))
+               return -EFAULT;
        return 0;
 }
 
@@ -3212,181 +3297,101 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
        return -ENOTTY;
 }
 
-static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type,
-                        track_information *ti)
-{
-       struct cdrom_device_ops *cdo = cdi->ops;
-       struct packet_command cgc;
-       int ret, buflen;
-
-       init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
-       cgc.cmd[1] = type & 3;
-       cgc.cmd[4] = (track & 0xff00) >> 8;
-       cgc.cmd[5] = track & 0xff;
-       cgc.cmd[8] = 8;
-       cgc.quiet = 1;
-
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
-       
-       buflen = be16_to_cpu(ti->track_information_length) +
-                    sizeof(ti->track_information_length);
-
-       if (buflen > sizeof(track_information))
-               buflen = sizeof(track_information);
-
-       cgc.cmd[8] = cgc.buflen = buflen;
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
-
-       /* return actual fill size */
-       return buflen;
-}
-
-/* requires CD R/RW */
-static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di)
+/*
+ * Just about every imaginable ioctl is supported in the Uniform layer
+ * these days.
+ * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
+ */
+int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
+               fmode_t mode, unsigned int cmd, unsigned long arg)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
-       struct packet_command cgc;
-       int ret, buflen;
-
-       /* set up command and get the disc info */
-       init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DISC_INFO;
-       cgc.cmd[8] = cgc.buflen = 2;
-       cgc.quiet = 1;
-
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+       void __user *argp = (void __user *)arg;
+       int ret;
 
-       /* not all drives have the same disc_info length, so requeue
-        * packet with the length the drive tells us it can supply
+       /*
+        * Try the generic SCSI command ioctl's first.
         */
-       buflen = be16_to_cpu(di->disc_information_length) +
-                    sizeof(di->disc_information_length);
-
-       if (buflen > sizeof(disc_information))
-               buflen = sizeof(disc_information);
-
-       cgc.cmd[8] = cgc.buflen = buflen;
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
+       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
+       if (ret != -ENOTTY)
                return ret;
 
-       /* return actual fill size */
-       return buflen;
-}
-
-/* return the last written block on the CD-R media. this is for the udf
-   file system. */
-int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written)
-{
-       struct cdrom_tocentry toc;
-       disc_information di;
-       track_information ti;
-       __u32 last_track;
-       int ret = -1, ti_size;
-
-       if (!CDROM_CAN(CDC_GENERIC_PACKET))
-               goto use_toc;
-
-       ret = cdrom_get_disc_info(cdi, &di);
-       if (ret < (int)(offsetof(typeof(di), last_track_lsb)
-                       + sizeof(di.last_track_lsb)))
-               goto use_toc;
-
-       /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
-       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
-       ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-       if (ti_size < (int)offsetof(typeof(ti), track_start))
-               goto use_toc;
-
-       /* if this track is blank, try the previous. */
-       if (ti.blank) {
-               if (last_track==1)
-                       goto use_toc;
-               last_track--;
-               ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-       }
-
-       if (ti_size < (int)(offsetof(typeof(ti), track_size)
-                               + sizeof(ti.track_size)))
-               goto use_toc;
-
-       /* if last recorded field is valid, return it. */
-       if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address)
-                               + sizeof(ti.last_rec_address))) {
-               *last_written = be32_to_cpu(ti.last_rec_address);
-       } else {
-               /* make it up instead */
-               *last_written = be32_to_cpu(ti.track_start) +
-                               be32_to_cpu(ti.track_size);
-               if (ti.free_blocks)
-                       *last_written -= (be32_to_cpu(ti.free_blocks) + 7);
+       switch (cmd) {
+       case CDROMMULTISESSION:
+               return cdrom_ioctl_multisession(cdi, argp);
+       case CDROMEJECT:
+               return cdrom_ioctl_eject(cdi);
+       case CDROMCLOSETRAY:
+               return cdrom_ioctl_closetray(cdi);
+       case CDROMEJECT_SW:
+               return cdrom_ioctl_eject_sw(cdi, arg);
+       case CDROM_MEDIA_CHANGED:
+               return cdrom_ioctl_media_changed(cdi, arg);
+       case CDROM_SET_OPTIONS:
+               return cdrom_ioctl_set_options(cdi, arg);
+       case CDROM_CLEAR_OPTIONS:
+               return cdrom_ioctl_clear_options(cdi, arg);
+       case CDROM_SELECT_SPEED:
+               return cdrom_ioctl_select_speed(cdi, arg);
+       case CDROM_SELECT_DISC:
+               return cdrom_ioctl_select_disc(cdi, arg);
+       case CDROMRESET:
+               return cdrom_ioctl_reset(cdi, bdev);
+       case CDROM_LOCKDOOR:
+               return cdrom_ioctl_lock_door(cdi, arg);
+       case CDROM_DEBUG:
+               return cdrom_ioctl_debug(cdi, arg);
+       case CDROM_GET_CAPABILITY:
+               return cdrom_ioctl_get_capability(cdi);
+       case CDROM_GET_MCN:
+               return cdrom_ioctl_get_mcn(cdi, argp);
+       case CDROM_DRIVE_STATUS:
+               return cdrom_ioctl_drive_status(cdi, arg);
+       case CDROM_DISC_STATUS:
+               return cdrom_ioctl_disc_status(cdi);
+       case CDROM_CHANGER_NSLOTS:
+               return cdrom_ioctl_changer_nslots(cdi);
        }
-       return 0;
 
-       /* this is where we end up if the drive either can't do a
-          GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if
-          it doesn't give enough information or fails. then we return
-          the toc contents. */
-use_toc:
-       toc.cdte_format = CDROM_MSF;
-       toc.cdte_track = CDROM_LEADOUT;
-       if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)))
-               return ret;
-       sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA);
-       *last_written = toc.cdte_addr.lba;
-       return 0;
-}
-
-/* return the next writable block. also for udf file system. */
-static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable)
-{
-       disc_information di;
-       track_information ti;
-       __u16 last_track;
-       int ret, ti_size;
-
-       if (!CDROM_CAN(CDC_GENERIC_PACKET))
-               goto use_last_written;
-
-       ret = cdrom_get_disc_info(cdi, &di);
-       if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb)
-                               + sizeof(di.last_track_lsb))
-               goto use_last_written;
-
-       /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
-       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
-       ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-       if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start))
-               goto use_last_written;
-
-        /* if this track is blank, try the previous. */
-       if (ti.blank) {
-               if (last_track == 1)
-                       goto use_last_written;
-               last_track--;
-               ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-               if (ti_size < 0)
-                       goto use_last_written;
+       /*
+        * Use the ioctls that are implemented through the generic_packet()
+        * interface. this may look at bit funny, but if -ENOTTY is
+        * returned that particular ioctl is not implemented and we
+        * let it go through the device specific ones.
+        */
+       if (CDROM_CAN(CDC_GENERIC_PACKET)) {
+               ret = mmc_ioctl(cdi, cmd, arg);
+               if (ret != -ENOTTY)
+                       return ret;
        }
 
-       /* if next recordable address field is valid, use it. */
-       if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable)
-                               + sizeof(ti.next_writable)) {
-               *next_writable = be32_to_cpu(ti.next_writable);
-               return 0;
+       /*
+        * Note: most of the cd_dbg() calls are commented out here,
+        * because they fill up the sys log when CD players poll
+        * the drive.
+        */
+       switch (cmd) {
+       case CDROMSUBCHNL:
+               return cdrom_ioctl_get_subchnl(cdi, argp);
+       case CDROMREADTOCHDR:
+               return cdrom_ioctl_read_tochdr(cdi, argp);
+       case CDROMREADTOCENTRY:
+               return cdrom_ioctl_read_tocentry(cdi, argp);
+       case CDROMPLAYMSF:
+               return cdrom_ioctl_play_msf(cdi, argp);
+       case CDROMPLAYTRKIND:
+               return cdrom_ioctl_play_trkind(cdi, argp);
+       case CDROMVOLCTRL:
+               return cdrom_ioctl_volctrl(cdi, argp);
+       case CDROMVOLREAD:
+               return cdrom_ioctl_volread(cdi, argp);
+       case CDROMSTART:
+       case CDROMSTOP:
+       case CDROMPAUSE:
+       case CDROMRESUME:
+               return cdrom_ioctl_audioctl(cdi, cmd);
        }
 
-use_last_written:
-       if ((ret = cdrom_get_last_written(cdi, next_writable))) {
-               *next_writable = 0;
-               return ret;
-       } else {
-               *next_writable += 7;
-               return 0;
-       }
+       return -ENOSYS;
 }
 
 EXPORT_SYMBOL(cdrom_get_last_written);
index 51e75ad964223e07268e0781caa5fa9230f43824..584bc3126403d58955a915db2117fcd1d16de5a2 100644 (file)
@@ -602,7 +602,7 @@ static void gdrom_readdisk_dma(struct work_struct *work)
                spin_unlock(&gdrom_lock);
                block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
                block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
-               __raw_writel(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
+               __raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG);
                __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
                __raw_writel(1, GDROM_DMA_DIRECTION_REG);
                __raw_writel(1, GDROM_DMA_ENABLE_REG);
index 244759bbd7b73d0aa3015c915654abd35ac7a193..ac6c0f3e2eb28df1318cf4423198d98fb81a6657 100644 (file)
@@ -2,7 +2,7 @@
 # Hardware Random Number Generator (RNG) configuration
 #
 
-config HW_RANDOM
+menuconfig HW_RANDOM
        tristate "Hardware Random Number Generator Core support"
        default m
        ---help---
@@ -20,9 +20,11 @@ config HW_RANDOM
 
          If unsure, say Y.
 
+if HW_RANDOM
+
 config HW_RANDOM_TIMERIOMEM
        tristate "Timer IOMEM HW Random Number Generator support"
-       depends on HW_RANDOM && HAS_IOMEM
+       depends on HAS_IOMEM
        ---help---
          This driver provides kernel-side support for a generic Random
          Number Generator used by reading a 'dumb' iomem address that
@@ -36,7 +38,7 @@ config HW_RANDOM_TIMERIOMEM
 
 config HW_RANDOM_INTEL
        tristate "Intel HW Random Number Generator support"
-       depends on HW_RANDOM && (X86 || IA64) && PCI
+       depends on (X86 || IA64) && PCI
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -49,7 +51,7 @@ config HW_RANDOM_INTEL
 
 config HW_RANDOM_AMD
        tristate "AMD HW Random Number Generator support"
-       depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI
+       depends on (X86 || PPC_MAPLE) && PCI
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -62,8 +64,8 @@ config HW_RANDOM_AMD
 
 config HW_RANDOM_ATMEL
        tristate "Atmel Random Number Generator support"
-       depends on HW_RANDOM && HAVE_CLK
-       default (HW_RANDOM && ARCH_AT91)
+       depends on ARCH_AT91 && HAVE_CLK
+       default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
          Generator hardware found on Atmel AT91 devices.
@@ -75,7 +77,7 @@ config HW_RANDOM_ATMEL
 
 config HW_RANDOM_BCM63XX
        tristate "Broadcom BCM63xx Random Number Generator support"
-       depends on HW_RANDOM && BCM63XX
+       depends on BCM63XX
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -88,7 +90,7 @@ config HW_RANDOM_BCM63XX
 
 config HW_RANDOM_BCM2835
        tristate "Broadcom BCM2835 Random Number Generator support"
-       depends on HW_RANDOM && ARCH_BCM2835
+       depends on ARCH_BCM2835
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -101,7 +103,7 @@ config HW_RANDOM_BCM2835
 
 config HW_RANDOM_GEODE
        tristate "AMD Geode HW Random Number Generator support"
-       depends on HW_RANDOM && X86_32 && PCI
+       depends on X86_32 && PCI
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -114,7 +116,7 @@ config HW_RANDOM_GEODE
 
 config HW_RANDOM_N2RNG
        tristate "Niagara2 Random Number Generator support"
-       depends on HW_RANDOM && SPARC64
+       depends on SPARC64
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -127,7 +129,7 @@ config HW_RANDOM_N2RNG
 
 config HW_RANDOM_VIA
        tristate "VIA HW Random Number Generator support"
-       depends on HW_RANDOM && X86
+       depends on X86
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -140,7 +142,7 @@ config HW_RANDOM_VIA
 
 config HW_RANDOM_IXP4XX
        tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
-       depends on HW_RANDOM && ARCH_IXP4XX
+       depends on ARCH_IXP4XX
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Pseudo-Random
@@ -153,7 +155,7 @@ config HW_RANDOM_IXP4XX
 
 config HW_RANDOM_OMAP
        tristate "OMAP Random Number Generator support"
-       depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
+       depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -167,7 +169,7 @@ config HW_RANDOM_OMAP
 
 config HW_RANDOM_OMAP3_ROM
        tristate "OMAP3 ROM Random Number Generator support"
-       depends on HW_RANDOM && ARCH_OMAP3
+       depends on ARCH_OMAP3
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -180,7 +182,7 @@ config HW_RANDOM_OMAP3_ROM
 
 config HW_RANDOM_OCTEON
        tristate "Octeon Random Number Generator support"
-       depends on HW_RANDOM && CAVIUM_OCTEON_SOC
+       depends on CAVIUM_OCTEON_SOC
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -193,7 +195,7 @@ config HW_RANDOM_OCTEON
 
 config HW_RANDOM_PASEMI
        tristate "PA Semi HW Random Number Generator support"
-       depends on HW_RANDOM && PPC_PASEMI
+       depends on PPC_PASEMI
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -206,7 +208,7 @@ config HW_RANDOM_PASEMI
 
 config HW_RANDOM_VIRTIO
        tristate "VirtIO Random Number Generator support"
-       depends on HW_RANDOM && VIRTIO
+       depends on VIRTIO
        ---help---
          This driver provides kernel-side support for the virtual Random Number
          Generator hardware.
@@ -216,7 +218,7 @@ config HW_RANDOM_VIRTIO
 
 config HW_RANDOM_TX4939
        tristate "TX4939 Random Number Generator support"
-       depends on HW_RANDOM && SOC_TX4939
+       depends on SOC_TX4939
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -229,7 +231,8 @@ config HW_RANDOM_TX4939
 
 config HW_RANDOM_MXC_RNGA
        tristate "Freescale i.MX RNGA Random Number Generator"
-       depends on HW_RANDOM && ARCH_HAS_RNGA
+       depends on ARCH_HAS_RNGA
+       default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
          Generator hardware found on Freescale i.MX processors.
@@ -241,7 +244,8 @@ config HW_RANDOM_MXC_RNGA
 
 config HW_RANDOM_NOMADIK
        tristate "ST-Ericsson Nomadik Random Number Generator support"
-       depends on HW_RANDOM && ARCH_NOMADIK
+       depends on ARCH_NOMADIK
+       default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
          Generator hardware found on ST-Ericsson SoCs (8815 and 8500).
@@ -251,21 +255,10 @@ config HW_RANDOM_NOMADIK
 
          If unsure, say Y.
 
-config HW_RANDOM_PICOXCELL
-       tristate "Picochip picoXcell true random number generator support"
-       depends on HW_RANDOM && ARCH_PICOXCELL && PICOXCELL_PC3X3
-       ---help---
-         This driver provides kernel-side support for the Random Number
-         Generator hardware found on Picochip PC3x3 and later devices.
-
-         To compile this driver as a module, choose M here: the
-         module will be called picoxcell-rng.
-
-         If unsure, say Y.
-
 config HW_RANDOM_PPC4XX
        tristate "PowerPC 4xx generic true random number generator support"
-       depends on HW_RANDOM && PPC && 4xx
+       depends on PPC && 4xx
+       default HW_RANDOM
        ---help---
         This driver provides the kernel-side support for the TRNG hardware
         found in the security function of some PowerPC 4xx SoCs.
@@ -275,24 +268,9 @@ config HW_RANDOM_PPC4XX
 
         If unsure, say N.
 
-config UML_RANDOM
-       depends on UML
-       tristate "Hardware random number generator"
-       help
-         This option enables UML's "hardware" random number generator.  It
-         attaches itself to the host's /dev/random, supplying as much entropy
-         as the host has, rather than the small amount the UML gets from its
-         own drivers.  It registers itself as a standard hardware random number
-         generator, major 10, minor 183, and the canonical device name is
-         /dev/hwrng.
-         The way to make use of this is to install the rng-tools package
-         (check your distro, or download from
-         http://sourceforge.net/projects/gkernel/).  rngd periodically reads
-         /dev/hwrng and injects the entropy into /dev/random.
-
 config HW_RANDOM_PSERIES
        tristate "pSeries HW Random Number Generator support"
-       depends on HW_RANDOM && PPC64 && IBMVIO
+       depends on PPC64 && IBMVIO
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -305,7 +283,7 @@ config HW_RANDOM_PSERIES
 
 config HW_RANDOM_POWERNV
        tristate "PowerNV Random Number Generator support"
-       depends on HW_RANDOM && PPC_POWERNV
+       depends on PPC_POWERNV
        default HW_RANDOM
        ---help---
          This is the driver for Random Number Generator hardware found
@@ -318,7 +296,8 @@ config HW_RANDOM_POWERNV
 
 config HW_RANDOM_EXYNOS
        tristate "EXYNOS HW random number generator support"
-       depends on HW_RANDOM && HAS_IOMEM && HAVE_CLK
+       depends on ARCH_EXYNOS
+       default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
          Generator hardware found on EXYNOS SOCs.
@@ -330,7 +309,7 @@ config HW_RANDOM_EXYNOS
 
 config HW_RANDOM_TPM
        tristate "TPM HW Random Number Generator support"
-       depends on HW_RANDOM && TCG_TPM
+       depends on TCG_TPM
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -343,7 +322,8 @@ config HW_RANDOM_TPM
 
 config HW_RANDOM_MSM
        tristate "Qualcomm SoCs Random Number Generator support"
-       depends on HW_RANDOM && ARCH_QCOM
+       depends on ARCH_QCOM
+       default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
          Generator hardware found on Qualcomm SoCs.
@@ -352,3 +332,20 @@ config HW_RANDOM_MSM
          module will be called msm-rng.
 
          If unsure, say Y.
+
+endif # HW_RANDOM
+
+config UML_RANDOM
+       depends on UML
+       tristate "Hardware random number generator"
+       help
+         This option enables UML's "hardware" random number generator.  It
+         attaches itself to the host's /dev/random, supplying as much entropy
+         as the host has, rather than the small amount the UML gets from its
+         own drivers.  It registers itself as a standard hardware random number
+         generator, major 10, minor 183, and the canonical device name is
+         /dev/hwrng.
+         The way to make use of this is to install the rng-tools package
+         (check your distro, or download from
+         http://sourceforge.net/projects/gkernel/).  rngd periodically reads
+         /dev/hwrng and injects the entropy into /dev/random.
index 3ae7755a52e706bd8356e8ae5bc660fe8a693767..199ed283e1497bcaadf99805f92116b49739d874 100644 (file)
@@ -22,7 +22,6 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
 obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
 obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
-obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
 obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
 obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c
deleted file mode 100644 (file)
index eab5448..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2010-2011 Picochip Ltd., Jamie Iles
- *
- * 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.
- *
- * All enquiries to support@picochip.com
- */
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/hw_random.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#define DATA_REG_OFFSET                0x0200
-#define CSR_REG_OFFSET         0x0278
-#define CSR_OUT_EMPTY_MASK     (1 << 24)
-#define CSR_FAULT_MASK         (1 << 1)
-#define TRNG_BLOCK_RESET_MASK  (1 << 0)
-#define TAI_REG_OFFSET         0x0380
-
-/*
- * The maximum amount of time in microseconds to spend waiting for data if the
- * core wants us to wait.  The TRNG should generate 32 bits every 320ns so a
- * timeout of 20us seems reasonable.  The TRNG does builtin tests of the data
- * for randomness so we can't always assume there is data present.
- */
-#define PICO_TRNG_TIMEOUT              20
-
-static void __iomem *rng_base;
-static struct clk *rng_clk;
-static struct device *rng_dev;
-
-static inline u32 picoxcell_trng_read_csr(void)
-{
-       return __raw_readl(rng_base + CSR_REG_OFFSET);
-}
-
-static inline bool picoxcell_trng_is_empty(void)
-{
-       return picoxcell_trng_read_csr() & CSR_OUT_EMPTY_MASK;
-}
-
-/*
- * Take the random number generator out of reset and make sure the interrupts
- * are masked. We shouldn't need to get large amounts of random bytes so just
- * poll the status register. The hardware generates 32 bits every 320ns so we
- * shouldn't have to wait long enough to warrant waiting for an IRQ.
- */
-static void picoxcell_trng_start(void)
-{
-       __raw_writel(0, rng_base + TAI_REG_OFFSET);
-       __raw_writel(0, rng_base + CSR_REG_OFFSET);
-}
-
-static void picoxcell_trng_reset(void)
-{
-       __raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + CSR_REG_OFFSET);
-       __raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + TAI_REG_OFFSET);
-       picoxcell_trng_start();
-}
-
-/*
- * Get some random data from the random number generator. The hw_random core
- * layer provides us with locking.
- */
-static int picoxcell_trng_read(struct hwrng *rng, void *buf, size_t max,
-                              bool wait)
-{
-       int i;
-
-       /* Wait for some data to become available. */
-       for (i = 0; i < PICO_TRNG_TIMEOUT && picoxcell_trng_is_empty(); ++i) {
-               if (!wait)
-                       return 0;
-
-               udelay(1);
-       }
-
-       if (picoxcell_trng_read_csr() & CSR_FAULT_MASK) {
-               dev_err(rng_dev, "fault detected, resetting TRNG\n");
-               picoxcell_trng_reset();
-               return -EIO;
-       }
-
-       if (i == PICO_TRNG_TIMEOUT)
-               return 0;
-
-       *(u32 *)buf = __raw_readl(rng_base + DATA_REG_OFFSET);
-       return sizeof(u32);
-}
-
-static struct hwrng picoxcell_trng = {
-       .name           = "picoxcell",
-       .read           = picoxcell_trng_read,
-};
-
-static int picoxcell_trng_probe(struct platform_device *pdev)
-{
-       int ret;
-       struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       rng_base = devm_ioremap_resource(&pdev->dev, mem);
-       if (IS_ERR(rng_base))
-               return PTR_ERR(rng_base);
-
-       rng_clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(rng_clk)) {
-               dev_warn(&pdev->dev, "no clk\n");
-               return PTR_ERR(rng_clk);
-       }
-
-       ret = clk_enable(rng_clk);
-       if (ret) {
-               dev_warn(&pdev->dev, "unable to enable clk\n");
-               return ret;
-       }
-
-       picoxcell_trng_start();
-       ret = hwrng_register(&picoxcell_trng);
-       if (ret)
-               goto err_register;
-
-       rng_dev = &pdev->dev;
-       dev_info(&pdev->dev, "pixoxcell random number generator active\n");
-
-       return 0;
-
-err_register:
-       clk_disable(rng_clk);
-       return ret;
-}
-
-static int picoxcell_trng_remove(struct platform_device *pdev)
-{
-       hwrng_unregister(&picoxcell_trng);
-       clk_disable(rng_clk);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int picoxcell_trng_suspend(struct device *dev)
-{
-       clk_disable(rng_clk);
-
-       return 0;
-}
-
-static int picoxcell_trng_resume(struct device *dev)
-{
-       return clk_enable(rng_clk);
-}
-
-static const struct dev_pm_ops picoxcell_trng_pm_ops = {
-       .suspend        = picoxcell_trng_suspend,
-       .resume         = picoxcell_trng_resume,
-};
-#endif /* CONFIG_PM */
-
-static struct platform_driver picoxcell_trng_driver = {
-       .probe          = picoxcell_trng_probe,
-       .remove         = picoxcell_trng_remove,
-       .driver         = {
-               .name   = "picoxcell-trng",
-               .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm     = &picoxcell_trng_pm_ops,
-#endif /* CONFIG_PM */
-       },
-};
-
-module_platform_driver(picoxcell_trng_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jamie Iles");
-MODULE_DESCRIPTION("Picochip picoXcell TRNG driver");
index 6b75713d953a4e719cd33610f6034bec430c5d95..0a19d866a153f235363365dd221e162e1cdfa0ff 100644 (file)
@@ -902,6 +902,7 @@ void add_disk_randomness(struct gendisk *disk)
        add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
        trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool));
 }
+EXPORT_SYMBOL_GPL(add_disk_randomness);
 #endif
 
 /*********************************************************************
index 6e8d65e9b1d3c196ea2d2bd76b78530dd0387920..0102dc788608ec0060cf2fe1666e058c2d2d8076 100644 (file)
@@ -284,10 +284,10 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
 #endif
 
 static const struct file_operations raw_fops = {
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = blkdev_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = blkdev_write_iter,
        .fsync          = blkdev_fsync,
        .open           = raw_open,
        .release        = raw_release,
index 693f7be129f12a0d159727c33cd126e68cf957e0..3b34dba9178d9c792fffa5f5afa5b2c0e00d83dd 100644 (file)
@@ -34,3 +34,7 @@ config DOVE_CLK
 config KIRKWOOD_CLK
        bool
        select MVEBU_CLK_COMMON
+
+config ORION_CLK
+       bool
+       select MVEBU_CLK_COMMON
index 4c66162fb0b440ca326f3f5b1510f71dbf3b755f..a9a56fc01901580f36804efb6d21968cf7d749f0 100644 (file)
@@ -8,3 +8,4 @@ obj-$(CONFIG_ARMADA_38X_CLK)    += armada-38x.o
 obj-$(CONFIG_ARMADA_XP_CLK)    += armada-xp.o
 obj-$(CONFIG_DOVE_CLK)         += dove.o
 obj-$(CONFIG_KIRKWOOD_CLK)     += kirkwood.o
+obj-$(CONFIG_ORION_CLK)                += orion.o
diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c
new file mode 100644 (file)
index 0000000..fd12956
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Marvell Orion SoC clocks
+ *
+ * Copyright (C) 2014 Thomas Petazzoni
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include "common.h"
+
+static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
+       { .id = 0, .name = "ddrclk", }
+};
+
+/*
+ * Orion 5182
+ */
+
+#define SAR_MV88F5182_TCLK_FREQ      8
+#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3
+
+static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) &
+               SAR_MV88F5182_TCLK_FREQ_MASK;
+       if (opt == 1)
+               return 150000000;
+       else if (opt == 2)
+               return 166666667;
+       else
+               return 0;
+}
+
+#define SAR_MV88F5182_CPU_FREQ       4
+#define SAR_MV88F5182_CPU_FREQ_MASK  0xf
+
+static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
+               SAR_MV88F5182_CPU_FREQ_MASK;
+       if (opt == 0)
+               return 333333333;
+       else if (opt == 1 || opt == 2)
+               return 400000000;
+       else if (opt == 3)
+               return 500000000;
+       else
+               return 0;
+}
+
+static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id,
+                                          int *mult, int *div)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
+               SAR_MV88F5182_CPU_FREQ_MASK;
+       if (opt == 0 || opt == 1) {
+               *mult = 1;
+               *div  = 2;
+       } else if (opt == 2 || opt == 3) {
+               *mult = 1;
+               *div  = 3;
+       } else {
+               *mult = 0;
+               *div  = 1;
+       }
+}
+
+static const struct coreclk_soc_desc mv88f5182_coreclks = {
+       .get_tclk_freq = mv88f5182_get_tclk_freq,
+       .get_cpu_freq = mv88f5182_get_cpu_freq,
+       .get_clk_ratio = mv88f5182_get_clk_ratio,
+       .ratios = orion_coreclk_ratios,
+       .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5182_clk_init(struct device_node *np)
+{
+       return mvebu_coreclk_setup(np, &mv88f5182_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init);
+
+/*
+ * Orion 5281
+ */
+
+static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar)
+{
+       /* On 5281, tclk is always 166 Mhz */
+       return 166666667;
+}
+
+#define SAR_MV88F5281_CPU_FREQ       4
+#define SAR_MV88F5281_CPU_FREQ_MASK  0xf
+
+static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
+               SAR_MV88F5281_CPU_FREQ_MASK;
+       if (opt == 1 || opt == 2)
+               return 400000000;
+       else if (opt == 3)
+               return 500000000;
+       else
+               return 0;
+}
+
+static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id,
+                                          int *mult, int *div)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
+               SAR_MV88F5281_CPU_FREQ_MASK;
+       if (opt == 1) {
+               *mult = 1;
+               *div = 2;
+       } else if (opt == 2 || opt == 3) {
+               *mult = 1;
+               *div = 3;
+       } else {
+               *mult = 0;
+               *div = 1;
+       }
+}
+
+static const struct coreclk_soc_desc mv88f5281_coreclks = {
+       .get_tclk_freq = mv88f5281_get_tclk_freq,
+       .get_cpu_freq = mv88f5281_get_cpu_freq,
+       .get_clk_ratio = mv88f5281_get_clk_ratio,
+       .ratios = orion_coreclk_ratios,
+       .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5281_clk_init(struct device_node *np)
+{
+       return mvebu_coreclk_setup(np, &mv88f5281_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init);
+
+/*
+ * Orion 6183
+ */
+
+#define SAR_MV88F6183_TCLK_FREQ      9
+#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1
+
+static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) &
+               SAR_MV88F6183_TCLK_FREQ_MASK;
+       if (opt == 0)
+               return 133333333;
+       else if (opt == 1)
+               return 166666667;
+       else
+               return 0;
+}
+
+#define SAR_MV88F6183_CPU_FREQ       1
+#define SAR_MV88F6183_CPU_FREQ_MASK  0x3f
+
+static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
+               SAR_MV88F6183_CPU_FREQ_MASK;
+       if (opt == 9)
+               return 333333333;
+       else if (opt == 17)
+               return 400000000;
+       else
+               return 0;
+}
+
+static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id,
+                                          int *mult, int *div)
+{
+       u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
+               SAR_MV88F6183_CPU_FREQ_MASK;
+       if (opt == 9 || opt == 17) {
+               *mult = 1;
+               *div  = 2;
+       } else {
+               *mult = 0;
+               *div  = 1;
+       }
+}
+
+static const struct coreclk_soc_desc mv88f6183_coreclks = {
+       .get_tclk_freq = mv88f6183_get_tclk_freq,
+       .get_cpu_freq = mv88f6183_get_cpu_freq,
+       .get_clk_ratio = mv88f6183_get_clk_ratio,
+       .ratios = orion_coreclk_ratios,
+       .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+
+static void __init mv88f6183_clk_init(struct device_node *np)
+{
+       return mvebu_coreclk_setup(np, &mv88f6183_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init);
index 8eb4799237f03d5106cfe52537c587fb7fc648dd..77313e27bc397ee87c21a1dd6a29cd8f9cb1003e 100644 (file)
@@ -8,4 +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
+obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
+obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
 obj-$(CONFIG_ARCH_S3C64XX)     += clk-s3c64xx.o
index 81e6d2f49aa001a9587b33e848c0b4692d5d82e0..7fb0a28e65d5f4b582ae76fc38ebff8287f5ec80 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/errno.h>
 #include <linux/hrtimer.h>
+#include <linux/delay.h>
 #include "clk.h"
 #include "clk-pll.h"
 
@@ -58,6 +59,72 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
        return rate_table[i - 1].rate;
 }
 
+/*
+ * PLL2126 Clock Type
+ */
+
+#define PLL2126_MDIV_MASK      (0xff)
+#define PLL2126_PDIV_MASK      (0x3f)
+#define PLL2126_SDIV_MASK      (0x3)
+#define PLL2126_MDIV_SHIFT     (16)
+#define PLL2126_PDIV_SHIFT     (8)
+#define PLL2126_SDIV_SHIFT     (0)
+
+static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
+                               unsigned long parent_rate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 pll_con, mdiv, pdiv, sdiv;
+       u64 fvco = parent_rate;
+
+       pll_con = __raw_readl(pll->con_reg);
+       mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
+       pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
+       sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
+
+       fvco *= (mdiv + 8);
+       do_div(fvco, (pdiv + 2) << sdiv);
+
+       return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll2126_clk_ops = {
+       .recalc_rate = samsung_pll2126_recalc_rate,
+};
+
+/*
+ * PLL3000 Clock Type
+ */
+
+#define PLL3000_MDIV_MASK      (0xff)
+#define PLL3000_PDIV_MASK      (0x3)
+#define PLL3000_SDIV_MASK      (0x3)
+#define PLL3000_MDIV_SHIFT     (16)
+#define PLL3000_PDIV_SHIFT     (8)
+#define PLL3000_SDIV_SHIFT     (0)
+
+static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
+                               unsigned long parent_rate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 pll_con, mdiv, pdiv, sdiv;
+       u64 fvco = parent_rate;
+
+       pll_con = __raw_readl(pll->con_reg);
+       mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
+       pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
+       sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
+
+       fvco *= (2 * (mdiv + 8));
+       do_div(fvco, pdiv << sdiv);
+
+       return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll3000_clk_ops = {
+       .recalc_rate = samsung_pll3000_recalc_rate,
+};
+
 /*
  * PLL35xx Clock Type
  */
@@ -564,7 +631,9 @@ static const struct clk_ops samsung_pll46xx_clk_min_ops = {
 #define PLL6552_PDIV_MASK      0x3f
 #define PLL6552_SDIV_MASK      0x7
 #define PLL6552_MDIV_SHIFT     16
+#define PLL6552_MDIV_SHIFT_2416        14
 #define PLL6552_PDIV_SHIFT     8
+#define PLL6552_PDIV_SHIFT_2416        5
 #define PLL6552_SDIV_SHIFT     0
 
 static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
@@ -575,8 +644,13 @@ static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
        u64 fvco = parent_rate;
 
        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;
+       if (pll->type == pll_6552_s3c2416) {
+               mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
+               pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
+       } else {
+               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;
 
        fvco *= mdiv;
@@ -627,6 +701,169 @@ static const struct clk_ops samsung_pll6553_clk_ops = {
        .recalc_rate = samsung_pll6553_recalc_rate,
 };
 
+/*
+ * PLL Clock Type of S3C24XX before S3C2443
+ */
+
+#define PLLS3C2410_MDIV_MASK           (0xff)
+#define PLLS3C2410_PDIV_MASK           (0x1f)
+#define PLLS3C2410_SDIV_MASK           (0x3)
+#define PLLS3C2410_MDIV_SHIFT          (12)
+#define PLLS3C2410_PDIV_SHIFT          (4)
+#define PLLS3C2410_SDIV_SHIFT          (0)
+
+#define PLLS3C2410_ENABLE_REG_OFFSET   0x10
+
+static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 pll_con, mdiv, pdiv, sdiv;
+       u64 fvco = parent_rate;
+
+       pll_con = __raw_readl(pll->con_reg);
+       mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
+       pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
+       sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
+
+       fvco *= (mdiv + 8);
+       do_div(fvco, (pdiv + 2) << sdiv);
+
+       return (unsigned int)fvco;
+}
+
+static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 pll_con, mdiv, pdiv, sdiv;
+       u64 fvco = parent_rate;
+
+       pll_con = __raw_readl(pll->con_reg);
+       mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
+       pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
+       sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
+
+       fvco *= (2 * (mdiv + 8));
+       do_div(fvco, (pdiv + 2) << sdiv);
+
+       return (unsigned int)fvco;
+}
+
+static int samsung_s3c2410_pll_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;
+       }
+
+       tmp = __raw_readl(pll->con_reg);
+
+       /* Change PLL PMS values */
+       tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
+                       (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
+                       (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
+       tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
+                       (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
+                       (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
+       __raw_writel(tmp, pll->con_reg);
+
+       /* Time to settle according to the manual */
+       udelay(300);
+
+       return 0;
+}
+
+static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
+       u32 pll_en_orig = pll_en;
+
+       if (enable)
+               pll_en &= ~BIT(bit);
+       else
+               pll_en |= BIT(bit);
+
+       __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
+
+       /* if we started the UPLL, then allow to settle */
+       if (enable && (pll_en_orig & BIT(bit)))
+               udelay(300);
+
+       return 0;
+}
+
+static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
+{
+       return samsung_s3c2410_pll_enable(hw, 5, true);
+}
+
+static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
+{
+       samsung_s3c2410_pll_enable(hw, 5, false);
+}
+
+static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
+{
+       return samsung_s3c2410_pll_enable(hw, 7, true);
+}
+
+static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
+{
+       samsung_s3c2410_pll_enable(hw, 7, false);
+}
+
+static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
+       .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+       .enable = samsung_s3c2410_mpll_enable,
+       .disable = samsung_s3c2410_mpll_disable,
+};
+
+static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
+       .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+       .enable = samsung_s3c2410_upll_enable,
+       .disable = samsung_s3c2410_upll_disable,
+};
+
+static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
+       .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
+       .enable = samsung_s3c2410_mpll_enable,
+       .disable = samsung_s3c2410_mpll_disable,
+};
+
+static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
+       .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+       .enable = samsung_s3c2410_mpll_enable,
+       .disable = samsung_s3c2410_mpll_disable,
+       .round_rate = samsung_pll_round_rate,
+       .set_rate = samsung_s3c2410_pll_set_rate,
+};
+
+static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
+       .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+       .enable = samsung_s3c2410_upll_enable,
+       .disable = samsung_s3c2410_upll_disable,
+       .round_rate = samsung_pll_round_rate,
+       .set_rate = samsung_s3c2410_pll_set_rate,
+};
+
+static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
+       .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
+       .enable = samsung_s3c2410_mpll_enable,
+       .disable = samsung_s3c2410_mpll_disable,
+       .round_rate = samsung_pll_round_rate,
+       .set_rate = samsung_s3c2410_pll_set_rate,
+};
+
 /*
  * PLL2550x Clock Type
  */
@@ -746,6 +983,12 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
        }
 
        switch (pll_clk->type) {
+       case pll_2126:
+               init.ops = &samsung_pll2126_clk_ops;
+               break;
+       case pll_3000:
+               init.ops = &samsung_pll3000_clk_ops;
+               break;
        /* clk_ops for 35xx and 2550 are similar */
        case pll_35xx:
        case pll_2550:
@@ -773,6 +1016,7 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
                        init.ops = &samsung_pll36xx_clk_ops;
                break;
        case pll_6552:
+       case pll_6552_s3c2416:
                init.ops = &samsung_pll6552_clk_ops;
                break;
        case pll_6553:
@@ -786,6 +1030,24 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
                else
                        init.ops = &samsung_pll46xx_clk_ops;
                break;
+       case pll_s3c2410_mpll:
+               if (!pll->rate_table)
+                       init.ops = &samsung_s3c2410_mpll_clk_min_ops;
+               else
+                       init.ops = &samsung_s3c2410_mpll_clk_ops;
+               break;
+       case pll_s3c2410_upll:
+               if (!pll->rate_table)
+                       init.ops = &samsung_s3c2410_upll_clk_min_ops;
+               else
+                       init.ops = &samsung_s3c2410_upll_clk_ops;
+               break;
+       case pll_s3c2440_mpll:
+               if (!pll->rate_table)
+                       init.ops = &samsung_s3c2440_mpll_clk_min_ops;
+               else
+                       init.ops = &samsung_s3c2440_mpll_clk_ops;
+               break;
        default:
                pr_warn("%s: Unknown pll type for pll clk %s\n",
                        __func__, pll_clk->name);
index 6c39030080fbede41fe6a4e52cdd87a7263aae18..6428bcc6df6f0791c0aa12d47da50ddf56e1f07d 100644 (file)
@@ -13,6 +13,8 @@
 #define __SAMSUNG_CLK_PLL_H
 
 enum samsung_pll_type {
+       pll_2126,
+       pll_3000,
        pll_35xx,
        pll_36xx,
        pll_2550,
@@ -24,7 +26,11 @@ enum samsung_pll_type {
        pll_4650,
        pll_4650c,
        pll_6552,
+       pll_6552_s3c2416,
        pll_6553,
+       pll_s3c2410_mpll,
+       pll_s3c2410_upll,
+       pll_s3c2440_mpll,
 };
 
 #define PLL_35XX_RATE(_rate, _m, _p, _s)                       \
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
new file mode 100644 (file)
index 0000000..0f11a07
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for S3C2412 and S3C2413.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/s3c2412.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+#define LOCKTIME       0x00
+#define MPLLCON                0x04
+#define UPLLCON                0x08
+#define CLKCON         0x0c
+#define CLKDIVN                0x14
+#define CLKSRC         0x1c
+
+/* list of PLLs to be registered */
+enum s3c2412_plls {
+       mpll, upll,
+};
+
+static void __iomem *reg_base;
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *s3c2412_save;
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static unsigned long s3c2412_clk_regs[] __initdata = {
+       LOCKTIME,
+       MPLLCON,
+       UPLLCON,
+       CLKCON,
+       CLKDIVN,
+       CLKSRC,
+};
+
+static int s3c2412_clk_suspend(void)
+{
+       samsung_clk_save(reg_base, s3c2412_save,
+                               ARRAY_SIZE(s3c2412_clk_regs));
+
+       return 0;
+}
+
+static void s3c2412_clk_resume(void)
+{
+       samsung_clk_restore(reg_base, s3c2412_save,
+                               ARRAY_SIZE(s3c2412_clk_regs));
+}
+
+static struct syscore_ops s3c2412_clk_syscore_ops = {
+       .suspend = s3c2412_clk_suspend,
+       .resume = s3c2412_clk_resume,
+};
+
+static void s3c2412_clk_sleep_init(void)
+{
+       s3c2412_save = samsung_clk_alloc_reg_dump(s3c2412_clk_regs,
+                                               ARRAY_SIZE(s3c2412_clk_regs));
+       if (!s3c2412_save) {
+               pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
+                       __func__);
+               return;
+       }
+
+       register_syscore_ops(&s3c2412_clk_syscore_ops);
+       return;
+}
+#else
+static void s3c2412_clk_sleep_init(void) {}
+#endif
+
+static struct clk_div_table divxti_d[] = {
+       { .val = 0, .div = 1 },
+       { .val = 1, .div = 2 },
+       { .val = 2, .div = 4 },
+       { .val = 3, .div = 6 },
+       { .val = 4, .div = 8 },
+       { .val = 5, .div = 10 },
+       { .val = 6, .div = 12 },
+       { .val = 7, .div = 14 },
+       { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2412_dividers[] __initdata = {
+       DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d),
+       DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4),
+       DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4),
+       DIV(0, "div_uart", "mux_uart", CLKDIVN, 8, 4),
+       DIV(0, "div_usb", "mux_usb", CLKDIVN, 6, 1),
+       DIV(0, "div_hclk_half", "hclk", CLKDIVN, 5, 1),
+       DIV(ARMDIV, "armdiv", "msysclk", CLKDIVN, 3, 1),
+       DIV(PCLK, "pclk", "hclk", CLKDIVN, 2, 1),
+       DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2),
+};
+
+struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = {
+       FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT),
+};
+
+/*
+ * The first two use the OM[4] setting, which is not readable from
+ * software, so assume it is set to xti.
+ */
+PNAME(erefclk_p) = { "xti", "xti", "xti", "ext" };
+PNAME(urefclk_p) = { "xti", "xti", "xti", "ext" };
+
+PNAME(camclk_p) = { "usysclk", "hclk" };
+PNAME(usbclk_p) = { "usysclk", "hclk" };
+PNAME(i2sclk_p) = { "erefclk", "mpll" };
+PNAME(uartclk_p) = { "erefclk", "mpll" };
+PNAME(usysclk_p) = { "urefclk", "upll" };
+PNAME(msysclk_p) = { "mdivclk", "mpll" };
+PNAME(mdivclk_p) = { "xti", "div_xti" };
+PNAME(armclk_p) = { "armdiv", "hclk" };
+
+struct samsung_mux_clock s3c2412_muxes[] __initdata = {
+       MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2),
+       MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2),
+       MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1),
+       MUX(0, "mux_usb", usbclk_p, CLKSRC, 10, 1),
+       MUX(0, "mux_i2s", i2sclk_p, CLKSRC, 9, 1),
+       MUX(0, "mux_uart", uartclk_p, CLKSRC, 8, 1),
+       MUX(USYSCLK, "usysclk", usysclk_p, CLKSRC, 5, 1),
+       MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1),
+       MUX(MDIVCLK, "mdivclk", mdivclk_p, CLKSRC, 3, 1),
+       MUX(ARMCLK, "armclk", armclk_p, CLKDIVN, 4, 1),
+};
+
+static struct samsung_pll_clock s3c2412_plls[] __initdata = {
+       [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti",
+                                               LOCKTIME, MPLLCON, NULL),
+       [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk",
+                                               LOCKTIME, UPLLCON, NULL),
+};
+
+struct samsung_gate_clock s3c2412_gates[] __initdata = {
+       GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0),
+       GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0),
+       GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0),
+       GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 25, 0, 0),
+       GATE(PCLK_ADC, "adc", "pclk", CLKCON, 24, 0, 0),
+       GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 23, 0, 0),
+       GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 22, CLK_IGNORE_UNUSED, 0),
+       GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 21, 0, 0),
+       GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 20, 0, 0),
+       GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 19, 0, 0),
+       GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 18, 0, 0),
+       GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 17, 0, 0),
+       GATE(PCLK_USBD, "usb-device", "pclk", CLKCON, 16, 0, 0),
+       GATE(SCLK_CAM, "sclk_cam", "div_cam", CLKCON, 15, 0, 0),
+       GATE(SCLK_UART, "sclk_uart", "div_uart", CLKCON, 14, 0, 0),
+       GATE(SCLK_I2S, "sclk_i2s", "div_i2s", CLKCON, 13, 0, 0),
+       GATE(SCLK_USBH, "sclk_usbh", "div_usb", CLKCON, 12, 0, 0),
+       GATE(SCLK_USBD, "sclk_usbd", "div_usb", CLKCON, 11, 0, 0),
+       GATE(HCLK_HALF, "hclk_half", "div_hclk_half", CLKCON, 10, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_X2, "hclkx2", "ff_hclk", CLKCON, 9, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_SDRAM, "sdram", "hclk", CLKCON, 8, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0),
+       GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0),
+       GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0),
+       GATE(HCLK_DMA3, "dma3", "hclk", CLKCON, 3, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA2, "dma2", "hclk", CLKCON, 2, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA1, "dma1", "hclk", CLKCON, 1, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0),
+};
+
+struct samsung_clock_alias s3c2412_aliases[] __initdata = {
+       ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"),
+       ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"),
+       ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"),
+       ALIAS(PCLK_UART0, "s3c2412-uart.0", "clk_uart_baud2"),
+       ALIAS(PCLK_UART1, "s3c2412-uart.1", "clk_uart_baud2"),
+       ALIAS(PCLK_UART2, "s3c2412-uart.2", "clk_uart_baud2"),
+       ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
+       ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"),
+       ALIAS(PCLK_ADC, NULL, "adc"),
+       ALIAS(PCLK_RTC, NULL, "rtc"),
+       ALIAS(PCLK_PWM, NULL, "timers"),
+       ALIAS(HCLK_LCD, NULL, "lcd"),
+       ALIAS(PCLK_USBD, NULL, "usb-device"),
+       ALIAS(SCLK_USBD, NULL, "usb-bus-gadget"),
+       ALIAS(HCLK_USBH, NULL, "usb-host"),
+       ALIAS(SCLK_USBH, NULL, "usb-bus-host"),
+       ALIAS(ARMCLK, NULL, "armclk"),
+       ALIAS(HCLK, NULL, "hclk"),
+       ALIAS(MPLL, NULL, "mpll"),
+       ALIAS(MSYSCLK, NULL, "fclk"),
+};
+
+/*
+ * fixed rate clocks generated outside the soc
+ * Only necessary until the devicetree-move is complete
+ */
+#define XTI    1
+struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = {
+       FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0),
+       FRATE(0, "ext", NULL, CLK_IS_ROOT, 0),
+};
+
+static void __init s3c2412_common_clk_register_fixed_ext(unsigned long xti_f,
+                                                        unsigned long ext_f)
+{
+       /* xtal alias is necessary for the current cpufreq driver */
+       struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal");
+
+       s3c2412_common_frate_clks[0].fixed_rate = xti_f;
+       s3c2412_common_frate_clks[1].fixed_rate = ext_f;
+       samsung_clk_register_fixed_rate(s3c2412_common_frate_clks,
+                               ARRAY_SIZE(s3c2412_common_frate_clks));
+
+       samsung_clk_register_alias(&xti_alias, 1);
+}
+
+void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
+                                   unsigned long ext_f, void __iomem *base)
+{
+       reg_base = base;
+
+       if (np) {
+               reg_base = of_iomap(np, 0);
+               if (!reg_base)
+                       panic("%s: failed to map registers\n", __func__);
+       }
+
+       samsung_clk_init(np, reg_base, NR_CLKS);
+
+       /* Register external clocks only in non-dt cases */
+       if (!np)
+               s3c2412_common_clk_register_fixed_ext(xti_f, ext_f);
+
+       /* Register PLLs. */
+       samsung_clk_register_pll(s3c2412_plls, ARRAY_SIZE(s3c2412_plls),
+                                reg_base);
+
+       /* Register common internal clocks. */
+       samsung_clk_register_mux(s3c2412_muxes, ARRAY_SIZE(s3c2412_muxes));
+       samsung_clk_register_div(s3c2412_dividers,
+                                         ARRAY_SIZE(s3c2412_dividers));
+       samsung_clk_register_gate(s3c2412_gates, ARRAY_SIZE(s3c2412_gates));
+       samsung_clk_register_fixed_factor(s3c2412_ffactor,
+                                         ARRAY_SIZE(s3c2412_ffactor));
+       samsung_clk_register_alias(s3c2412_aliases,
+                                  ARRAY_SIZE(s3c2412_aliases));
+
+       s3c2412_clk_sleep_init();
+}
+
+static void __init s3c2412_clk_init(struct device_node *np)
+{
+       s3c2412_common_clk_init(np, 0, 0, 0);
+}
+CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init);
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
new file mode 100644 (file)
index 0000000..8e4f451
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for S3C2443 and following SoCs.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/s3c2443.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+/* S3C2416 clock controller register offsets */
+#define LOCKCON0       0x00
+#define LOCKCON1       0x04
+#define MPLLCON                0x10
+#define EPLLCON                0x18
+#define EPLLCON_K      0x1C
+#define CLKSRC         0x20
+#define CLKDIV0                0x24
+#define CLKDIV1                0x28
+#define CLKDIV2                0x2C
+#define HCLKCON                0x30
+#define PCLKCON                0x34
+#define SCLKCON                0x38
+
+/* the soc types */
+enum supported_socs {
+       S3C2416,
+       S3C2443,
+       S3C2450,
+};
+
+/* list of PLLs to be registered */
+enum s3c2443_plls {
+       mpll, epll,
+};
+
+static void __iomem *reg_base;
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *s3c2443_save;
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static unsigned long s3c2443_clk_regs[] __initdata = {
+       LOCKCON0,
+       LOCKCON1,
+       MPLLCON,
+       EPLLCON,
+       EPLLCON_K,
+       CLKSRC,
+       CLKDIV0,
+       CLKDIV1,
+       CLKDIV2,
+       PCLKCON,
+       HCLKCON,
+       SCLKCON,
+};
+
+static int s3c2443_clk_suspend(void)
+{
+       samsung_clk_save(reg_base, s3c2443_save,
+                               ARRAY_SIZE(s3c2443_clk_regs));
+
+       return 0;
+}
+
+static void s3c2443_clk_resume(void)
+{
+       samsung_clk_restore(reg_base, s3c2443_save,
+                               ARRAY_SIZE(s3c2443_clk_regs));
+}
+
+static struct syscore_ops s3c2443_clk_syscore_ops = {
+       .suspend = s3c2443_clk_suspend,
+       .resume = s3c2443_clk_resume,
+};
+
+static void s3c2443_clk_sleep_init(void)
+{
+       s3c2443_save = samsung_clk_alloc_reg_dump(s3c2443_clk_regs,
+                                               ARRAY_SIZE(s3c2443_clk_regs));
+       if (!s3c2443_save) {
+               pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
+                       __func__);
+               return;
+       }
+
+       register_syscore_ops(&s3c2443_clk_syscore_ops);
+       return;
+}
+#else
+static void s3c2443_clk_sleep_init(void) {}
+#endif
+
+PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" };
+PNAME(esysclk_p) = { "epllref", "epll" };
+PNAME(mpllref_p) = { "xti", "mdivclk" };
+PNAME(msysclk_p) = { "mpllref", "mpll" };
+PNAME(armclk_p) = { "armdiv" , "hclk" };
+PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" };
+
+struct samsung_mux_clock s3c2443_common_muxes[] __initdata = {
+       MUX(0, "epllref", epllref_p, CLKSRC, 7, 2),
+       MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1),
+       MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1),
+       MUX_A(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1, "msysclk"),
+       MUX_A(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1, "armclk"),
+       MUX(0, "mux_i2s0", i2s0_p, CLKSRC, 14, 2),
+};
+
+static struct clk_div_table hclk_d[] = {
+       { .val = 0, .div = 1 },
+       { .val = 1, .div = 2 },
+       { .val = 3, .div = 4 },
+       { /* sentinel */ },
+};
+
+static struct clk_div_table mdivclk_d[] = {
+       { .val = 0, .div = 1 },
+       { .val = 1, .div = 3 },
+       { .val = 2, .div = 5 },
+       { .val = 3, .div = 7 },
+       { .val = 4, .div = 9 },
+       { .val = 5, .div = 11 },
+       { .val = 6, .div = 13 },
+       { .val = 7, .div = 15 },
+       { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2443_common_dividers[] __initdata = {
+       DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d),
+       DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2),
+       DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d),
+       DIV(PCLK, "pclk", "hclk", CLKDIV0, 2, 1),
+       DIV(0, "div_hsspi0_epll", "esysclk", CLKDIV1, 24, 2),
+       DIV(0, "div_fimd", "esysclk", CLKDIV1, 16, 8),
+       DIV(0, "div_i2s0", "esysclk", CLKDIV1, 12, 4),
+       DIV(0, "div_uart", "esysclk", CLKDIV1, 8, 4),
+       DIV(0, "div_hsmmc1", "esysclk", CLKDIV1, 6, 2),
+       DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2),
+};
+
+struct samsung_gate_clock s3c2443_common_gates[] __initdata = {
+       GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0),
+       GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0),
+       GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0),
+       GATE(SCLK_I2S0, "sclk_i2s0", "mux_i2s0", SCLKCON, 9, 0, 0),
+       GATE(SCLK_UART, "sclk_uart", "div_uart", SCLKCON, 8, 0, 0),
+       GATE(SCLK_USBH, "sclk_usbhost", "div_usbhost", SCLKCON, 1, 0, 0),
+       GATE(HCLK_DRAM, "dram", "hclk", HCLKCON, 19, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_SSMC, "ssmc", "hclk", HCLKCON, 18, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_HSMMC1, "hsmmc1", "hclk", HCLKCON, 16, 0, 0),
+       GATE(HCLK_USBD, "usb-device", "hclk", HCLKCON, 12, 0, 0),
+       GATE(HCLK_USBH, "usb-host", "hclk", HCLKCON, 11, 0, 0),
+       GATE(HCLK_LCD, "lcd", "hclk", HCLKCON, 9, 0, 0),
+       GATE(HCLK_DMA5, "dma5", "hclk", HCLKCON, 5, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA4, "dma4", "hclk", HCLKCON, 4, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA3, "dma3", "hclk", HCLKCON, 3, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA2, "dma2", "hclk", HCLKCON, 2, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA1, "dma1", "hclk", HCLKCON, 1, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA0, "dma0", "hclk", HCLKCON, 0, CLK_IGNORE_UNUSED, 0),
+       GATE(PCLK_GPIO, "gpio", "pclk", PCLKCON, 13, CLK_IGNORE_UNUSED, 0),
+       GATE(PCLK_RTC, "rtc", "pclk", PCLKCON, 12, 0, 0),
+       GATE(PCLK_WDT, "wdt", "pclk", PCLKCON, 11, 0, 0),
+       GATE(PCLK_PWM, "pwm", "pclk", PCLKCON, 10, 0, 0),
+       GATE(PCLK_I2S0, "i2s0", "pclk", PCLKCON, 9, 0, 0),
+       GATE(PCLK_AC97, "ac97", "pclk", PCLKCON, 8, 0, 0),
+       GATE(PCLK_ADC, "adc", "pclk", PCLKCON, 7, 0, 0),
+       GATE(PCLK_SPI0, "spi0", "pclk", PCLKCON, 6, 0, 0),
+       GATE(PCLK_I2C0, "i2c0", "pclk", PCLKCON, 4, 0, 0),
+       GATE(PCLK_UART3, "uart3", "pclk", PCLKCON, 3, 0, 0),
+       GATE(PCLK_UART2, "uart2", "pclk", PCLKCON, 2, 0, 0),
+       GATE(PCLK_UART1, "uart1", "pclk", PCLKCON, 1, 0, 0),
+       GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0),
+};
+
+struct samsung_clock_alias s3c2443_common_aliases[] __initdata = {
+       ALIAS(HCLK, NULL, "hclk"),
+       ALIAS(HCLK_SSMC, NULL, "nand"),
+       ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"),
+       ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"),
+       ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"),
+       ALIAS(PCLK_UART3, "s3c2440-uart.3", "uart"),
+       ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"),
+       ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"),
+       ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"),
+       ALIAS(PCLK_UART3, "s3c2440-uart.3", "clk_uart_baud2"),
+       ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
+       ALIAS(PCLK_PWM, NULL, "timers"),
+       ALIAS(PCLK_RTC, NULL, "rtc"),
+       ALIAS(PCLK_WDT, NULL, "watchdog"),
+       ALIAS(PCLK_ADC, NULL, "adc"),
+       ALIAS(PCLK_I2C0, "s3c2410-i2c.0", "i2c"),
+       ALIAS(HCLK_USBD, NULL, "usb-device"),
+       ALIAS(HCLK_USBH, NULL, "usb-host"),
+       ALIAS(SCLK_USBH, NULL, "usb-bus-host"),
+       ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi"),
+       ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi_busclk0"),
+       ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "hsmmc"),
+       ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
+       ALIAS(PCLK_I2S0, "samsung-i2s.0", "iis"),
+       ALIAS(SCLK_I2S0, NULL, "i2s-if"),
+       ALIAS(HCLK_LCD, NULL, "lcd"),
+       ALIAS(SCLK_FIMD, NULL, "sclk_fimd"),
+};
+
+/* S3C2416 specific clocks */
+
+static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = {
+       [mpll] = PLL(pll_6552_s3c2416, 0, "mpll", "mpllref",
+                                               LOCKCON0, MPLLCON, NULL),
+       [epll] = PLL(pll_6553, 0, "epll", "epllref",
+                                               LOCKCON1, EPLLCON, NULL),
+};
+
+PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" };
+PNAME(s3c2416_hsmmc1_p) = { "sclk_hsmmc1", "sclk_hsmmcext" };
+PNAME(s3c2416_hsspi0_p) = { "hsspi0_epll", "hsspi0_mpll" };
+
+static struct clk_div_table armdiv_s3c2416_d[] = {
+       { .val = 0, .div = 1 },
+       { .val = 1, .div = 2 },
+       { .val = 2, .div = 3 },
+       { .val = 3, .div = 4 },
+       { .val = 5, .div = 6 },
+       { .val = 7, .div = 8 },
+       { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2416_dividers[] __initdata = {
+       DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d),
+       DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4),
+       DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2),
+};
+
+struct samsung_mux_clock s3c2416_muxes[] __initdata = {
+       MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1),
+       MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1),
+       MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1),
+};
+
+struct samsung_gate_clock s3c2416_gates[] __initdata = {
+       GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0),
+       GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
+       GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0),
+       GATE(HCLK_2D, "2d", "hclk", HCLKCON, 20, 0, 0),
+       GATE(HCLK_HSMMC0, "hsmmc0", "hclk", HCLKCON, 15, 0, 0),
+       GATE(HCLK_IROM, "irom", "hclk", HCLKCON, 13, CLK_IGNORE_UNUSED, 0),
+       GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0),
+};
+
+struct samsung_clock_alias s3c2416_aliases[] __initdata = {
+       ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
+       ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
+       ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"),
+       ALIAS(MUX_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"),
+       ALIAS(MUX_HSSPI0, "s3c2443-spi.0", "spi_busclk2"),
+       ALIAS(ARMDIV, NULL, "armdiv"),
+};
+
+/* S3C2443 specific clocks */
+
+static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = {
+       [mpll] = PLL(pll_3000, 0, "mpll", "mpllref",
+                                               LOCKCON0, MPLLCON, NULL),
+       [epll] = PLL(pll_2126, 0, "epll", "epllref",
+                                               LOCKCON1, EPLLCON, NULL),
+};
+
+static struct clk_div_table armdiv_s3c2443_d[] = {
+       { .val = 0, .div = 1 },
+       { .val = 8, .div = 2 },
+       { .val = 2, .div = 3 },
+       { .val = 9, .div = 4 },
+       { .val = 10, .div = 6 },
+       { .val = 11, .div = 8 },
+       { .val = 13, .div = 12 },
+       { .val = 15, .div = 16 },
+       { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2443_dividers[] __initdata = {
+       DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d),
+       DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4),
+};
+
+struct samsung_gate_clock s3c2443_gates[] __initdata = {
+       GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
+       GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0),
+       GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0),
+       GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 15, 0, 0),
+       GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0),
+};
+
+struct samsung_clock_alias s3c2443_aliases[] __initdata = {
+       ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"),
+       ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"),
+       ALIAS(SCLK_CAM, NULL, "camif-upll"),
+       ALIAS(PCLK_SPI1, "s3c2410-spi.0", "spi"),
+       ALIAS(PCLK_SDI, NULL, "sdi"),
+       ALIAS(HCLK_CFC, NULL, "cfc"),
+       ALIAS(ARMDIV, NULL, "armdiv"),
+};
+
+/* S3C2450 specific clocks */
+
+PNAME(s3c2450_cam_p) = { "div_cam", "hclk" };
+PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" };
+PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" };
+
+struct samsung_div_clock s3c2450_dividers[] __initdata = {
+       DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4),
+       DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2),
+       DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4),
+       DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4),
+};
+
+struct samsung_mux_clock s3c2450_muxes[] __initdata = {
+       MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1),
+       MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1),
+       MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2),
+};
+
+struct samsung_gate_clock s3c2450_gates[] __initdata = {
+       GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0),
+       GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0),
+       GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0),
+       GATE(HCLK_DMA7, "dma7", "hclk", HCLKCON, 7, CLK_IGNORE_UNUSED, 0),
+       GATE(HCLK_DMA6, "dma6", "hclk", HCLKCON, 6, CLK_IGNORE_UNUSED, 0),
+       GATE(PCLK_I2S1, "i2s1", "pclk", PCLKCON, 17, 0, 0),
+       GATE(PCLK_I2C1, "i2c1", "pclk", PCLKCON, 16, 0, 0),
+       GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0),
+};
+
+struct samsung_clock_alias s3c2450_aliases[] __initdata = {
+       ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"),
+       ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"),
+       ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"),
+       ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"),
+};
+
+/*
+ * fixed rate clocks generated outside the soc
+ * Only necessary until the devicetree-move is complete
+ */
+struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = {
+       FRATE(0, "xti", NULL, CLK_IS_ROOT, 0),
+       FRATE(0, "ext", NULL, CLK_IS_ROOT, 0),
+       FRATE(0, "ext_i2s", NULL, CLK_IS_ROOT, 0),
+       FRATE(0, "ext_uart", NULL, CLK_IS_ROOT, 0),
+};
+
+static void __init s3c2443_common_clk_register_fixed_ext(unsigned long xti_f)
+{
+       s3c2443_common_frate_clks[0].fixed_rate = xti_f;
+       samsung_clk_register_fixed_rate(s3c2443_common_frate_clks,
+                               ARRAY_SIZE(s3c2443_common_frate_clks));
+}
+
+void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
+                                   int current_soc,
+                                   void __iomem *base)
+{
+       reg_base = base;
+
+       if (np) {
+               reg_base = of_iomap(np, 0);
+               if (!reg_base)
+                       panic("%s: failed to map registers\n", __func__);
+       }
+
+       samsung_clk_init(np, reg_base, NR_CLKS);
+
+       /* Register external clocks only in non-dt cases */
+       if (!np)
+               s3c2443_common_clk_register_fixed_ext(xti_f);
+
+       /* Register PLLs. */
+       if (current_soc == S3C2416 || current_soc == S3C2450)
+               samsung_clk_register_pll(s3c2416_pll_clks,
+                               ARRAY_SIZE(s3c2416_pll_clks), reg_base);
+       else
+               samsung_clk_register_pll(s3c2443_pll_clks,
+                               ARRAY_SIZE(s3c2443_pll_clks), reg_base);
+
+       /* Register common internal clocks. */
+       samsung_clk_register_mux(s3c2443_common_muxes,
+                       ARRAY_SIZE(s3c2443_common_muxes));
+       samsung_clk_register_div(s3c2443_common_dividers,
+                       ARRAY_SIZE(s3c2443_common_dividers));
+       samsung_clk_register_gate(s3c2443_common_gates,
+               ARRAY_SIZE(s3c2443_common_gates));
+       samsung_clk_register_alias(s3c2443_common_aliases,
+               ARRAY_SIZE(s3c2443_common_aliases));
+
+       /* Register SoC-specific clocks. */
+       switch (current_soc) {
+       case S3C2450:
+               samsung_clk_register_div(s3c2450_dividers,
+                               ARRAY_SIZE(s3c2450_dividers));
+               samsung_clk_register_mux(s3c2450_muxes,
+                               ARRAY_SIZE(s3c2450_muxes));
+               samsung_clk_register_gate(s3c2450_gates,
+                               ARRAY_SIZE(s3c2450_gates));
+               samsung_clk_register_alias(s3c2450_aliases,
+                               ARRAY_SIZE(s3c2450_aliases));
+               /* fall through, as s3c2450 extends the s3c2416 clocks */
+       case S3C2416:
+               samsung_clk_register_div(s3c2416_dividers,
+                               ARRAY_SIZE(s3c2416_dividers));
+               samsung_clk_register_mux(s3c2416_muxes,
+                               ARRAY_SIZE(s3c2416_muxes));
+               samsung_clk_register_gate(s3c2416_gates,
+                               ARRAY_SIZE(s3c2416_gates));
+               samsung_clk_register_alias(s3c2416_aliases,
+                               ARRAY_SIZE(s3c2416_aliases));
+               break;
+       case S3C2443:
+               samsung_clk_register_div(s3c2443_dividers,
+                               ARRAY_SIZE(s3c2443_dividers));
+               samsung_clk_register_gate(s3c2443_gates,
+                               ARRAY_SIZE(s3c2443_gates));
+               samsung_clk_register_alias(s3c2443_aliases,
+                               ARRAY_SIZE(s3c2443_aliases));
+               break;
+       }
+
+       s3c2443_clk_sleep_init();
+}
+
+static void __init s3c2416_clk_init(struct device_node *np)
+{
+       s3c2443_common_clk_init(np, 0, S3C2416, 0);
+}
+CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init);
+
+static void __init s3c2443_clk_init(struct device_node *np)
+{
+       s3c2443_common_clk_init(np, 0, S3C2443, 0);
+}
+CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init);
+
+static void __init s3c2450_clk_init(struct device_node *np)
+{
+       s3c2443_common_clk_init(np, 0, S3C2450, 0);
+}
+CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init);
index 67c8de572c50188af9fb50a1629bcfd0a73193f0..b4877e0ee91051ddbc2cebc4d4d569c6ffc3c2cb 100644 (file)
@@ -110,9 +110,25 @@ static struct ti_dt_clk am43xx_clks[] = {
 
 int __init am43xx_dt_clk_init(void)
 {
+       struct clk *clk1, *clk2;
+
        ti_dt_clocks_register(am43xx_clks);
 
        omap2_clk_disable_autoidle_all();
 
+       /*
+        * cpsw_cpts_rft_clk  has got the choice of 3 clocksources
+        * dpll_core_m4_ck, dpll_core_m5_ck and dpll_disp_m2_ck.
+        * By default dpll_core_m4_ck is selected, witn this as clock
+        * source the CPTS doesnot work properly. It gives clockcheck errors
+        * while running PTP.
+        * clockcheck: clock jumped backward or running slower than expected!
+        * By selecting dpll_core_m5_ck as the clocksource fixes this issue.
+        * In AM335x dpll_core_m5_ck is the default clocksource.
+        */
+       clk1 = clk_get_sys(NULL, "cpsw_cpts_rft_clk");
+       clk2 = clk_get_sys(NULL, "dpll_core_m5_ck");
+       clk_set_parent(clk1, clk2);
+
        return 0;
 }
index a535c7bf85745144a99d86ff86fc27c0399ff8ab..422391242b39ceac4a322ee532288ee46b6eba32 100644 (file)
@@ -100,6 +100,8 @@ void __init vexpress_osc_of_setup(struct device_node *node)
        struct clk *clk;
        u32 range[2];
 
+       vexpress_sysreg_of_early_init();
+
        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
        if (!osc)
                return;
index 57e823c44d2ad326eeaaa788fbb67d80ba620c7d..5163ec13429d1e37082b8d32c84684284217322f 100644 (file)
@@ -66,6 +66,7 @@ static int arch_timer_ppi[MAX_TIMER_PPI];
 static struct clock_event_device __percpu *arch_timer_evt;
 
 static bool arch_timer_use_virtual = true;
+static bool arch_timer_c3stop;
 static bool arch_timer_mem_use_virtual;
 
 /*
@@ -263,7 +264,8 @@ static void __arch_timer_setup(unsigned type,
        clk->features = CLOCK_EVT_FEAT_ONESHOT;
 
        if (type == ARCH_CP15_TIMER) {
-               clk->features |= CLOCK_EVT_FEAT_C3STOP;
+               if (arch_timer_c3stop)
+                       clk->features |= CLOCK_EVT_FEAT_C3STOP;
                clk->name = "arch_sys_timer";
                clk->rating = 450;
                clk->cpumask = cpumask_of(smp_processor_id());
@@ -665,6 +667,8 @@ static void __init arch_timer_init(struct device_node *np)
                }
        }
 
+       arch_timer_c3stop = !of_property_read_bool(np, "always-on");
+
        arch_timer_register();
        arch_timer_common_init();
 }
index ca81809d159d5ebf49ddcb6f9df0bc38208fefce..7ce442148c3f5dfb32449498bc9352066050688e 100644 (file)
@@ -212,4 +212,9 @@ error_free:
        return ret;
 }
 
-CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_add);
+static void __init zevio_timer_init(struct device_node *node)
+{
+       BUG_ON(zevio_timer_add(node));
+}
+
+CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init);
index 148d707a1d439375ef36bf2ac8e6655fe2a61042..ccdd4c7e748b3b1e63b75e08398ac7972fde66b8 100644 (file)
@@ -369,7 +369,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
                return;
 
        /* Can only change if privileged. */
-       if (!capable(CAP_NET_ADMIN)) {
+       if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
                err = EPERM;
                goto out;
        }
index 580503513f0f10687d46e666e19f253d7fbbfb51..6e05a1e18e52723dbeeee99f90fcc8b768466b14 100644 (file)
@@ -85,7 +85,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW
          It allows usage of special frequencies for Samsung Exynos
          processors if thermal conditions are appropriate.
 
-         It reguires, for safe operation, thermal framework with properly
+         It requires, for safe operation, thermal framework with properly
          defined trip points.
 
          If in doubt, say N.
@@ -186,7 +186,7 @@ config ARM_S3C2416_CPUFREQ
          S3C2450 SoC. The S3C2416 supports changing the rate of the
          armdiv clock source and also entering a so called dynamic
          voltage scaling mode in which it is possible to reduce the
-         core voltage of the cpu.
+         core voltage of the CPU.
 
          If in doubt, say N.
 
index d369349eeaab2df6fe768469470ad6de39583889..89ae88f9189532d8313a5fee264de96393851cd0 100644 (file)
@@ -10,7 +10,7 @@ config X86_INTEL_PSTATE
          The driver implements an internal governor and will become
           the scaling driver and governor for Sandy bridge processors.
 
-         When this driver is enabled it will become the perferred
+         When this driver is enabled it will become the preferred
           scaling driver for Sandy bridge processors.
 
          If in doubt, say N.
@@ -52,7 +52,7 @@ config X86_ACPI_CPUFREQ_CPB
        help
          The powernow-k8 driver used to provide a sysfs knob called "cpb"
          to disable the Core Performance Boosting feature of AMD CPUs. This
-         file has now been superseeded by the more generic "boost" entry.
+         file has now been superseded by the more generic "boost" entry.
 
          By enabling this option the acpi_cpufreq driver provides the old
          entry in addition to the new boost ones, for compatibility reasons.
index 000e4e0afd7e672abaac488d3096ae199f68a301..b0c18ed8d83f707d000213e458dba613e4ffaf96 100644 (file)
@@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
 
 static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
 {
-       int i;
+       struct cpufreq_frequency_table *pos;
        struct acpi_processor_performance *perf;
 
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
@@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
 
        perf = data->acpi_data;
 
-       for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               if (msr == perf->states[data->freq_table[i].driver_data].status)
-                       return data->freq_table[i].frequency;
-       }
+       cpufreq_for_each_entry(pos, data->freq_table)
+               if (msr == perf->states[pos->driver_data].status)
+                       return pos->frequency;
        return data->freq_table[0].frequency;
 }
 
index bad2ed317ba294462212bc00cc3cc94132e0aeb2..1f4d4e31505746db9e2cc5565710d4180349245b 100644 (file)
@@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table)
 /* get the minimum frequency in the cpufreq_frequency_table */
 static inline u32 get_table_min(struct cpufreq_frequency_table *table)
 {
-       int i;
+       struct cpufreq_frequency_table *pos;
        uint32_t min_freq = ~0;
-       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
-               if (table[i].frequency < min_freq)
-                       min_freq = table[i].frequency;
+       cpufreq_for_each_entry(pos, table)
+               if (pos->frequency < min_freq)
+                       min_freq = pos->frequency;
        return min_freq;
 }
 
 /* get the maximum frequency in the cpufreq_frequency_table */
 static inline u32 get_table_max(struct cpufreq_frequency_table *table)
 {
-       int i;
+       struct cpufreq_frequency_table *pos;
        uint32_t max_freq = 0;
-       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
-               if (table[i].frequency > max_freq)
-                       max_freq = table[i].frequency;
+       cpufreq_for_each_entry(pos, table)
+               if (pos->frequency > max_freq)
+                       max_freq = pos->frequency;
        return max_freq;
 }
 
index abda6609d3e79f670c7143a01bbec53078e8bce1..a517da996aaffb229632c52bef7e17239729a641 100644 (file)
@@ -237,6 +237,17 @@ void cpufreq_cpu_put(struct cpufreq_policy *policy)
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
 
+bool cpufreq_next_valid(struct cpufreq_frequency_table **pos)
+{
+       while ((*pos)->frequency != CPUFREQ_TABLE_END)
+               if ((*pos)->frequency != CPUFREQ_ENTRY_INVALID)
+                       return true;
+               else
+                       (*pos)++;
+       return false;
+}
+EXPORT_SYMBOL_GPL(cpufreq_next_valid);
+
 /*********************************************************************
  *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
  *********************************************************************/
index ecaaebf969fc4e5427464dfce53d0bb321e3c39b..0cd9b4dcef997d4814c5d2570092b46d26b4e143 100644 (file)
@@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu)
 
 static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
 {
-       unsigned int i, j, count = 0, ret = 0;
+       unsigned int i, count = 0, ret = 0;
        struct cpufreq_stats *stat;
        unsigned int alloc_size;
        unsigned int cpu = policy->cpu;
-       struct cpufreq_frequency_table *table;
+       struct cpufreq_frequency_table *pos, *table;
 
        table = cpufreq_frequency_get_table(cpu);
        if (unlikely(!table))
@@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
        stat->cpu = cpu;
        per_cpu(cpufreq_stats_table, cpu) = stat;
 
-       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               unsigned int freq = table[i].frequency;
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       cpufreq_for_each_valid_entry(pos, table)
                count++;
-       }
 
        alloc_size = count * sizeof(int) + count * sizeof(u64);
 
@@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        stat->trans_table = stat->freq_table + count;
 #endif
-       j = 0;
-       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               unsigned int freq = table[i].frequency;
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
-               if (freq_table_get_index(stat, freq) == -1)
-                       stat->freq_table[j++] = freq;
-       }
-       stat->state_num = j;
+       i = 0;
+       cpufreq_for_each_valid_entry(pos, table)
+               if (freq_table_get_index(stat, pos->frequency) == -1)
+                       stat->freq_table[i++] = pos->frequency;
+       stat->state_num = i;
        spin_lock(&cpufreq_stats_lock);
        stat->last_time = get_jiffies_64();
        stat->last_index = freq_table_get_index(stat, policy->cur);
index 412a78bb0c9410b3fe592227d6b9b03e534616b7..4bebc1b5db48f389aa546083ea6ec68d80edfa67 100644 (file)
@@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = {
 
 static int dbx500_cpufreq_probe(struct platform_device *pdev)
 {
-       int i = 0;
+       struct cpufreq_frequency_table *pos;
 
        freq_table = dev_get_platdata(&pdev->dev);
        if (!freq_table) {
@@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
        }
 
        pr_info("dbx500-cpufreq: Available frequencies:\n");
-       while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
-               pr_info("  %d Mhz\n", freq_table[i].frequency/1000);
-               i++;
-       }
+       cpufreq_for_each_entry(pos, freq_table)
+               pr_info("  %d Mhz\n", pos->frequency / 1000);
 
        return cpufreq_register_driver(&dbx500_cpufreq_driver);
 }
index 7f5d2a68c3532880b37646ff0761bb73911e00e5..1c06e786c9baa53f587579ab932701e0a51d5a3f 100644 (file)
@@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
 static int elanfreq_cpu_init(struct cpufreq_policy *policy)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
-       unsigned int i;
+       struct cpufreq_frequency_table *pos;
 
        /* capability check */
        if ((c->x86_vendor != X86_VENDOR_AMD) ||
@@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
                max_freq = elanfreq_get_cpu_frequency(0);
 
        /* table init */
-       for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
-               if (elanfreq_table[i].frequency > max_freq)
-                       elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
-       }
+       cpufreq_for_each_entry(pos, elanfreq_table)
+               if (pos->frequency > max_freq)
+                       pos->frequency = CPUFREQ_ENTRY_INVALID;
 
        /* cpuinfo and default policy values */
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index f99cfe24e7bca6489dcbf592372a38d1d019f4f1..c3e55aa28cf87de7da5bbad69ff74f2385578f84 100644 (file)
@@ -29,17 +29,16 @@ static unsigned int locking_frequency;
 static int exynos_cpufreq_get_index(unsigned int freq)
 {
        struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
-       int index;
+       struct cpufreq_frequency_table *pos;
 
-       for (index = 0;
-               freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
-               if (freq_table[index].frequency == freq)
+       cpufreq_for_each_entry(pos, freq_table)
+               if (pos->frequency == freq)
                        break;
 
-       if (freq_table[index].frequency == CPUFREQ_TABLE_END)
+       if (pos->frequency == CPUFREQ_TABLE_END)
                return -EINVAL;
 
-       return index;
+       return pos - freq_table;
 }
 
 static int exynos_cpufreq_scale(unsigned int target_freq)
@@ -49,6 +48,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
        struct cpufreq_policy *policy = cpufreq_cpu_get(0);
        unsigned int arm_volt, safe_arm_volt = 0;
        unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
+       struct device *dev = exynos_info->dev;
        unsigned int old_freq;
        int index, old_index;
        int ret = 0;
@@ -90,8 +90,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
                /* Firstly, voltage up to increase frequency */
                ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
                if (ret) {
-                       pr_err("%s: failed to set cpu voltage to %d\n",
-                               __func__, arm_volt);
+                       dev_err(dev, "failed to set cpu voltage to %d\n",
+                               arm_volt);
                        return ret;
                }
        }
@@ -100,8 +100,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
                ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
                                      safe_arm_volt);
                if (ret) {
-                       pr_err("%s: failed to set cpu voltage to %d\n",
-                               __func__, safe_arm_volt);
+                       dev_err(dev, "failed to set cpu voltage to %d\n",
+                               safe_arm_volt);
                        return ret;
                }
        }
@@ -115,8 +115,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
                ret = regulator_set_voltage(arm_regulator, arm_volt,
                                arm_volt);
                if (ret) {
-                       pr_err("%s: failed to set cpu voltage to %d\n",
-                               __func__, arm_volt);
+                       dev_err(dev, "failed to set cpu voltage to %d\n",
+                               arm_volt);
                        goto out;
                }
        }
@@ -163,6 +163,8 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
        if (!exynos_info)
                return -ENOMEM;
 
+       exynos_info->dev = &pdev->dev;
+
        if (soc_is_exynos4210())
                ret = exynos4210_cpufreq_init(exynos_info);
        else if (soc_is_exynos4212() || soc_is_exynos4412())
@@ -176,13 +178,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
                goto err_vdd_arm;
 
        if (exynos_info->set_freq == NULL) {
-               pr_err("%s: No set_freq function (ERR)\n", __func__);
+               dev_err(&pdev->dev, "No set_freq function (ERR)\n");
                goto err_vdd_arm;
        }
 
        arm_regulator = regulator_get(NULL, "vdd_arm");
        if (IS_ERR(arm_regulator)) {
-               pr_err("%s: failed to get resource vdd_arm\n", __func__);
+               dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
                goto err_vdd_arm;
        }
 
@@ -192,7 +194,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
        if (!cpufreq_register_driver(&exynos_driver))
                return 0;
 
-       pr_err("%s: failed to register cpufreq driver\n", __func__);
+       dev_err(&pdev->dev, "failed to register cpufreq driver\n");
        regulator_put(arm_regulator);
 err_vdd_arm:
        kfree(exynos_info);
index 3ddade8a51251e31a2091642aa9e6c4d76e3f398..b72ff10a040ef1ddebf73d7d57aec7eddb1b94ca 100644 (file)
@@ -34,6 +34,7 @@ struct apll_freq {
 };
 
 struct exynos_dvfs_info {
+       struct device   *dev;
        unsigned long   mpll_freq_khz;
        unsigned int    pll_safe_idx;
        struct clk      *cpu_clk;
index a6b8214d7b7712bb7d877d68d71e476e7bde26dc..f33f25b483ca6ce0ac87cfda264ba0f1a1eff8d6 100644 (file)
@@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs;
 
 static int init_div_table(void)
 {
-       struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
+       struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table;
        unsigned int tmp, clk_div, ema_div, freq, volt_id;
-       int i = 0;
        struct dev_pm_opp *opp;
 
        rcu_read_lock();
-       for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
-
+       cpufreq_for_each_entry(pos, freq_tbl) {
                opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
-                                       freq_tbl[i].frequency * 1000, true);
+                                       pos->frequency * 1000, true);
                if (IS_ERR(opp)) {
                        rcu_read_unlock();
                        dev_err(dvfs_info->dev,
                                "failed to find valid OPP for %u KHZ\n",
-                               freq_tbl[i].frequency);
+                               pos->frequency);
                        return PTR_ERR(opp);
                }
 
-               freq = freq_tbl[i].frequency / 1000; /* In MHZ */
+               freq = pos->frequency / 1000; /* In MHZ */
                clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
                                        << P0_7_CPUCLKDEV_SHIFT;
                clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
@@ -157,7 +155,8 @@ static int init_div_table(void)
                tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
                        | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
 
-               __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i);
+               __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
+                                               (pos - freq_tbl));
        }
 
        rcu_read_unlock();
@@ -166,8 +165,9 @@ static int init_div_table(void)
 
 static void exynos_enable_dvfs(unsigned int cur_frequency)
 {
-       unsigned int tmp, i, cpu;
+       unsigned int tmp, cpu;
        struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
+       struct cpufreq_frequency_table *pos;
        /* Disable DVFS */
        __raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
 
@@ -182,15 +182,15 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
         __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
 
        /* Set initial performance index */
-       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
-               if (freq_table[i].frequency == cur_frequency)
+       cpufreq_for_each_entry(pos, freq_table)
+               if (pos->frequency == cur_frequency)
                        break;
 
-       if (freq_table[i].frequency == CPUFREQ_TABLE_END) {
+       if (pos->frequency == CPUFREQ_TABLE_END) {
                dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
                /* Assign the highest frequency */
-               i = 0;
-               cur_frequency = freq_table[i].frequency;
+               pos = freq_table;
+               cur_frequency = pos->frequency;
        }
 
        dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
@@ -199,7 +199,7 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
        for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
                tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
                tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
-               tmp |= (i << C0_3_PSTATE_NEW_SHIFT);
+               tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT);
                __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
        }
 
index 08e7bbcf6d7362d633311132e8b9fe21433360a0..8e518c6893935135e0bfff4d7c7b8735bd0fefa1 100644 (file)
 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
                                    struct cpufreq_frequency_table *table)
 {
+       struct cpufreq_frequency_table *pos;
        unsigned int min_freq = ~0;
        unsigned int max_freq = 0;
-       unsigned int i;
+       unsigned int freq;
 
-       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
-               unsigned int freq = table[i].frequency;
-               if (freq == CPUFREQ_ENTRY_INVALID) {
-                       pr_debug("table entry %u is invalid, skipping\n", i);
+       cpufreq_for_each_valid_entry(pos, table) {
+               freq = pos->frequency;
 
-                       continue;
-               }
                if (!cpufreq_boost_enabled()
-                   && (table[i].flags & CPUFREQ_BOOST_FREQ))
+                   && (pos->flags & CPUFREQ_BOOST_FREQ))
                        continue;
 
-               pr_debug("table entry %u: %u kHz\n", i, freq);
+               pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
                if (freq < min_freq)
                        min_freq = freq;
                if (freq > max_freq)
@@ -57,7 +54,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
                                   struct cpufreq_frequency_table *table)
 {
-       unsigned int next_larger = ~0, freq, i = 0;
+       struct cpufreq_frequency_table *pos;
+       unsigned int freq, next_larger = ~0;
        bool found = false;
 
        pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
@@ -65,9 +63,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
 
        cpufreq_verify_within_cpu_limits(policy);
 
-       for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) {
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       cpufreq_for_each_valid_entry(pos, table) {
+               freq = pos->frequency;
+
                if ((freq >= policy->min) && (freq <= policy->max)) {
                        found = true;
                        break;
@@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                .driver_data = ~0,
                .frequency = 0,
        };
-       unsigned int i;
+       struct cpufreq_frequency_table *pos;
+       unsigned int freq, i = 0;
 
        pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
                                        target_freq, relation, policy->cpu);
@@ -132,10 +131,10 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                break;
        }
 
-       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
-               unsigned int freq = table[i].frequency;
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       cpufreq_for_each_valid_entry(pos, table) {
+               freq = pos->frequency;
+
+               i = pos - table;
                if ((freq < policy->min) || (freq > policy->max))
                        continue;
                switch (relation) {
@@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
                unsigned int freq)
 {
-       struct cpufreq_frequency_table *table;
-       int i;
+       struct cpufreq_frequency_table *pos, *table;
 
        table = cpufreq_frequency_get_table(policy->cpu);
        if (unlikely(!table)) {
@@ -193,10 +191,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
                return -ENOENT;
        }
 
-       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               if (table[i].frequency == freq)
-                       return i;
-       }
+       cpufreq_for_each_valid_entry(pos, table)
+               if (pos->frequency == freq)
+                       return pos - table;
 
        return -EINVAL;
 }
@@ -208,16 +205,13 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
                                    bool show_boost)
 {
-       unsigned int i = 0;
        ssize_t count = 0;
-       struct cpufreq_frequency_table *table = policy->freq_table;
+       struct cpufreq_frequency_table *pos, *table = policy->freq_table;
 
        if (!table)
                return -ENODEV;
 
-       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
-               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       cpufreq_for_each_valid_entry(pos, table) {
                /*
                 * show_boost = true and driver_data = BOOST freq
                 * display BOOST freqs
@@ -229,10 +223,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
                 * show_boost = false and driver_data != BOOST freq
                 * display NON BOOST freqs
                 */
-               if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ))
+               if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
                        continue;
 
-               count += sprintf(&buf[count], "%d ", table[i].frequency);
+               count += sprintf(&buf[count], "%d ", pos->frequency);
        }
        count += sprintf(&buf[count], "\n");
 
index d00e5d1abd258b469bf48862a5f14b08e04f97a7..c913906a719ee0f9b44598593b4900c201395596 100644 (file)
@@ -242,7 +242,7 @@ static void do_powersaver(int cx_address, unsigned int mults_index,
  * Sets a new clock ratio.
  */
 
-static void longhaul_setstate(struct cpufreq_policy *policy,
+static int longhaul_setstate(struct cpufreq_policy *policy,
                unsigned int table_index)
 {
        unsigned int mults_index;
@@ -258,10 +258,12 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
        /* Safety precautions */
        mult = mults[mults_index & 0x1f];
        if (mult == -1)
-               return;
+               return -EINVAL;
+
        speed = calc_speed(mult);
        if ((speed > highest_speed) || (speed < lowest_speed))
-               return;
+               return -EINVAL;
+
        /* Voltage transition before frequency transition? */
        if (can_scale_voltage && longhaul_index < table_index)
                dir = 1;
@@ -269,8 +271,6 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
        freqs.old = calc_speed(longhaul_get_cpu_mult());
        freqs.new = speed;
 
-       cpufreq_freq_transition_begin(policy, &freqs);
-
        pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
                        fsb, mult/10, mult%10, print_speed(speed/1000));
 retry_loop:
@@ -385,12 +385,14 @@ retry_loop:
                        goto retry_loop;
                }
        }
-       /* Report true CPU frequency */
-       cpufreq_freq_transition_end(policy, &freqs, 0);
 
-       if (!bm_timeout)
+       if (!bm_timeout) {
                printk(KERN_INFO PFX "Warning: Timeout while waiting for "
                                "idle PCI bus.\n");
+               return -EBUSY;
+       }
+
+       return 0;
 }
 
 /*
@@ -528,6 +530,7 @@ static int longhaul_get_ranges(void)
 
 static void longhaul_setup_voltagescaling(void)
 {
+       struct cpufreq_frequency_table *freq_pos;
        union msr_longhaul longhaul;
        struct mV_pos minvid, maxvid, vid;
        unsigned int j, speed, pos, kHz_step, numvscales;
@@ -606,18 +609,16 @@ static void longhaul_setup_voltagescaling(void)
        /* Calculate kHz for one voltage step */
        kHz_step = (highest_speed - min_vid_speed) / numvscales;
 
-       j = 0;
-       while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
-               speed = longhaul_table[j].frequency;
+       cpufreq_for_each_entry(freq_pos, longhaul_table) {
+               speed = freq_pos->frequency;
                if (speed > min_vid_speed)
                        pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
                else
                        pos = minvid.pos;
-               longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8;
+               freq_pos->driver_data |= mV_vrm_table[pos] << 8;
                vid = vrm_mV_table[mV_vrm_table[pos]];
                printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
-                               speed, j, vid.mV);
-               j++;
+                       speed, (int)(freq_pos - longhaul_table), vid.mV);
        }
 
        can_scale_voltage = 1;
@@ -631,9 +632,10 @@ static int longhaul_target(struct cpufreq_policy *policy,
        unsigned int i;
        unsigned int dir = 0;
        u8 vid, current_vid;
+       int retval = 0;
 
        if (!can_scale_voltage)
-               longhaul_setstate(policy, table_index);
+               retval = longhaul_setstate(policy, table_index);
        else {
                /* On test system voltage transitions exceeding single
                 * step up or down were turning motherboard off. Both
@@ -648,7 +650,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
                while (i != table_index) {
                        vid = (longhaul_table[i].driver_data >> 8) & 0x1f;
                        if (vid != current_vid) {
-                               longhaul_setstate(policy, i);
+                               retval = longhaul_setstate(policy, i);
                                current_vid = vid;
                                msleep(200);
                        }
@@ -657,10 +659,11 @@ static int longhaul_target(struct cpufreq_policy *policy,
                        else
                                i--;
                }
-               longhaul_setstate(policy, table_index);
+               retval = longhaul_setstate(policy, table_index);
        }
+
        longhaul_index = table_index;
-       return 0;
+       return retval;
 }
 
 
@@ -968,7 +971,15 @@ static void __exit longhaul_exit(void)
 
        for (i = 0; i < numscales; i++) {
                if (mults[i] == maxmult) {
+                       struct cpufreq_freqs freqs;
+
+                       freqs.old = policy->cur;
+                       freqs.new = longhaul_table[i].frequency;
+                       freqs.flags = 0;
+
+                       cpufreq_freq_transition_begin(policy, &freqs);
                        longhaul_setstate(policy, i);
+                       cpufreq_freq_transition_end(policy, &freqs, 0);
                        break;
                }
        }
index f0bc31f5db27a41db3d7f8556e72274b42a5eda5..d4add86219444af31891ef8c76013eaed0838282 100644 (file)
@@ -62,7 +62,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
        set_cpus_allowed_ptr(current, &cpus_allowed);
 
        /* setting the cpu frequency */
-       clk_set_rate(policy->clk, freq);
+       clk_set_rate(policy->clk, freq * 1000);
 
        return 0;
 }
@@ -92,7 +92,7 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
             i++)
                loongson2_clockmod_table[i].frequency = (rate * i) / 8;
 
-       ret = clk_set_rate(cpuclk, rate);
+       ret = clk_set_rate(cpuclk, rate * 1000);
        if (ret) {
                clk_put(cpuclk);
                return ret;
index 84c84b5f0f3a426d70738730b8715defc18bec20..35dd4d7ffee0824be3bd1bb0ce55eca7074a8da4 100644 (file)
@@ -136,9 +136,10 @@ void restore_astate(int cpu)
 
 static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
+       struct cpufreq_frequency_table *pos;
        const u32 *max_freqp;
        u32 max_freq;
-       int i, cur_astate;
+       int cur_astate;
        struct resource res;
        struct device_node *cpu, *dn;
        int err = -ENODEV;
@@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
        pr_debug("initializing frequency table\n");
 
        /* initialize frequency table */
-       for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
-               pas_freqs[i].frequency =
-                       get_astate_freq(pas_freqs[i].driver_data) * 100000;
-               pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
+       cpufreq_for_each_entry(pos, pas_freqs) {
+               pos->frequency = get_astate_freq(pos->driver_data) * 100000;
+               pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency);
        }
 
        cur_astate = get_cur_astate(policy->cpu);
index 49f120e1bc7be0ecb879f184424d1dc56ee63981..c8012bc869107206ad1fd7024ab86a76a406890e 100644 (file)
@@ -138,27 +138,20 @@ static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
 static int powernow_k6_target(struct cpufreq_policy *policy,
                unsigned int best_i)
 {
-       struct cpufreq_freqs freqs;
 
        if (clock_ratio[best_i].driver_data > max_multiplier) {
                printk(KERN_ERR PFX "invalid target frequency\n");
                return -EINVAL;
        }
 
-       freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
-       freqs.new = busfreq * clock_ratio[best_i].driver_data;
-
-       cpufreq_freq_transition_begin(policy, &freqs);
-
        powernow_k6_set_cpu_multiplier(best_i);
 
-       cpufreq_freq_transition_end(policy, &freqs, 0);
-
        return 0;
 }
 
 static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
 {
+       struct cpufreq_frequency_table *pos;
        unsigned int i, f;
        unsigned khz;
 
@@ -176,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
                }
        }
        if (param_max_multiplier) {
-               for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
-                       if (clock_ratio[i].driver_data == param_max_multiplier) {
+               cpufreq_for_each_entry(pos, clock_ratio)
+                       if (pos->driver_data == param_max_multiplier) {
                                max_multiplier = param_max_multiplier;
                                goto have_max_multiplier;
                        }
-               }
                printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
                return -EINVAL;
        }
@@ -209,12 +201,12 @@ have_busfreq:
        param_busfreq = busfreq * 10;
 
        /* table init */
-       for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
-               f = clock_ratio[i].driver_data;
+       cpufreq_for_each_entry(pos, clock_ratio) {
+               f = pos->driver_data;
                if (f > max_multiplier)
-                       clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       pos->frequency = CPUFREQ_ENTRY_INVALID;
                else
-                       clock_ratio[i].frequency = busfreq * f;
+                       pos->frequency = busfreq * f;
        }
 
        /* cpuinfo and default policy values */
@@ -227,9 +219,20 @@ have_busfreq:
 static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
 {
        unsigned int i;
-       for (i = 0; i < 8; i++) {
-               if (i == max_multiplier)
+
+       for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
+               if (clock_ratio[i].driver_data == max_multiplier) {
+                       struct cpufreq_freqs freqs;
+
+                       freqs.old = policy->cur;
+                       freqs.new = clock_ratio[i].frequency;
+                       freqs.flags = 0;
+
+                       cpufreq_freq_transition_begin(policy, &freqs);
                        powernow_k6_target(policy, i);
+                       cpufreq_freq_transition_end(policy, &freqs, 0);
+                       break;
+               }
        }
        return 0;
 }
index f911645c3f6db59e18f32b68c06bfc890283c029..e61e224475ad457fd71b6934b2a5256a2d96fcc0 100644 (file)
@@ -269,8 +269,6 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
 
        freqs.new = powernow_table[index].frequency;
 
-       cpufreq_freq_transition_begin(policy, &freqs);
-
        /* Now do the magic poking into the MSRs.  */
 
        if (have_a0 == 1)       /* A0 errata 5 */
@@ -290,8 +288,6 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
        if (have_a0 == 1)
                local_irq_enable();
 
-       cpufreq_freq_transition_end(policy, &freqs, 0);
-
        return 0;
 }
 
index a1ca3dd04a8e7b616acf50467cbbf142f8325035..0af618abebafa4b44b323d1811c1f885a52e0beb 100644 (file)
@@ -138,6 +138,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
        struct cpufreq_frequency_table *table;
        struct cpu_data *data;
        unsigned int cpu = policy->cpu;
+       u64 transition_latency_hz;
 
        np = of_get_cpu_node(cpu, NULL);
        if (!np)
@@ -205,8 +206,10 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
        for_each_cpu(i, per_cpu(cpu_mask, cpu))
                per_cpu(cpu_data, i) = data;
 
+       transition_latency_hz = 12ULL * NSEC_PER_SEC;
        policy->cpuinfo.transition_latency =
-                               (12ULL * NSEC_PER_SEC) / fsl_get_sys_freq();
+               do_div(transition_latency_hz, fsl_get_sys_freq());
+
        of_node_put(np);
 
        return 0;
index 5be8a48dba74fdca1d3d8b33ac02c93229b792c6..5a4c5a639f618f01074c5d1c73afa9b0e48352c3 100644 (file)
@@ -67,9 +67,10 @@ static int set_pmode(unsigned int cpu, unsigned int slow_mode)
 
 static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
+       struct cpufreq_frequency_table *pos;
        const u32 *max_freqp;
        u32 max_freq;
-       int i, cur_pmode;
+       int cur_pmode;
        struct device_node *cpu;
 
        cpu = of_get_cpu_node(policy->cpu, NULL);
@@ -102,9 +103,9 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
        pr_debug("initializing frequency table\n");
 
        /* initialize frequency table */
-       for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
-               cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
-               pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
+       cpufreq_for_each_entry(pos, cbe_freqs) {
+               pos->frequency = max_freq / pos->driver_data;
+               pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
        }
 
        /* if DEBUG is enabled set_pmode() measures the latency
index 4626f90559b55167869b86aa6c0349cb45d29d46..2fd53eaaec20bf30ef00d6a19226fba13670501a 100644 (file)
@@ -266,7 +266,7 @@ out:
 static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
 {
        int count, v, i, found;
-       struct cpufreq_frequency_table *freq;
+       struct cpufreq_frequency_table *pos;
        struct s3c2416_dvfs *dvfs;
 
        count = regulator_count_voltages(s3c_freq->vddarm);
@@ -275,12 +275,11 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
                return;
        }
 
-       freq = s3c_freq->freq_table;
-       while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
-               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       if (!count)
+               goto out;
 
-               dvfs = &s3c2416_dvfs_table[freq->driver_data];
+       cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) {
+               dvfs = &s3c2416_dvfs_table[pos->driver_data];
                found = 0;
 
                /* Check only the min-voltage, more is always ok on S3C2416 */
@@ -292,13 +291,12 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
 
                if (!found) {
                        pr_debug("cpufreq: %dkHz unsupported by regulator\n",
-                                freq->frequency);
-                       freq->frequency = CPUFREQ_ENTRY_INVALID;
+                                pos->frequency);
+                       pos->frequency = CPUFREQ_ENTRY_INVALID;
                }
-
-               freq++;
        }
 
+out:
        /* Guessed */
        s3c_freq->regulator_latency = 1 * 1000 * 1000;
 }
@@ -338,7 +336,7 @@ static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
 static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
 {
        struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
-       struct cpufreq_frequency_table *freq;
+       struct cpufreq_frequency_table *pos;
        struct clk *msysclk;
        unsigned long rate;
        int ret;
@@ -427,31 +425,27 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
        s3c_freq->regulator_latency = 0;
 #endif
 
-       freq = s3c_freq->freq_table;
-       while (freq->frequency != CPUFREQ_TABLE_END) {
+       cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
                /* special handling for dvs mode */
-               if (freq->driver_data == 0) {
+               if (pos->driver_data == 0) {
                        if (!s3c_freq->hclk) {
                                pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
-                                        freq->frequency);
-                               freq->frequency = CPUFREQ_ENTRY_INVALID;
+                                        pos->frequency);
+                               pos->frequency = CPUFREQ_ENTRY_INVALID;
                        } else {
-                               freq++;
                                continue;
                        }
                }
 
                /* Check for frequencies we can generate */
                rate = clk_round_rate(s3c_freq->armdiv,
-                                     freq->frequency * 1000);
+                                     pos->frequency * 1000);
                rate /= 1000;
-               if (rate != freq->frequency) {
+               if (rate != pos->frequency) {
                        pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
-                                freq->frequency, rate);
-                       freq->frequency = CPUFREQ_ENTRY_INVALID;
+                               pos->frequency, rate);
+                       pos->frequency = CPUFREQ_ENTRY_INVALID;
                }
-
-               freq++;
        }
 
        /* Datasheet says PLL stabalisation time must be at least 300us,
index ff7d3ecb85f0f3c45430423942dc79a03f8837a6..176e84cc3991994871d6eee9a1b8927a3bdf95fa 100644 (file)
@@ -118,11 +118,10 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
                pr_err("Unable to check supported voltages\n");
        }
 
-       freq = s3c64xx_freq_table;
-       while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
-               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       if (!count)
+               goto out;
 
+       cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) {
                dvfs = &s3c64xx_dvfs_table[freq->driver_data];
                found = 0;
 
@@ -137,10 +136,9 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
                                 freq->frequency);
                        freq->frequency = CPUFREQ_ENTRY_INVALID;
                }
-
-               freq++;
        }
 
+out:
        /* Guess based on having to do an I2C/SPI write; in future we
         * will be able to query the regulator performance here. */
        regulator_latency = 1 * 1000 * 1000;
@@ -179,8 +177,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
        }
 #endif
 
-       freq = s3c64xx_freq_table;
-       while (freq->frequency != CPUFREQ_TABLE_END) {
+       cpufreq_for_each_entry(freq, s3c64xx_freq_table) {
                unsigned long r;
 
                /* Check for frequencies we can generate */
@@ -196,8 +193,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
                 * frequency is the maximum we can support. */
                if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
                        freq->frequency = CPUFREQ_ENTRY_INVALID;
-
-               freq++;
        }
 
        /* Datasheet says PLL stabalisation time (if we were to use
index 6723f0390f20dace530f77f4d94c4109af48b351..7d4a31571608524e75cfa71c35c5336dea485efa 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/cpu_device_id.h>
 
 #define PFX            "speedstep-centrino: "
-#define MAINTAINER     "cpufreq@vger.kernel.org"
+#define MAINTAINER     "linux-pm@vger.kernel.org"
 
 #define INTEL_MSR_RANGE        (0xffff)
 
index 97ccc31dbdd8fb8c48510cc00f5472ea6aefa191..5bb94780d3778d31424b741b292ef70637444782 100644 (file)
@@ -1,6 +1,11 @@
 #
 # ARM CPU Idle drivers
 #
+config ARM_ARMADA_370_XP_CPUIDLE
+       bool "CPU Idle Driver for Armada 370/XP family processors"
+       depends on ARCH_MVEBU
+       help
+         Select this to enable cpuidle on Armada 370/XP processors.
 
 config ARM_BIG_LITTLE_CPUIDLE
        bool "Support for ARM big.LITTLE processors"
index f71ae1b373c5e85fc1075622e144832b5d7a0d1e..9902d052bd87a49cee52fc0ee90ae891c6cc91ce 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 
 ##################################################################################
 # ARM SoC drivers
+obj-$(CONFIG_ARM_ARMADA_370_XP_CPUIDLE) += cpuidle-armada-370-xp.o
 obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE)   += cpuidle-big_little.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)     += cpuidle-calxeda.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)     += cpuidle-kirkwood.o
diff --git a/drivers/cpuidle/cpuidle-armada-370-xp.c b/drivers/cpuidle/cpuidle-armada-370-xp.c
new file mode 100644 (file)
index 0000000..28587d0
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Marvell Armada 370 and Armada XP SoC cpuidle driver
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Nadav Haklai <nadavh@marvell.com>
+ * Gregory CLEMENT <gregory.clement@free-electrons.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.
+ *
+ * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
+ */
+
+#include <linux/cpu_pm.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
+#include <asm/cpuidle.h>
+
+#define ARMADA_370_XP_MAX_STATES       3
+#define ARMADA_370_XP_FLAG_DEEP_IDLE   0x10000
+
+static int (*armada_370_xp_cpu_suspend)(int);
+
+static int armada_370_xp_enter_idle(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
+                               int index)
+{
+       int ret;
+       bool deepidle = false;
+       cpu_pm_enter();
+
+       if (drv->states[index].flags & ARMADA_370_XP_FLAG_DEEP_IDLE)
+               deepidle = true;
+
+       ret = armada_370_xp_cpu_suspend(deepidle);
+       if (ret)
+               return ret;
+
+       cpu_pm_exit();
+
+       return index;
+}
+
+static struct cpuidle_driver armada_370_xp_idle_driver = {
+       .name                   = "armada_370_xp_idle",
+       .states[0]              = ARM_CPUIDLE_WFI_STATE,
+       .states[1]              = {
+               .enter                  = armada_370_xp_enter_idle,
+               .exit_latency           = 10,
+               .power_usage            = 50,
+               .target_residency       = 100,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID,
+               .name                   = "MV CPU IDLE",
+               .desc                   = "CPU power down",
+       },
+       .states[2]              = {
+               .enter                  = armada_370_xp_enter_idle,
+               .exit_latency           = 100,
+               .power_usage            = 5,
+               .target_residency       = 1000,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID |
+                                               ARMADA_370_XP_FLAG_DEEP_IDLE,
+               .name                   = "MV CPU DEEP IDLE",
+               .desc                   = "CPU and L2 Fabric power down",
+       },
+       .state_count = ARMADA_370_XP_MAX_STATES,
+};
+
+static int armada_370_xp_cpuidle_probe(struct platform_device *pdev)
+{
+
+       armada_370_xp_cpu_suspend = (void *)(pdev->dev.platform_data);
+       return cpuidle_register(&armada_370_xp_idle_driver, NULL);
+}
+
+static struct platform_driver armada_370_xp_cpuidle_plat_driver = {
+       .driver = {
+               .name = "cpuidle-armada-370-xp",
+               .owner = THIS_MODULE,
+       },
+       .probe = armada_370_xp_cpuidle_probe,
+};
+
+module_platform_driver(armada_370_xp_cpuidle_plat_driver);
+
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_DESCRIPTION("Armada 370/XP cpu idle driver");
+MODULE_LICENSE("GPL");
index d7c9e317423cb2910e808571584ef3c4cd0bd84e..a083474991abbb343aa330160ff988f34635b268 100644 (file)
@@ -716,6 +716,12 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
                        return -EINVAL;
                }
                ctx->block_size = CFB32_BLOCK_SIZE;
+       } else if (mode & AES_FLAGS_CFB64) {
+               if (!IS_ALIGNED(req->nbytes, CFB64_BLOCK_SIZE)) {
+                       pr_err("request size is not exact amount of CFB64 blocks\n");
+                       return -EINVAL;
+               }
+               ctx->block_size = CFB64_BLOCK_SIZE;
        } else {
                if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
                        pr_err("request size is not exact amount of AES blocks\n");
@@ -1069,7 +1075,7 @@ static struct crypto_alg aes_algs[] = {
        .cra_driver_name        = "atmel-cfb8-aes",
        .cra_priority           = 100,
        .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-       .cra_blocksize          = CFB64_BLOCK_SIZE,
+       .cra_blocksize          = CFB8_BLOCK_SIZE,
        .cra_ctxsize            = sizeof(struct atmel_aes_ctx),
        .cra_alignmask          = 0x0,
        .cra_type               = &crypto_ablkcipher_type,
index c9ff298e6d26e8670a85affa59ea1104554be6a0..b099e33cb07303dff8e32da36fdfc589426d0bc0 100644 (file)
 #include <crypto/hash.h>
 #include <crypto/internal/hash.h>
 
-#include <asm/blackfin.h>
-#include <asm/bfin_crc.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
+#include <asm/io.h>
+
+#include "bfin_crc.h"
 
 #define CRC_CCRYPTO_QUEUE_LENGTH       5
 
@@ -54,12 +55,13 @@ struct bfin_crypto_crc {
        int                     irq;
        int                     dma_ch;
        u32                     poly;
-       volatile struct crc_register *regs;
+       struct crc_register     *regs;
 
        struct ahash_request    *req; /* current request in operation */
        struct dma_desc_array   *sg_cpu; /* virt addr of sg dma descriptors */
        dma_addr_t              sg_dma; /* phy addr of sg dma descriptors */
        u8                      *sg_mid_buf;
+       dma_addr_t              sg_mid_dma; /* phy addr of sg mid buffer */
 
        struct tasklet_struct   done_task;
        struct crypto_queue     queue; /* waiting requests */
@@ -132,13 +134,13 @@ static struct scatterlist *sg_get(struct scatterlist *sg_list, unsigned int nent
 
 static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key)
 {
-       crc->regs->datacntrld = 0;
-       crc->regs->control = MODE_CALC_CRC << OPMODE_OFFSET;
-       crc->regs->curresult = key;
+       writel(0, &crc->regs->datacntrld);
+       writel(MODE_CALC_CRC << OPMODE_OFFSET, &crc->regs->control);
+       writel(key, &crc->regs->curresult);
 
        /* setup CRC interrupts */
-       crc->regs->status = CMPERRI | DCNTEXPI;
-       crc->regs->intrenset = CMPERRI | DCNTEXPI;
+       writel(CMPERRI | DCNTEXPI, &crc->regs->status);
+       writel(CMPERRI | DCNTEXPI, &crc->regs->intrenset);
 
        return 0;
 }
@@ -194,7 +196,6 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
        dma_map_sg(crc->dev, ctx->sg, ctx->sg_nents, DMA_TO_DEVICE);
 
        for_each_sg(ctx->sg, sg, ctx->sg_nents, j) {
-               dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32;
                dma_addr = sg_dma_address(sg);
                /* deduce extra bytes in last sg */
                if (sg_is_last(sg))
@@ -207,12 +208,29 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
                           bytes in current sg buffer. Move addr of current
                           sg and deduce the length of current sg.
                         */
-                       memcpy(crc->sg_mid_buf +((i-1) << 2) + mid_dma_count,
-                               (void *)dma_addr,
+                       memcpy(crc->sg_mid_buf +(i << 2) + mid_dma_count,
+                               sg_virt(sg),
                                CHKSUM_DIGEST_SIZE - mid_dma_count);
                        dma_addr += CHKSUM_DIGEST_SIZE - mid_dma_count;
                        dma_count -= CHKSUM_DIGEST_SIZE - mid_dma_count;
+
+                       dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 |
+                               DMAEN | PSIZE_32 | WDSIZE_32;
+
+                       /* setup new dma descriptor for next middle dma */
+                       crc->sg_cpu[i].start_addr = crc->sg_mid_dma + (i << 2);
+                       crc->sg_cpu[i].cfg = dma_config;
+                       crc->sg_cpu[i].x_count = 1;
+                       crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
+                       dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
+                               "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
+                               i, crc->sg_cpu[i].start_addr,
+                               crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
+                               crc->sg_cpu[i].x_modify);
+                       i++;
                }
+
+               dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32;
                /* chop current sg dma len to multiple of 32 bits */
                mid_dma_count = dma_count % 4;
                dma_count &= ~0x3;
@@ -243,24 +261,9 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
 
                if (mid_dma_count) {
                        /* copy extra bytes to next middle dma buffer */
-                       dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 |
-                               DMAEN | PSIZE_32 | WDSIZE_32;
                        memcpy(crc->sg_mid_buf + (i << 2),
-                               (void *)(dma_addr + (dma_count << 2)),
+                               (u8*)sg_virt(sg) + (dma_count << 2),
                                mid_dma_count);
-                       /* setup new dma descriptor for next middle dma */
-                       crc->sg_cpu[i].start_addr = dma_map_single(crc->dev,
-                                       crc->sg_mid_buf + (i << 2),
-                                       CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
-                       crc->sg_cpu[i].cfg = dma_config;
-                       crc->sg_cpu[i].x_count = 1;
-                       crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
-                       dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
-                               "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
-                               i, crc->sg_cpu[i].start_addr,
-                               crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
-                               crc->sg_cpu[i].x_modify);
-                       i++;
                }
        }
 
@@ -303,6 +306,7 @@ static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc,
        int nsg, i, j;
        unsigned int nextlen;
        unsigned long flags;
+       u32 reg;
 
        spin_lock_irqsave(&crc->lock, flags);
        if (req)
@@ -402,13 +406,14 @@ finish_update:
                ctx->sg_buflen += CHKSUM_DIGEST_SIZE;
 
        /* set CRC data count before start DMA */
-       crc->regs->datacnt = ctx->sg_buflen >> 2;
+       writel(ctx->sg_buflen >> 2, &crc->regs->datacnt);
 
        /* setup and enable CRC DMA */
        bfin_crypto_crc_config_dma(crc);
 
        /* finally kick off CRC operation */
-       crc->regs->control |= BLKEN;
+       reg = readl(&crc->regs->control);
+       writel(reg | BLKEN, &crc->regs->control);
 
        return -EINPROGRESS;
 }
@@ -529,14 +534,17 @@ static void bfin_crypto_crc_done_task(unsigned long data)
 static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id)
 {
        struct bfin_crypto_crc *crc = dev_id;
+       u32 reg;
 
-       if (crc->regs->status & DCNTEXP) {
-               crc->regs->status = DCNTEXP;
+       if (readl(&crc->regs->status) & DCNTEXP) {
+               writel(DCNTEXP, &crc->regs->status);
 
                /* prepare results */
-               put_unaligned_le32(crc->regs->result, crc->req->result);
+               put_unaligned_le32(readl(&crc->regs->result),
+                       crc->req->result);
 
-               crc->regs->control &= ~BLKEN;
+               reg = readl(&crc->regs->control);
+               writel(reg & ~BLKEN, &crc->regs->control);
                crc->busy = 0;
 
                if (crc->req->base.complete)
@@ -560,7 +568,7 @@ static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t st
        struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
        int i = 100000;
 
-       while ((crc->regs->control & BLKEN) && --i)
+       while ((readl(&crc->regs->control) & BLKEN) && --i)
                cpu_relax();
 
        if (i == 0)
@@ -647,29 +655,32 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev)
         * 1 last + 1 next dma descriptors
         */
        crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1));
+       crc->sg_mid_dma = crc->sg_dma + sizeof(struct dma_desc_array)
+                       * ((CRC_MAX_DMA_DESC + 1) << 1);
 
-       crc->regs->control = 0;
-       crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data;
+       writel(0, &crc->regs->control);
+       crc->poly = (u32)pdev->dev.platform_data;
+       writel(crc->poly, &crc->regs->poly);
 
-       while (!(crc->regs->status & LUTDONE) && (--timeout) > 0)
+       while (!(readl(&crc->regs->status) & LUTDONE) && (--timeout) > 0)
                cpu_relax();
 
        if (timeout == 0)
                dev_info(&pdev->dev, "init crc poly timeout\n");
 
+       platform_set_drvdata(pdev, crc);
+
        spin_lock(&crc_list.lock);
        list_add(&crc->list, &crc_list.dev_list);
        spin_unlock(&crc_list.lock);
 
-       platform_set_drvdata(pdev, crc);
-
-       ret = crypto_register_ahash(&algs);
-       if (ret) {
-               spin_lock(&crc_list.lock);
-               list_del(&crc->list);
-               spin_unlock(&crc_list.lock);
-               dev_err(&pdev->dev, "Cann't register crypto ahash device\n");
-               goto out_error_dma;
+       if (list_is_singular(&crc_list.dev_list)) {
+               ret = crypto_register_ahash(&algs);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Can't register crypto ahash device\n");
+                       goto out_error_dma;
+               }
        }
 
        dev_info(&pdev->dev, "initialized\n");
diff --git a/drivers/crypto/bfin_crc.h b/drivers/crypto/bfin_crc.h
new file mode 100644 (file)
index 0000000..75cef4d
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * bfin_crc.h - interface to Blackfin CRC controllers
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFIN_CRC_H__
+#define __BFIN_CRC_H__
+
+/* Function driver which use hardware crc must initialize the structure */
+struct crc_info {
+       /* Input data address */
+       unsigned char *in_addr;
+       /* Output data address */
+       unsigned char *out_addr;
+       /* Input or output bytes */
+       unsigned long datasize;
+       union {
+       /* CRC to compare with that of input buffer */
+       unsigned long crc_compare;
+       /* Value to compare with input data */
+       unsigned long val_verify;
+       /* Value to fill */
+       unsigned long val_fill;
+       };
+       /* Value to program the 32b CRC Polynomial */
+       unsigned long crc_poly;
+       union {
+       /* CRC calculated from the input data */
+       unsigned long crc_result;
+       /* First failed position to verify input data */
+       unsigned long pos_verify;
+       };
+       /* CRC mirror flags */
+       unsigned int bitmirr:1;
+       unsigned int bytmirr:1;
+       unsigned int w16swp:1;
+       unsigned int fdsel:1;
+       unsigned int rsltmirr:1;
+       unsigned int polymirr:1;
+       unsigned int cmpmirr:1;
+};
+
+/* Userspace interface */
+#define CRC_IOC_MAGIC          'C'
+#define CRC_IOC_CALC_CRC       _IOWR('C', 0x01, unsigned int)
+#define CRC_IOC_MEMCPY_CRC     _IOWR('C', 0x02, unsigned int)
+#define CRC_IOC_VERIFY_VAL     _IOWR('C', 0x03, unsigned int)
+#define CRC_IOC_FILL_VAL       _IOWR('C', 0x04, unsigned int)
+
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+
+struct crc_register {
+       u32 control;
+       u32 datacnt;
+       u32 datacntrld;
+       u32 __pad_1[2];
+       u32 compare;
+       u32 fillval;
+       u32 datafifo;
+       u32 intren;
+       u32 intrenset;
+       u32 intrenclr;
+       u32 poly;
+       u32 __pad_2[4];
+       u32 status;
+       u32 datacntcap;
+       u32 __pad_3;
+       u32 result;
+       u32 curresult;
+       u32 __pad_4[3];
+       u32 revid;
+};
+
+/* CRC_STATUS Masks */
+#define CMPERR                 0x00000002      /* Compare error */
+#define DCNTEXP                        0x00000010      /* datacnt register expired */
+#define IBR                    0x00010000      /* Input buffer ready */
+#define OBR                    0x00020000      /* Output buffer ready */
+#define IRR                    0x00040000      /* Immediate result readt */
+#define LUTDONE                        0x00080000      /* Look-up table generation done */
+#define FSTAT                  0x00700000      /* FIFO status */
+#define MAX_FIFO               4               /* Max fifo size */
+
+/* CRC_CONTROL Masks */
+#define BLKEN                  0x00000001      /* Block enable */
+#define OPMODE                 0x000000F0      /* Operation mode */
+#define OPMODE_OFFSET          4               /* Operation mode mask offset*/
+#define MODE_DMACPY_CRC                1               /* MTM CRC compute and compare */
+#define MODE_DATA_FILL         2               /* MTM data fill */
+#define MODE_CALC_CRC          3               /* MSM CRC compute and compare */
+#define MODE_DATA_VERIFY       4               /* MSM data verify */
+#define AUTOCLRZ               0x00000100      /* Auto clear to zero */
+#define AUTOCLRF               0x00000200      /* Auto clear to one */
+#define OBRSTALL               0x00001000      /* Stall on output buffer ready */
+#define IRRSTALL               0x00002000      /* Stall on immediate result ready */
+#define BITMIRR                        0x00010000      /* Mirror bits within each byte of 32-bit input data */
+#define BITMIRR_OFFSET         16              /* Mirror bits offset */
+#define BYTMIRR                        0x00020000      /* Mirror bytes of 32-bit input data */
+#define BYTMIRR_OFFSET         17              /* Mirror bytes offset */
+#define W16SWP                 0x00040000      /* Mirror uppper and lower 16-bit word of 32-bit input data */
+#define W16SWP_OFFSET          18              /* Mirror 16-bit word offset */
+#define FDSEL                  0x00080000      /* FIFO is written after input data is mirrored */
+#define FDSEL_OFFSET           19              /* Mirror FIFO offset */
+#define RSLTMIRR               0x00100000      /* CRC result registers are mirrored. */
+#define RSLTMIRR_OFFSET                20              /* Mirror CRC result offset. */
+#define POLYMIRR               0x00200000      /* CRC poly register is mirrored. */
+#define POLYMIRR_OFFSET                21              /* Mirror CRC poly offset. */
+#define CMPMIRR                        0x00400000      /* CRC compare register is mirrored. */
+#define CMPMIRR_OFFSET         22              /* Mirror CRC compare offset. */
+
+/* CRC_INTREN Masks */
+#define CMPERRI                0x02            /* CRC_ERROR_INTR */
+#define DCNTEXPI               0x10            /* CRC_STATUS_INTR */
+
+#endif
+
+#endif
index 0378328f47a775b368b795cd3d7adc9b678fd31b..2d244e629ed2e514a9830bca1d99a7b064e2ecb0 100644 (file)
@@ -545,7 +545,8 @@ static int ahash_setkey(struct crypto_ahash *ahash,
                                      DMA_TO_DEVICE);
        if (dma_mapping_error(jrdev, ctx->key_dma)) {
                dev_err(jrdev, "unable to map key i/o memory\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto map_err;
        }
 #ifdef DEBUG
        print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
@@ -559,6 +560,7 @@ static int ahash_setkey(struct crypto_ahash *ahash,
                                 DMA_TO_DEVICE);
        }
 
+map_err:
        kfree(hashed_key);
        return ret;
 badkey:
index 9f25f5296029aeb0a22e0caf81bf35ca41b00063..0eabd81e1a902711bb838eb93dfed8e3289be610 100644 (file)
        char *tmp;                                              \
                                                                \
        tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC);  \
-       sprintf(tmp, format, param);                            \
-       strcat(str, tmp);                                       \
-       kfree(tmp);                                             \
+       if (likely(tmp)) {                                      \
+               sprintf(tmp, format, param);                    \
+               strcat(str, tmp);                               \
+               kfree(tmp);                                     \
+       } else {                                                \
+               strcat(str, "kmalloc failure in SPRINTFCAT");   \
+       }                                                       \
 }
 
 static void report_jump_idx(u32 status, char *outstr)
index 93319f9db7531b5667542fe6b3c371046711fd5e..0d746236df5ef6ae886cfacc93b462efa8f96741 100644 (file)
@@ -48,12 +48,11 @@ static int ccp_get_msix_irqs(struct ccp_device *ccp)
        for (v = 0; v < ARRAY_SIZE(msix_entry); v++)
                msix_entry[v].entry = v;
 
-       while ((ret = pci_enable_msix(pdev, msix_entry, v)) > 0)
-               v = ret;
-       if (ret)
+       ret = pci_enable_msix_range(pdev, msix_entry, 1, v);
+       if (ret < 0)
                return ret;
 
-       ccp_pci->msix_count = v;
+       ccp_pci->msix_count = ret;
        for (v = 0; v < ccp_pci->msix_count; v++) {
                /* Set the interrupt names and request the irqs */
                snprintf(ccp_pci->msix[v].name, name_len, "ccp-%u", v);
index 1e5481d88a262c655aec0d381574341531f5f4ae..c4fcbf47475f59113df1a9c6f6366416e40dedeb 100644 (file)
@@ -1234,7 +1234,7 @@ static int __exit nx842_remove(struct vio_dev *viodev)
        old_devdata = rcu_dereference_check(devdata,
                        lockdep_is_held(&devdata_mutex));
        of_reconfig_notifier_unregister(&nx842_of_nb);
-       rcu_assign_pointer(devdata, NULL);
+       RCU_INIT_POINTER(devdata, NULL);
        spin_unlock_irqrestore(&devdata_mutex, flags);
        synchronize_rcu();
        dev_set_drvdata(&viodev->dev, NULL);
@@ -1285,7 +1285,7 @@ static void __exit nx842_exit(void)
        spin_lock_irqsave(&devdata_mutex, flags);
        old_devdata = rcu_dereference_check(devdata,
                        lockdep_is_held(&devdata_mutex));
-       rcu_assign_pointer(devdata, NULL);
+       RCU_INIT_POINTER(devdata, NULL);
        spin_unlock_irqrestore(&devdata_mutex, flags);
        synchronize_rcu();
        if (old_devdata)
index ec5f13162b733c027d1b2c8d2df2ac2def08c4d8..b8bc84be874178397e7c3ccf51e1bbca2e926634 100644 (file)
@@ -223,12 +223,19 @@ static void omap_des_write_n(struct omap_des_dev *dd, u32 offset,
 
 static int omap_des_hw_init(struct omap_des_dev *dd)
 {
+       int err;
+
        /*
         * clocks are enabled when request starts and disabled when finished.
         * It may be long delays between requests.
         * Device might go to off mode to save power.
         */
-       pm_runtime_get_sync(dd->dev);
+       err = pm_runtime_get_sync(dd->dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(dd->dev);
+               dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
+               return err;
+       }
 
        if (!(dd->flags & FLAGS_INIT)) {
                dd->flags |= FLAGS_INIT;
@@ -1074,16 +1081,20 @@ static int omap_des_probe(struct platform_device *pdev)
        if (err)
                goto err_res;
 
-       dd->io_base = devm_request_and_ioremap(dev, res);
-       if (!dd->io_base) {
-               dev_err(dev, "can't ioremap\n");
-               err = -ENOMEM;
+       dd->io_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(dd->io_base)) {
+               err = PTR_ERR(dd->io_base);
                goto err_res;
        }
        dd->phys_base = res->start;
 
        pm_runtime_enable(dev);
-       pm_runtime_get_sync(dev);
+       err = pm_runtime_get_sync(dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(dev);
+               dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
+               goto err_get;
+       }
 
        omap_des_dma_stop(dd);
 
@@ -1148,6 +1159,7 @@ err_algs:
 err_irq:
        tasklet_kill(&dd->done_task);
        tasklet_kill(&dd->queue_task);
+err_get:
        pm_runtime_disable(dev);
 err_res:
        dd = NULL;
@@ -1191,7 +1203,14 @@ static int omap_des_suspend(struct device *dev)
 
 static int omap_des_resume(struct device *dev)
 {
-       pm_runtime_get_sync(dev);
+       int err;
+
+       err = pm_runtime_get_sync(dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(dev);
+               dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err);
+               return err;
+       }
        return 0;
 }
 #endif
index 5c5863842de92bdd653fb0f24fdea96228c9908a..b30b7ed89fb27fe44606b0fe159a1b309c383848 100644 (file)
@@ -361,6 +361,20 @@ config FSL_EDMA
          multiplexing capability for DMA request sources(slot).
          This module can be found on Freescale Vybrid and LS-1 SoCs.
 
+config XILINX_VDMA
+       tristate "Xilinx AXI VDMA Engine"
+       depends on (ARCH_ZYNQ || MICROBLAZE)
+       select DMA_ENGINE
+       help
+         Enable support for Xilinx AXI VDMA Soft IP.
+
+         This engine provides high-bandwidth direct memory access
+         between memory and AXI4-Stream video type target
+         peripherals including peripherals which support AXI4-
+         Stream Video Protocol.  It has two stream interfaces/
+         channels, Memory Mapped to Stream (MM2S) and Stream to
+         Memory Mapped (S2MM) for the data transfers.
+
 config DMA_ENGINE
        bool
 
index 5150c82c9caf2e9203ee8935ebd8192346965d56..c779e1eb2db2acca9f35a1faf24dffb04dd930fb 100644 (file)
@@ -46,3 +46,4 @@ obj-$(CONFIG_K3_DMA) += k3dma.o
 obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
 obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
 obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o
+obj-y += xilinx/
index a886713937fd05b38fc10866bbce5266ac0bfae1..d5d30ed863ceb904c6e19e245b94d7ddba40f88f 100644 (file)
@@ -1009,6 +1009,7 @@ static void dmaengine_unmap(struct kref *kref)
                dma_unmap_page(dev, unmap->addr[i], unmap->len,
                               DMA_BIDIRECTIONAL);
        }
+       cnt = unmap->map_cnt;
        mempool_free(unmap, __get_unmap_pool(cnt)->pool);
 }
 
@@ -1074,6 +1075,7 @@ dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags)
        memset(unmap, 0, sizeof(*unmap));
        kref_init(&unmap->kref);
        unmap->dev = dev;
+       unmap->map_cnt = nr;
 
        return unmap;
 }
index 926360c2db6abcb3b448e815246e182fe1a7d3ae..d08c4dedef3585ba62e6681ec4a778ba65074907 100644 (file)
 #define EDMA_MAX_SLOTS         MAX_NR_SG
 #define EDMA_DESCRIPTORS       16
 
+struct edma_pset {
+       u32                             len;
+       dma_addr_t                      addr;
+       struct edmacc_param             param;
+};
+
 struct edma_desc {
        struct virt_dma_desc            vdesc;
        struct list_head                node;
+       enum dma_transfer_direction     direction;
        int                             cyclic;
        int                             absync;
        int                             pset_nr;
+       struct edma_chan                *echan;
        int                             processed;
-       struct edmacc_param             pset[0];
+
+       /*
+        * The following 4 elements are used for residue accounting.
+        *
+        * - processed_stat: the number of SG elements we have traversed
+        * so far to cover accounting. This is updated directly to processed
+        * during edma_callback and is always <= processed, because processed
+        * refers to the number of pending transfer (programmed to EDMA
+        * controller), where as processed_stat tracks number of transfers
+        * accounted for so far.
+        *
+        * - residue: The amount of bytes we have left to transfer for this desc
+        *
+        * - residue_stat: The residue in bytes of data we have covered
+        * so far for accounting. This is updated directly to residue
+        * during callbacks to keep it current.
+        *
+        * - sg_len: Tracks the length of the current intermediate transfer,
+        * this is required to update the residue during intermediate transfer
+        * completion callback.
+        */
+       int                             processed_stat;
+       u32                             sg_len;
+       u32                             residue;
+       u32                             residue_stat;
+
+       struct edma_pset                pset[0];
 };
 
 struct edma_cc;
@@ -136,12 +170,14 @@ static void edma_execute(struct edma_chan *echan)
        /* Find out how many left */
        left = edesc->pset_nr - edesc->processed;
        nslots = min(MAX_NR_SG, left);
+       edesc->sg_len = 0;
 
        /* Write descriptor PaRAM set(s) */
        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,
+               edma_write_slot(echan->slot[i], &edesc->pset[j].param);
+               edesc->sg_len += edesc->pset[j].len;
+               dev_vdbg(echan->vchan.chan.device->dev,
                        "\n pset[%d]:\n"
                        "  chnum\t%d\n"
                        "  slot\t%d\n"
@@ -154,14 +190,14 @@ static void edma_execute(struct edma_chan *echan)
                        "  cidx\t%08x\n"
                        "  lkrld\t%08x\n",
                        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);
+                       edesc->pset[j].param.opt,
+                       edesc->pset[j].param.src,
+                       edesc->pset[j].param.dst,
+                       edesc->pset[j].param.a_b_cnt,
+                       edesc->pset[j].param.ccnt,
+                       edesc->pset[j].param.src_dst_bidx,
+                       edesc->pset[j].param.src_dst_cidx,
+                       edesc->pset[j].param.link_bcntrld);
                /* Link to the previous slot if not the last set */
                if (i != (nslots - 1))
                        edma_link(echan->slot[i], echan->slot[i+1]);
@@ -183,7 +219,8 @@ static void edma_execute(struct edma_chan *echan)
        }
 
        if (edesc->processed <= MAX_NR_SG) {
-               dev_dbg(dev, "first transfer starting %d\n", echan->ch_num);
+               dev_dbg(dev, "first transfer starting on channel %d\n",
+                       echan->ch_num);
                edma_start(echan->ch_num);
        } else {
                dev_dbg(dev, "chan: %d: completed %d elements, resuming\n",
@@ -197,7 +234,7 @@ static void edma_execute(struct edma_chan *echan)
         * MAX_NR_SG
         */
        if (echan->missed) {
-               dev_dbg(dev, "missed event in execute detected\n");
+               dev_dbg(dev, "missed event on channel %d\n", echan->ch_num);
                edma_clean_channel(echan->ch_num);
                edma_stop(echan->ch_num);
                edma_start(echan->ch_num);
@@ -242,6 +279,26 @@ static int edma_slave_config(struct edma_chan *echan,
        return 0;
 }
 
+static int edma_dma_pause(struct edma_chan *echan)
+{
+       /* Pause/Resume only allowed with cyclic mode */
+       if (!echan->edesc->cyclic)
+               return -EINVAL;
+
+       edma_pause(echan->ch_num);
+       return 0;
+}
+
+static int edma_dma_resume(struct edma_chan *echan)
+{
+       /* Pause/Resume only allowed with cyclic mode */
+       if (!echan->edesc->cyclic)
+               return -EINVAL;
+
+       edma_resume(echan->ch_num);
+       return 0;
+}
+
 static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                        unsigned long arg)
 {
@@ -257,6 +314,14 @@ static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                config = (struct dma_slave_config *)arg;
                ret = edma_slave_config(echan, config);
                break;
+       case DMA_PAUSE:
+               ret = edma_dma_pause(echan);
+               break;
+
+       case DMA_RESUME:
+               ret = edma_dma_resume(echan);
+               break;
+
        default:
                ret = -ENOSYS;
        }
@@ -275,18 +340,23 @@ static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
  * @dma_length: Total length of the DMA transfer
  * @direction: Direction of the transfer
  */
-static int edma_config_pset(struct dma_chan *chan, struct edmacc_param *pset,
+static int edma_config_pset(struct dma_chan *chan, struct edma_pset *epset,
        dma_addr_t src_addr, dma_addr_t dst_addr, u32 burst,
        enum dma_slave_buswidth dev_width, unsigned int dma_length,
        enum dma_transfer_direction direction)
 {
        struct edma_chan *echan = to_edma_chan(chan);
        struct device *dev = chan->device->dev;
+       struct edmacc_param *param = &epset->param;
        int acnt, bcnt, ccnt, cidx;
        int src_bidx, dst_bidx, src_cidx, dst_cidx;
        int absync;
 
        acnt = dev_width;
+
+       /* src/dst_maxburst == 0 is the same case as src/dst_maxburst == 1 */
+       if (!burst)
+               burst = 1;
        /*
         * If the maxburst is equal to the fifo width, use
         * A-synced transfers. This allows for large contiguous
@@ -337,41 +407,50 @@ static int edma_config_pset(struct dma_chan *chan, struct edmacc_param *pset,
                cidx = acnt * bcnt;
        }
 
+       epset->len = dma_length;
+
        if (direction == DMA_MEM_TO_DEV) {
                src_bidx = acnt;
                src_cidx = cidx;
                dst_bidx = 0;
                dst_cidx = 0;
+               epset->addr = src_addr;
        } else if (direction == DMA_DEV_TO_MEM)  {
                src_bidx = 0;
                src_cidx = 0;
                dst_bidx = acnt;
                dst_cidx = cidx;
+               epset->addr = dst_addr;
+       } else if (direction == DMA_MEM_TO_MEM)  {
+               src_bidx = acnt;
+               src_cidx = cidx;
+               dst_bidx = acnt;
+               dst_cidx = cidx;
        } else {
                dev_err(dev, "%s: direction not implemented yet\n", __func__);
                return -EINVAL;
        }
 
-       pset->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
+       param->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
        /* Configure A or AB synchronized transfers */
        if (absync)
-               pset->opt |= SYNCDIM;
+               param->opt |= SYNCDIM;
 
-       pset->src = src_addr;
-       pset->dst = dst_addr;
+       param->src = src_addr;
+       param->dst = dst_addr;
 
-       pset->src_dst_bidx = (dst_bidx << 16) | src_bidx;
-       pset->src_dst_cidx = (dst_cidx << 16) | src_cidx;
+       param->src_dst_bidx = (dst_bidx << 16) | src_bidx;
+       param->src_dst_cidx = (dst_cidx << 16) | src_cidx;
 
-       pset->a_b_cnt = bcnt << 16 | acnt;
-       pset->ccnt = ccnt;
+       param->a_b_cnt = bcnt << 16 | acnt;
+       param->ccnt = ccnt;
        /*
         * Only time when (bcntrld) auto reload is required is for
         * A-sync case, and in this case, a requirement of reload value
         * of SZ_64K-1 only is assured. 'link' is initially set to NULL
         * and then later will be populated by edma_execute.
         */
-       pset->link_bcntrld = 0xffffffff;
+       param->link_bcntrld = 0xffffffff;
        return absync;
 }
 
@@ -401,23 +480,26 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                dev_width = echan->cfg.dst_addr_width;
                burst = echan->cfg.dst_maxburst;
        } else {
-               dev_err(dev, "%s: bad direction?\n", __func__);
+               dev_err(dev, "%s: bad direction: %d\n", __func__, direction);
                return NULL;
        }
 
        if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
-               dev_err(dev, "Undefined slave buswidth\n");
+               dev_err(dev, "%s: Undefined slave buswidth\n", __func__);
                return NULL;
        }
 
        edesc = kzalloc(sizeof(*edesc) + sg_len *
                sizeof(edesc->pset[0]), GFP_ATOMIC);
        if (!edesc) {
-               dev_dbg(dev, "Failed to allocate a descriptor\n");
+               dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__);
                return NULL;
        }
 
        edesc->pset_nr = sg_len;
+       edesc->residue = 0;
+       edesc->direction = direction;
+       edesc->echan = echan;
 
        /* Allocate a PaRAM slot, if needed */
        nslots = min_t(unsigned, MAX_NR_SG, sg_len);
@@ -429,7 +511,8 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                                                EDMA_SLOT_ANY);
                        if (echan->slot[i] < 0) {
                                kfree(edesc);
-                               dev_err(dev, "Failed to allocate slot\n");
+                               dev_err(dev, "%s: Failed to allocate slot\n",
+                                       __func__);
                                return NULL;
                        }
                }
@@ -452,16 +535,56 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                }
 
                edesc->absync = ret;
+               edesc->residue += sg_dma_len(sg);
 
                /* 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;
+                       edesc->pset[i].param.opt |= TCINTEN;
 
                /* If this is the last set, enable completion interrupt flag */
                if (i == sg_len - 1)
-                       edesc->pset[i].opt |= TCINTEN;
+                       edesc->pset[i].param.opt |= TCINTEN;
        }
+       edesc->residue_stat = edesc->residue;
+
+       return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
+}
+
+struct dma_async_tx_descriptor *edma_prep_dma_memcpy(
+       struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+       size_t len, unsigned long tx_flags)
+{
+       int ret;
+       struct edma_desc *edesc;
+       struct device *dev = chan->device->dev;
+       struct edma_chan *echan = to_edma_chan(chan);
+
+       if (unlikely(!echan || !len))
+               return NULL;
+
+       edesc = kzalloc(sizeof(*edesc) + sizeof(edesc->pset[0]), GFP_ATOMIC);
+       if (!edesc) {
+               dev_dbg(dev, "Failed to allocate a descriptor\n");
+               return NULL;
+       }
+
+       edesc->pset_nr = 1;
+
+       ret = edma_config_pset(chan, &edesc->pset[0], src, dest, 1,
+                              DMA_SLAVE_BUSWIDTH_4_BYTES, len, DMA_MEM_TO_MEM);
+       if (ret < 0)
+               return NULL;
+
+       edesc->absync = ret;
+
+       /*
+        * Enable intermediate transfer chaining to re-trigger channel
+        * on completion of every TR, and enable transfer-completion
+        * interrupt on completion of the whole transfer.
+        */
+       edesc->pset[0].param.opt |= ITCCHEN;
+       edesc->pset[0].param.opt |= TCINTEN;
 
        return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
 }
@@ -493,12 +616,12 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                dev_width = echan->cfg.dst_addr_width;
                burst = echan->cfg.dst_maxburst;
        } else {
-               dev_err(dev, "%s: bad direction?\n", __func__);
+               dev_err(dev, "%s: bad direction: %d\n", __func__, direction);
                return NULL;
        }
 
        if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
-               dev_err(dev, "Undefined slave buswidth\n");
+               dev_err(dev, "%s: Undefined slave buswidth\n", __func__);
                return NULL;
        }
 
@@ -523,16 +646,18 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
        edesc = kzalloc(sizeof(*edesc) + nslots *
                sizeof(edesc->pset[0]), GFP_ATOMIC);
        if (!edesc) {
-               dev_dbg(dev, "Failed to allocate a descriptor\n");
+               dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__);
                return NULL;
        }
 
        edesc->cyclic = 1;
        edesc->pset_nr = nslots;
+       edesc->residue = edesc->residue_stat = buf_len;
+       edesc->direction = direction;
+       edesc->echan = echan;
 
-       dev_dbg(dev, "%s: nslots=%d\n", __func__, nslots);
-       dev_dbg(dev, "%s: period_len=%d\n", __func__, period_len);
-       dev_dbg(dev, "%s: buf_len=%d\n", __func__, buf_len);
+       dev_dbg(dev, "%s: channel=%d nslots=%d period_len=%zu buf_len=%zu\n",
+               __func__, echan->ch_num, nslots, period_len, buf_len);
 
        for (i = 0; i < nslots; i++) {
                /* Allocate a PaRAM slot, if needed */
@@ -542,7 +667,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                                                EDMA_SLOT_ANY);
                        if (echan->slot[i] < 0) {
                                kfree(edesc);
-                               dev_err(dev, "Failed to allocate slot\n");
+                               dev_err(dev, "%s: Failed to allocate slot\n",
+                                       __func__);
                                return NULL;
                        }
                }
@@ -566,8 +692,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                else
                        src_addr += period_len;
 
-               dev_dbg(dev, "%s: Configure period %d of buf:\n", __func__, i);
-               dev_dbg(dev,
+               dev_vdbg(dev, "%s: Configure period %d of buf:\n", __func__, i);
+               dev_vdbg(dev,
                        "\n pset[%d]:\n"
                        "  chnum\t%d\n"
                        "  slot\t%d\n"
@@ -580,14 +706,14 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                        "  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);
+                       edesc->pset[i].param.opt,
+                       edesc->pset[i].param.src,
+                       edesc->pset[i].param.dst,
+                       edesc->pset[i].param.a_b_cnt,
+                       edesc->pset[i].param.ccnt,
+                       edesc->pset[i].param.src_dst_bidx,
+                       edesc->pset[i].param.src_dst_cidx,
+                       edesc->pset[i].param.link_bcntrld);
 
                edesc->absync = ret;
 
@@ -595,7 +721,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                 * Enable interrupts for every period because callback
                 * has to be called for every period.
                 */
-               edesc->pset[i].opt |= TCINTEN;
+               edesc->pset[i].param.opt |= TCINTEN;
        }
 
        return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
@@ -606,7 +732,6 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
        struct edma_chan *echan = data;
        struct device *dev = echan->vchan.chan.device->dev;
        struct edma_desc *edesc;
-       unsigned long flags;
        struct edmacc_param p;
 
        edesc = echan->edesc;
@@ -617,27 +742,34 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
 
        switch (ch_status) {
        case EDMA_DMA_COMPLETE:
-               spin_lock_irqsave(&echan->vchan.lock, flags);
+               spin_lock(&echan->vchan.lock);
 
                if (edesc) {
                        if (edesc->cyclic) {
                                vchan_cyclic_callback(&edesc->vdesc);
                        } else if (edesc->processed == edesc->pset_nr) {
                                dev_dbg(dev, "Transfer complete, stopping channel %d\n", ch_num);
+                               edesc->residue = 0;
                                edma_stop(echan->ch_num);
                                vchan_cookie_complete(&edesc->vdesc);
                                edma_execute(echan);
                        } else {
                                dev_dbg(dev, "Intermediate transfer complete on channel %d\n", ch_num);
+
+                               /* Update statistics for tx_status */
+                               edesc->residue -= edesc->sg_len;
+                               edesc->residue_stat = edesc->residue;
+                               edesc->processed_stat = edesc->processed;
+
                                edma_execute(echan);
                        }
                }
 
-               spin_unlock_irqrestore(&echan->vchan.lock, flags);
+               spin_unlock(&echan->vchan.lock);
 
                break;
        case EDMA_DMA_CC_ERROR:
-               spin_lock_irqsave(&echan->vchan.lock, flags);
+               spin_lock(&echan->vchan.lock);
 
                edma_read_slot(EDMA_CHAN_SLOT(echan->slot[0]), &p);
 
@@ -668,7 +800,7 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
                        edma_trigger_channel(echan->ch_num);
                }
 
-               spin_unlock_irqrestore(&echan->vchan.lock, flags);
+               spin_unlock(&echan->vchan.lock);
 
                break;
        default:
@@ -704,7 +836,7 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
        echan->alloced = true;
        echan->slot[0] = echan->ch_num;
 
-       dev_dbg(dev, "allocated channel for %u:%u\n",
+       dev_dbg(dev, "allocated channel %d for %u:%u\n", echan->ch_num,
                EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num));
 
        return 0;
@@ -756,23 +888,52 @@ static void edma_issue_pending(struct dma_chan *chan)
        spin_unlock_irqrestore(&echan->vchan.lock, flags);
 }
 
-static size_t edma_desc_size(struct edma_desc *edesc)
+static u32 edma_residue(struct edma_desc *edesc)
 {
+       bool dst = edesc->direction == DMA_DEV_TO_MEM;
+       struct edma_pset *pset = edesc->pset;
+       dma_addr_t done, pos;
        int i;
-       size_t size;
-
-       if (edesc->absync)
-               for (size = i = 0; i < edesc->pset_nr; i++)
-                       size += (edesc->pset[i].a_b_cnt & 0xffff) *
-                               (edesc->pset[i].a_b_cnt >> 16) *
-                                edesc->pset[i].ccnt;
-       else
-               size = (edesc->pset[0].a_b_cnt & 0xffff) *
-                       (edesc->pset[0].a_b_cnt >> 16) +
-                       (edesc->pset[0].a_b_cnt & 0xffff) *
-                       (SZ_64K - 1) * edesc->pset[0].ccnt;
-
-       return size;
+
+       /*
+        * We always read the dst/src position from the first RamPar
+        * pset. That's the one which is active now.
+        */
+       pos = edma_get_position(edesc->echan->slot[0], dst);
+
+       /*
+        * Cyclic is simple. Just subtract pset[0].addr from pos.
+        *
+        * We never update edesc->residue in the cyclic case, so we
+        * can tell the remaining room to the end of the circular
+        * buffer.
+        */
+       if (edesc->cyclic) {
+               done = pos - pset->addr;
+               edesc->residue_stat = edesc->residue - done;
+               return edesc->residue_stat;
+       }
+
+       /*
+        * For SG operation we catch up with the last processed
+        * status.
+        */
+       pset += edesc->processed_stat;
+
+       for (i = edesc->processed_stat; i < edesc->processed; i++, pset++) {
+               /*
+                * If we are inside this pset address range, we know
+                * this is the active one. Get the current delta and
+                * stop walking the psets.
+                */
+               if (pos >= pset->addr && pos < pset->addr + pset->len)
+                       return edesc->residue_stat - (pos - pset->addr);
+
+               /* Otherwise mark it done and update residue_stat. */
+               edesc->processed_stat++;
+               edesc->residue_stat -= pset->len;
+       }
+       return edesc->residue_stat;
 }
 
 /* Check request completion status */
@@ -790,13 +951,10 @@ static enum dma_status edma_tx_status(struct dma_chan *chan,
                return ret;
 
        spin_lock_irqsave(&echan->vchan.lock, flags);
-       vdesc = vchan_find_desc(&echan->vchan, cookie);
-       if (vdesc) {
-               txstate->residue = edma_desc_size(to_edma_desc(&vdesc->tx));
-       } else if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) {
-               struct edma_desc *edesc = echan->edesc;
-               txstate->residue = edma_desc_size(edesc);
-       }
+       if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie)
+               txstate->residue = edma_residue(echan->edesc);
+       else if ((vdesc = vchan_find_desc(&echan->vchan, cookie)))
+               txstate->residue = to_edma_desc(&vdesc->tx)->residue;
        spin_unlock_irqrestore(&echan->vchan.lock, flags);
 
        return ret;
@@ -822,18 +980,43 @@ static void __init edma_chan_init(struct edma_cc *ecc,
        }
 }
 
+#define EDMA_DMA_BUSWIDTHS     (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
+static int edma_dma_device_slave_caps(struct dma_chan *dchan,
+                                     struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = EDMA_DMA_BUSWIDTHS;
+       caps->dstn_addr_widths = EDMA_DMA_BUSWIDTHS;
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = true;
+       caps->cmd_terminate = true;
+       caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+
+       return 0;
+}
+
 static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
                          struct device *dev)
 {
        dma->device_prep_slave_sg = edma_prep_slave_sg;
        dma->device_prep_dma_cyclic = edma_prep_dma_cyclic;
+       dma->device_prep_dma_memcpy = edma_prep_dma_memcpy;
        dma->device_alloc_chan_resources = edma_alloc_chan_resources;
        dma->device_free_chan_resources = edma_free_chan_resources;
        dma->device_issue_pending = edma_issue_pending;
        dma->device_tx_status = edma_tx_status;
        dma->device_control = edma_control;
+       dma->device_slave_caps = edma_dma_device_slave_caps;
        dma->dev = dev;
 
+       /*
+        * code using dma memcpy must make sure alignment of
+        * length is at dma->copy_align boundary.
+        */
+       dma->copy_align = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
        INIT_LIST_HEAD(&dma->channels);
 }
 
@@ -861,6 +1044,8 @@ static int edma_probe(struct platform_device *pdev)
 
        dma_cap_zero(ecc->dma_slave.cap_mask);
        dma_cap_set(DMA_SLAVE, ecc->dma_slave.cap_mask);
+       dma_cap_set(DMA_CYCLIC, ecc->dma_slave.cap_mask);
+       dma_cap_set(DMA_MEMCPY, ecc->dma_slave.cap_mask);
 
        edma_dma_init(ecc, &ecc->dma_slave, &pdev->dev);
 
index f157c6f76b32b8c98dce28eed6253db033acc258..e0fec68aed2511220206960a1b0930cf65e696b8 100644 (file)
@@ -61,6 +61,16 @@ static u32 get_sr(struct fsldma_chan *chan)
        return DMA_IN(chan, &chan->regs->sr, 32);
 }
 
+static void set_mr(struct fsldma_chan *chan, u32 val)
+{
+       DMA_OUT(chan, &chan->regs->mr, val, 32);
+}
+
+static u32 get_mr(struct fsldma_chan *chan)
+{
+       return DMA_IN(chan, &chan->regs->mr, 32);
+}
+
 static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
 {
        DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
@@ -71,6 +81,11 @@ static dma_addr_t get_cdar(struct fsldma_chan *chan)
        return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
 }
 
+static void set_bcr(struct fsldma_chan *chan, u32 val)
+{
+       DMA_OUT(chan, &chan->regs->bcr, val, 32);
+}
+
 static u32 get_bcr(struct fsldma_chan *chan)
 {
        return DMA_IN(chan, &chan->regs->bcr, 32);
@@ -135,7 +150,7 @@ static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 static void dma_init(struct fsldma_chan *chan)
 {
        /* Reset the channel */
-       DMA_OUT(chan, &chan->regs->mr, 0, 32);
+       set_mr(chan, 0);
 
        switch (chan->feature & FSL_DMA_IP_MASK) {
        case FSL_DMA_IP_85XX:
@@ -144,16 +159,15 @@ static void dma_init(struct fsldma_chan *chan)
                 * EOLNIE - End of links interrupt enable
                 * BWC - Bandwidth sharing among channels
                 */
-               DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
-                               | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE, 32);
+               set_mr(chan, FSL_DMA_MR_BWC | FSL_DMA_MR_EIE
+                       | FSL_DMA_MR_EOLNIE);
                break;
        case FSL_DMA_IP_83XX:
                /* Set the channel to below modes:
                 * EOTIE - End-of-transfer interrupt enable
                 * PRC_RM - PCI read multiple
                 */
-               DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
-                               | FSL_DMA_MR_PRC_RM, 32);
+               set_mr(chan, FSL_DMA_MR_EOTIE | FSL_DMA_MR_PRC_RM);
                break;
        }
 }
@@ -175,10 +189,10 @@ static void dma_start(struct fsldma_chan *chan)
 {
        u32 mode;
 
-       mode = DMA_IN(chan, &chan->regs->mr, 32);
+       mode = get_mr(chan);
 
        if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
-               DMA_OUT(chan, &chan->regs->bcr, 0, 32);
+               set_bcr(chan, 0);
                mode |= FSL_DMA_MR_EMP_EN;
        } else {
                mode &= ~FSL_DMA_MR_EMP_EN;
@@ -191,7 +205,7 @@ static void dma_start(struct fsldma_chan *chan)
                mode |= FSL_DMA_MR_CS;
        }
 
-       DMA_OUT(chan, &chan->regs->mr, mode, 32);
+       set_mr(chan, mode);
 }
 
 static void dma_halt(struct fsldma_chan *chan)
@@ -200,7 +214,7 @@ static void dma_halt(struct fsldma_chan *chan)
        int i;
 
        /* read the mode register */
-       mode = DMA_IN(chan, &chan->regs->mr, 32);
+       mode = get_mr(chan);
 
        /*
         * The 85xx controller supports channel abort, which will stop
@@ -209,14 +223,14 @@ static void dma_halt(struct fsldma_chan *chan)
         */
        if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
                mode |= FSL_DMA_MR_CA;
-               DMA_OUT(chan, &chan->regs->mr, mode, 32);
+               set_mr(chan, mode);
 
                mode &= ~FSL_DMA_MR_CA;
        }
 
        /* stop the DMA controller */
        mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN);
-       DMA_OUT(chan, &chan->regs->mr, mode, 32);
+       set_mr(chan, mode);
 
        /* wait for the DMA controller to become idle */
        for (i = 0; i < 100; i++) {
@@ -245,7 +259,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size)
 {
        u32 mode;
 
-       mode = DMA_IN(chan, &chan->regs->mr, 32);
+       mode = get_mr(chan);
 
        switch (size) {
        case 0:
@@ -259,7 +273,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size)
                break;
        }
 
-       DMA_OUT(chan, &chan->regs->mr, mode, 32);
+       set_mr(chan, mode);
 }
 
 /**
@@ -277,7 +291,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size)
 {
        u32 mode;
 
-       mode = DMA_IN(chan, &chan->regs->mr, 32);
+       mode = get_mr(chan);
 
        switch (size) {
        case 0:
@@ -291,7 +305,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size)
                break;
        }
 
-       DMA_OUT(chan, &chan->regs->mr, mode, 32);
+       set_mr(chan, mode);
 }
 
 /**
@@ -312,10 +326,10 @@ static void fsl_chan_set_request_count(struct fsldma_chan *chan, int size)
 
        BUG_ON(size > 1024);
 
-       mode = DMA_IN(chan, &chan->regs->mr, 32);
+       mode = get_mr(chan);
        mode |= (__ilog2(size) << 24) & 0x0f000000;
 
-       DMA_OUT(chan, &chan->regs->mr, mode, 32);
+       set_mr(chan, mode);
 }
 
 /**
@@ -403,6 +417,19 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
        return cookie;
 }
 
+/**
+ * fsl_dma_free_descriptor - Free descriptor from channel's DMA pool.
+ * @chan : Freescale DMA channel
+ * @desc: descriptor to be freed
+ */
+static void fsl_dma_free_descriptor(struct fsldma_chan *chan,
+               struct fsl_desc_sw *desc)
+{
+       list_del(&desc->node);
+       chan_dbg(chan, "LD %p free\n", desc);
+       dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
+}
+
 /**
  * fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool.
  * @chan : Freescale DMA channel
@@ -426,13 +453,106 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan)
        desc->async_tx.tx_submit = fsl_dma_tx_submit;
        desc->async_tx.phys = pdesc;
 
-#ifdef FSL_DMA_LD_DEBUG
        chan_dbg(chan, "LD %p allocated\n", desc);
-#endif
 
        return desc;
 }
 
+/**
+ * fsl_chan_xfer_ld_queue - transfer any pending transactions
+ * @chan : Freescale DMA channel
+ *
+ * HARDWARE STATE: idle
+ * LOCKING: must hold chan->desc_lock
+ */
+static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
+{
+       struct fsl_desc_sw *desc;
+
+       /*
+        * If the list of pending descriptors is empty, then we
+        * don't need to do any work at all
+        */
+       if (list_empty(&chan->ld_pending)) {
+               chan_dbg(chan, "no pending LDs\n");
+               return;
+       }
+
+       /*
+        * The DMA controller is not idle, which means that the interrupt
+        * handler will start any queued transactions when it runs after
+        * this transaction finishes
+        */
+       if (!chan->idle) {
+               chan_dbg(chan, "DMA controller still busy\n");
+               return;
+       }
+
+       /*
+        * If there are some link descriptors which have not been
+        * transferred, we need to start the controller
+        */
+
+       /*
+        * Move all elements from the queue of pending transactions
+        * onto the list of running transactions
+        */
+       chan_dbg(chan, "idle, starting controller\n");
+       desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node);
+       list_splice_tail_init(&chan->ld_pending, &chan->ld_running);
+
+       /*
+        * The 85xx DMA controller doesn't clear the channel start bit
+        * automatically at the end of a transfer. Therefore we must clear
+        * it in software before starting the transfer.
+        */
+       if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+               u32 mode;
+
+               mode = get_mr(chan);
+               mode &= ~FSL_DMA_MR_CS;
+               set_mr(chan, mode);
+       }
+
+       /*
+        * Program the descriptor's address into the DMA controller,
+        * then start the DMA transaction
+        */
+       set_cdar(chan, desc->async_tx.phys);
+       get_cdar(chan);
+
+       dma_start(chan);
+       chan->idle = false;
+}
+
+/**
+ * fsldma_cleanup_descriptor - cleanup and free a single link descriptor
+ * @chan: Freescale DMA channel
+ * @desc: descriptor to cleanup and free
+ *
+ * This function is used on a descriptor which has been executed by the DMA
+ * controller. It will run any callbacks, submit any dependencies, and then
+ * free the descriptor.
+ */
+static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
+                                     struct fsl_desc_sw *desc)
+{
+       struct dma_async_tx_descriptor *txd = &desc->async_tx;
+
+       /* Run the link descriptor callback function */
+       if (txd->callback) {
+               chan_dbg(chan, "LD %p callback\n", desc);
+               txd->callback(txd->callback_param);
+       }
+
+       /* Run any dependencies */
+       dma_run_dependencies(txd);
+
+       dma_descriptor_unmap(txd);
+       chan_dbg(chan, "LD %p free\n", desc);
+       dma_pool_free(chan->desc_pool, desc, txd->phys);
+}
+
 /**
  * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
  * @chan : Freescale DMA channel
@@ -477,13 +597,8 @@ static void fsldma_free_desc_list(struct fsldma_chan *chan,
 {
        struct fsl_desc_sw *desc, *_desc;
 
-       list_for_each_entry_safe(desc, _desc, list, node) {
-               list_del(&desc->node);
-#ifdef FSL_DMA_LD_DEBUG
-               chan_dbg(chan, "LD %p free\n", desc);
-#endif
-               dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
-       }
+       list_for_each_entry_safe(desc, _desc, list, node)
+               fsl_dma_free_descriptor(chan, desc);
 }
 
 static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
@@ -491,13 +606,8 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
 {
        struct fsl_desc_sw *desc, *_desc;
 
-       list_for_each_entry_safe_reverse(desc, _desc, list, node) {
-               list_del(&desc->node);
-#ifdef FSL_DMA_LD_DEBUG
-               chan_dbg(chan, "LD %p free\n", desc);
-#endif
-               dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
-       }
+       list_for_each_entry_safe_reverse(desc, _desc, list, node)
+               fsl_dma_free_descriptor(chan, desc);
 }
 
 /**
@@ -519,35 +629,6 @@ static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
        chan->desc_pool = NULL;
 }
 
-static struct dma_async_tx_descriptor *
-fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
-{
-       struct fsldma_chan *chan;
-       struct fsl_desc_sw *new;
-
-       if (!dchan)
-               return NULL;
-
-       chan = to_fsl_chan(dchan);
-
-       new = fsl_dma_alloc_descriptor(chan);
-       if (!new) {
-               chan_err(chan, "%s\n", msg_ld_oom);
-               return NULL;
-       }
-
-       new->async_tx.cookie = -EBUSY;
-       new->async_tx.flags = flags;
-
-       /* Insert the link descriptor to the LD ring */
-       list_add_tail(&new->node, &new->tx_list);
-
-       /* Set End-of-link to the last link descriptor of new list */
-       set_ld_eol(chan, new);
-
-       return &new->async_tx;
-}
-
 static struct dma_async_tx_descriptor *
 fsl_dma_prep_memcpy(struct dma_chan *dchan,
        dma_addr_t dma_dst, dma_addr_t dma_src,
@@ -816,105 +897,6 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
        return 0;
 }
 
-/**
- * fsldma_cleanup_descriptor - cleanup and free a single link descriptor
- * @chan: Freescale DMA channel
- * @desc: descriptor to cleanup and free
- *
- * This function is used on a descriptor which has been executed by the DMA
- * controller. It will run any callbacks, submit any dependencies, and then
- * free the descriptor.
- */
-static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
-                                     struct fsl_desc_sw *desc)
-{
-       struct dma_async_tx_descriptor *txd = &desc->async_tx;
-
-       /* Run the link descriptor callback function */
-       if (txd->callback) {
-#ifdef FSL_DMA_LD_DEBUG
-               chan_dbg(chan, "LD %p callback\n", desc);
-#endif
-               txd->callback(txd->callback_param);
-       }
-
-       /* Run any dependencies */
-       dma_run_dependencies(txd);
-
-       dma_descriptor_unmap(txd);
-#ifdef FSL_DMA_LD_DEBUG
-       chan_dbg(chan, "LD %p free\n", desc);
-#endif
-       dma_pool_free(chan->desc_pool, desc, txd->phys);
-}
-
-/**
- * fsl_chan_xfer_ld_queue - transfer any pending transactions
- * @chan : Freescale DMA channel
- *
- * HARDWARE STATE: idle
- * LOCKING: must hold chan->desc_lock
- */
-static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
-{
-       struct fsl_desc_sw *desc;
-
-       /*
-        * If the list of pending descriptors is empty, then we
-        * don't need to do any work at all
-        */
-       if (list_empty(&chan->ld_pending)) {
-               chan_dbg(chan, "no pending LDs\n");
-               return;
-       }
-
-       /*
-        * The DMA controller is not idle, which means that the interrupt
-        * handler will start any queued transactions when it runs after
-        * this transaction finishes
-        */
-       if (!chan->idle) {
-               chan_dbg(chan, "DMA controller still busy\n");
-               return;
-       }
-
-       /*
-        * If there are some link descriptors which have not been
-        * transferred, we need to start the controller
-        */
-
-       /*
-        * Move all elements from the queue of pending transactions
-        * onto the list of running transactions
-        */
-       chan_dbg(chan, "idle, starting controller\n");
-       desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node);
-       list_splice_tail_init(&chan->ld_pending, &chan->ld_running);
-
-       /*
-        * The 85xx DMA controller doesn't clear the channel start bit
-        * automatically at the end of a transfer. Therefore we must clear
-        * it in software before starting the transfer.
-        */
-       if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
-               u32 mode;
-
-               mode = DMA_IN(chan, &chan->regs->mr, 32);
-               mode &= ~FSL_DMA_MR_CS;
-               DMA_OUT(chan, &chan->regs->mr, mode, 32);
-       }
-
-       /*
-        * Program the descriptor's address into the DMA controller,
-        * then start the DMA transaction
-        */
-       set_cdar(chan, desc->async_tx.phys);
-       get_cdar(chan);
-
-       dma_start(chan);
-       chan->idle = false;
-}
-
 /**
  * fsl_dma_memcpy_issue_pending - Issue the DMA start command
  * @chan : Freescale DMA channel
@@ -1304,12 +1286,10 @@ static int fsldma_of_probe(struct platform_device *op)
        fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
 
        dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
-       dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
        dma_cap_set(DMA_SG, fdev->common.cap_mask);
        dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
        fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
        fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
-       fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
        fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
        fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
        fdev->common.device_tx_status = fsl_tx_status;
index 9e84d5bc930779d4b8f60c98a68ac43108bd3660..3b55bb8d969a6e609e839e6fc5eb26f2713ffe28 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "dma.h"
 #include "registers.h"
+#include "dma_v2.h"
 
 /*
  * Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6
@@ -147,7 +148,7 @@ static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev)
        u16 id;
 
        /* This implementation only supports PCI-Express */
-       if (dev->bus != &pci_bus_type)
+       if (!dev_is_pci(dev))
                return -ENODEV;
        pdev = to_pci_dev(dev);
        id = dcaid_from_pcidev(pdev);
@@ -179,7 +180,7 @@ static int ioat_dca_remove_requester(struct dca_provider *dca,
        int i;
 
        /* This implementation only supports PCI-Express */
-       if (dev->bus != &pci_bus_type)
+       if (!dev_is_pci(dev))
                return -ENODEV;
        pdev = to_pci_dev(dev);
 
@@ -320,7 +321,7 @@ static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev)
        u16 global_req_table;
 
        /* This implementation only supports PCI-Express */
-       if (dev->bus != &pci_bus_type)
+       if (!dev_is_pci(dev))
                return -ENODEV;
        pdev = to_pci_dev(dev);
        id = dcaid_from_pcidev(pdev);
@@ -354,7 +355,7 @@ static int ioat2_dca_remove_requester(struct dca_provider *dca,
        u16 global_req_table;
 
        /* This implementation only supports PCI-Express */
-       if (dev->bus != &pci_bus_type)
+       if (!dev_is_pci(dev))
                return -ENODEV;
        pdev = to_pci_dev(dev);
 
@@ -496,7 +497,7 @@ static int ioat3_dca_add_requester(struct dca_provider *dca, struct device *dev)
        u16 global_req_table;
 
        /* This implementation only supports PCI-Express */
-       if (dev->bus != &pci_bus_type)
+       if (!dev_is_pci(dev))
                return -ENODEV;
        pdev = to_pci_dev(dev);
        id = dcaid_from_pcidev(pdev);
@@ -530,7 +531,7 @@ static int ioat3_dca_remove_requester(struct dca_provider *dca,
        u16 global_req_table;
 
        /* This implementation only supports PCI-Express */
-       if (dev->bus != &pci_bus_type)
+       if (!dev_is_pci(dev))
                return -ENODEV;
        pdev = to_pci_dev(dev);
 
index 4e3549a161324f29159775312b3c9d8075914359..b76c1485933bebd0e9b45371f2681dd8986c2ba2 100644 (file)
@@ -947,7 +947,7 @@ msix:
        for (i = 0; i < msixcnt; i++)
                device->msix_entries[i].entry = i;
 
-       err = pci_enable_msix(pdev, device->msix_entries, msixcnt);
+       err = pci_enable_msix_exact(pdev, device->msix_entries, msixcnt);
        if (err)
                goto msi;
 
index b9b38a1cf92fbdc4147e70af93508f0d9caf6867..85971d6e964687f7f6f9bd61be4e97d5e4b7d81e 100644 (file)
@@ -740,7 +740,7 @@ ioat3_prep_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
        return __ioat3_prep_xor_lock(chan, NULL, dest, src, src_cnt, len, flags);
 }
 
-struct dma_async_tx_descriptor *
+static struct dma_async_tx_descriptor *
 ioat3_prep_xor_val(struct dma_chan *chan, dma_addr_t *src,
                    unsigned int src_cnt, size_t len,
                    enum sum_check_flags *result, unsigned long flags)
@@ -1091,7 +1091,7 @@ ioat3_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
        }
 }
 
-struct dma_async_tx_descriptor *
+static struct dma_async_tx_descriptor *
 ioat3_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
                  unsigned int src_cnt, const unsigned char *scf, size_t len,
                  enum sum_check_flags *pqres, unsigned long flags)
@@ -1133,7 +1133,7 @@ ioat3_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
                                     flags);
 }
 
-struct dma_async_tx_descriptor *
+static struct dma_async_tx_descriptor *
 ioat3_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src,
                     unsigned int src_cnt, size_t len,
                     enum sum_check_flags *result, unsigned long flags)
index bf02e7beb51ad5c206cd65dd684a3a3ce83a0f77..7affa533d2a8d6c72f8458892a6747570cff7baa 100644 (file)
@@ -277,7 +277,7 @@ static void mmp_pdma_free_phy(struct mmp_pdma_chan *pchan)
                return;
 
        /* clear the channel mapping in DRCMR */
-       reg = DRCMR(pchan->phy->vchan->drcmr);
+       reg = DRCMR(pchan->drcmr);
        writel(0, pchan->phy->base + reg);
 
        spin_lock_irqsave(&pdev->phy_lock, flags);
@@ -858,8 +858,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
        struct mmp_pdma_chan *chan;
        int ret;
 
-       chan = devm_kzalloc(pdev->dev, sizeof(struct mmp_pdma_chan),
-                           GFP_KERNEL);
+       chan = devm_kzalloc(pdev->dev, sizeof(*chan), GFP_KERNEL);
        if (chan == NULL)
                return -ENOMEM;
 
@@ -946,8 +945,7 @@ static int mmp_pdma_probe(struct platform_device *op)
                        irq_num++;
        }
 
-       pdev->phy = devm_kcalloc(pdev->dev,
-                                dma_channels, sizeof(struct mmp_pdma_chan),
+       pdev->phy = devm_kcalloc(pdev->dev, dma_channels, sizeof(*pdev->phy),
                                 GFP_KERNEL);
        if (pdev->phy == NULL)
                return -ENOMEM;
index 448750da4402fb4b68f7c9ebd540553a21cab55e..96104f4eebe8d0d40b791bf453c0af646df23959 100644 (file)
 #define MPC_DMA_DESCRIPTORS    64
 
 /* Macro definitions */
-#define MPC_DMA_CHANNELS       64
 #define MPC_DMA_TCD_OFFSET     0x1000
 
+/*
+ * Maximum channel counts for individual hardware variants
+ * and the maximum channel count over all supported controllers,
+ * used for data structure size
+ */
+#define MPC8308_DMACHAN_MAX    16
+#define MPC512x_DMACHAN_MAX    64
+#define MPC_DMA_CHANNELS       64
+
 /* Arbitration mode of group and channel */
 #define MPC_DMA_DMACR_EDCG     (1 << 31)
 #define MPC_DMA_DMACR_ERGA     (1 << 3)
@@ -649,13 +657,15 @@ static int mpc_dma_probe(struct platform_device *op)
        mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL);
        if (!mdma) {
                dev_err(dev, "Memory exhausted!\n");
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto err;
        }
 
        mdma->irq = irq_of_parse_and_map(dn, 0);
        if (mdma->irq == NO_IRQ) {
                dev_err(dev, "Error mapping IRQ!\n");
-               return -EINVAL;
+               retval = -EINVAL;
+               goto err;
        }
 
        if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) {
@@ -663,14 +673,15 @@ static int mpc_dma_probe(struct platform_device *op)
                mdma->irq2 = irq_of_parse_and_map(dn, 1);
                if (mdma->irq2 == NO_IRQ) {
                        dev_err(dev, "Error mapping IRQ!\n");
-                       return -EINVAL;
+                       retval = -EINVAL;
+                       goto err_dispose1;
                }
        }
 
        retval = of_address_to_resource(dn, 0, &res);
        if (retval) {
                dev_err(dev, "Error parsing memory region!\n");
-               return retval;
+               goto err_dispose2;
        }
 
        regs_start = res.start;
@@ -678,31 +689,34 @@ static int mpc_dma_probe(struct platform_device *op)
 
        if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) {
                dev_err(dev, "Error requesting memory region!\n");
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_dispose2;
        }
 
        mdma->regs = devm_ioremap(dev, regs_start, regs_size);
        if (!mdma->regs) {
                dev_err(dev, "Error mapping memory region!\n");
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto err_dispose2;
        }
 
        mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
                                                        + MPC_DMA_TCD_OFFSET);
 
-       retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME,
-                                                                       mdma);
+       retval = request_irq(mdma->irq, &mpc_dma_irq, 0, DRV_NAME, mdma);
        if (retval) {
                dev_err(dev, "Error requesting IRQ!\n");
-               return -EINVAL;
+               retval = -EINVAL;
+               goto err_dispose2;
        }
 
        if (mdma->is_mpc8308) {
-               retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0,
-                               DRV_NAME, mdma);
+               retval = request_irq(mdma->irq2, &mpc_dma_irq, 0,
+                                                       DRV_NAME, mdma);
                if (retval) {
                        dev_err(dev, "Error requesting IRQ2!\n");
-                       return -EINVAL;
+                       retval = -EINVAL;
+                       goto err_free1;
                }
        }
 
@@ -710,10 +724,10 @@ static int mpc_dma_probe(struct platform_device *op)
 
        dma = &mdma->dma;
        dma->dev = dev;
-       if (!mdma->is_mpc8308)
-               dma->chancnt = MPC_DMA_CHANNELS;
+       if (mdma->is_mpc8308)
+               dma->chancnt = MPC8308_DMACHAN_MAX;
        else
-               dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */
+               dma->chancnt = MPC512x_DMACHAN_MAX;
        dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
        dma->device_free_chan_resources = mpc_dma_free_chan_resources;
        dma->device_issue_pending = mpc_dma_issue_pending;
@@ -747,7 +761,19 @@ static int mpc_dma_probe(struct platform_device *op)
         * - Round-robin group arbitration,
         * - Round-robin channel arbitration.
         */
-       if (!mdma->is_mpc8308) {
+       if (mdma->is_mpc8308) {
+               /* MPC8308 has 16 channels and lacks some registers */
+               out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
+
+               /* enable snooping */
+               out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
+               /* Disable error interrupts */
+               out_be32(&mdma->regs->dmaeeil, 0);
+
+               /* Clear interrupts status */
+               out_be32(&mdma->regs->dmaintl, 0xFFFF);
+               out_be32(&mdma->regs->dmaerrl, 0xFFFF);
+       } else {
                out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
                                        MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
 
@@ -768,29 +794,28 @@ static int mpc_dma_probe(struct platform_device *op)
                /* Route interrupts to IPIC */
                out_be32(&mdma->regs->dmaihsa, 0);
                out_be32(&mdma->regs->dmailsa, 0);
-       } else {
-               /* MPC8308 has 16 channels and lacks some registers */
-               out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
-
-               /* enable snooping */
-               out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
-               /* Disable error interrupts */
-               out_be32(&mdma->regs->dmaeeil, 0);
-
-               /* Clear interrupts status */
-               out_be32(&mdma->regs->dmaintl, 0xFFFF);
-               out_be32(&mdma->regs->dmaerrl, 0xFFFF);
        }
 
        /* Register DMA engine */
        dev_set_drvdata(dev, mdma);
        retval = dma_async_device_register(dma);
-       if (retval) {
-               devm_free_irq(dev, mdma->irq, mdma);
-               irq_dispose_mapping(mdma->irq);
-       }
+       if (retval)
+               goto err_free2;
 
        return retval;
+
+err_free2:
+       if (mdma->is_mpc8308)
+               free_irq(mdma->irq2, mdma);
+err_free1:
+       free_irq(mdma->irq, mdma);
+err_dispose2:
+       if (mdma->is_mpc8308)
+               irq_dispose_mapping(mdma->irq2);
+err_dispose1:
+       irq_dispose_mapping(mdma->irq);
+err:
+       return retval;
 }
 
 static int mpc_dma_remove(struct platform_device *op)
@@ -799,7 +824,11 @@ static int mpc_dma_remove(struct platform_device *op)
        struct mpc_dma *mdma = dev_get_drvdata(dev);
 
        dma_async_device_unregister(&mdma->dma);
-       devm_free_irq(dev, mdma->irq, mdma);
+       if (mdma->is_mpc8308) {
+               free_irq(mdma->irq2, mdma);
+               irq_dispose_mapping(mdma->irq2);
+       }
+       free_irq(mdma->irq, mdma);
        irq_dispose_mapping(mdma->irq);
 
        return 0;
@@ -807,6 +836,7 @@ static int mpc_dma_remove(struct platform_device *op)
 
 static struct of_device_id mpc_dma_match[] = {
        { .compatible = "fsl,mpc5121-dma", },
+       { .compatible = "fsl,mpc8308-dma", },
        {},
 };
 
index 766b68ed505c4d2b3964bfb1f0de6ab5ae1ff3a9..7938272f2edf4faf63518874153298a707e03098 100644 (file)
@@ -191,12 +191,10 @@ static void mv_set_mode(struct mv_xor_chan *chan,
 
 static void mv_chan_activate(struct mv_xor_chan *chan)
 {
-       u32 activation;
-
        dev_dbg(mv_chan_to_devp(chan), " activate chan.\n");
-       activation = readl_relaxed(XOR_ACTIVATION(chan));
-       activation |= 0x1;
-       writel_relaxed(activation, XOR_ACTIVATION(chan));
+
+       /* writel ensures all descriptors are flushed before activation */
+       writel(BIT(0), XOR_ACTIVATION(chan));
 }
 
 static char mv_chan_is_busy(struct mv_xor_chan *chan)
@@ -312,7 +310,8 @@ mv_xor_clean_slot(struct mv_xor_desc_slot *desc,
        return 0;
 }
 
-static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
+/* This function must be called with the mv_xor_chan spinlock held */
+static void mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
 {
        struct mv_xor_desc_slot *iter, *_iter;
        dma_cookie_t cookie = 0;
@@ -368,18 +367,13 @@ static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
                mv_chan->dmachan.completed_cookie = cookie;
 }
 
-static void
-mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
-{
-       spin_lock_bh(&mv_chan->lock);
-       __mv_xor_slot_cleanup(mv_chan);
-       spin_unlock_bh(&mv_chan->lock);
-}
-
 static void mv_xor_tasklet(unsigned long data)
 {
        struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
+
+       spin_lock_bh(&chan->lock);
        mv_xor_slot_cleanup(chan);
+       spin_unlock_bh(&chan->lock);
 }
 
 static struct mv_xor_desc_slot *
@@ -658,9 +652,10 @@ static void mv_xor_free_chan_resources(struct dma_chan *chan)
        struct mv_xor_desc_slot *iter, *_iter;
        int in_use_descs = 0;
 
+       spin_lock_bh(&mv_chan->lock);
+
        mv_xor_slot_cleanup(mv_chan);
 
-       spin_lock_bh(&mv_chan->lock);
        list_for_each_entry_safe(iter, _iter, &mv_chan->chain,
                                        chain_node) {
                in_use_descs++;
@@ -702,11 +697,12 @@ static enum dma_status mv_xor_status(struct dma_chan *chan,
        enum dma_status ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret == DMA_COMPLETE) {
-               mv_xor_clean_completed_slots(mv_chan);
+       if (ret == DMA_COMPLETE)
                return ret;
-       }
+
+       spin_lock_bh(&mv_chan->lock);
        mv_xor_slot_cleanup(mv_chan);
+       spin_unlock_bh(&mv_chan->lock);
 
        return dma_cookie_status(chan, cookie, txstate);
 }
@@ -784,7 +780,7 @@ static void mv_xor_issue_pending(struct dma_chan *chan)
 
 static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan)
 {
-       int i;
+       int i, ret;
        void *src, *dest;
        dma_addr_t src_dma, dest_dma;
        struct dma_chan *dma_chan;
@@ -821,19 +817,44 @@ static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan)
 
        src_dma = dma_map_page(dma_chan->device->dev, virt_to_page(src), 0,
                                 PAGE_SIZE, DMA_TO_DEVICE);
-       unmap->to_cnt = 1;
        unmap->addr[0] = src_dma;
 
+       ret = dma_mapping_error(dma_chan->device->dev, src_dma);
+       if (ret) {
+               err = -ENOMEM;
+               goto free_resources;
+       }
+       unmap->to_cnt = 1;
+
        dest_dma = dma_map_page(dma_chan->device->dev, virt_to_page(dest), 0,
                                  PAGE_SIZE, DMA_FROM_DEVICE);
-       unmap->from_cnt = 1;
        unmap->addr[1] = dest_dma;
 
+       ret = dma_mapping_error(dma_chan->device->dev, dest_dma);
+       if (ret) {
+               err = -ENOMEM;
+               goto free_resources;
+       }
+       unmap->from_cnt = 1;
        unmap->len = PAGE_SIZE;
 
        tx = mv_xor_prep_dma_memcpy(dma_chan, dest_dma, src_dma,
                                    PAGE_SIZE, 0);
+       if (!tx) {
+               dev_err(dma_chan->device->dev,
+                       "Self-test cannot prepare operation, disabling\n");
+               err = -ENODEV;
+               goto free_resources;
+       }
+
        cookie = mv_xor_tx_submit(tx);
+       if (dma_submit_error(cookie)) {
+               dev_err(dma_chan->device->dev,
+                       "Self-test submit error, disabling\n");
+               err = -ENODEV;
+               goto free_resources;
+       }
+
        mv_xor_issue_pending(dma_chan);
        async_tx_ack(tx);
        msleep(1);
@@ -868,7 +889,7 @@ out:
 static int
 mv_xor_xor_self_test(struct mv_xor_chan *mv_chan)
 {
-       int i, src_idx;
+       int i, src_idx, ret;
        struct page *dest;
        struct page *xor_srcs[MV_XOR_NUM_SRC_TEST];
        dma_addr_t dma_srcs[MV_XOR_NUM_SRC_TEST];
@@ -931,19 +952,42 @@ mv_xor_xor_self_test(struct mv_xor_chan *mv_chan)
                unmap->addr[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i],
                                              0, PAGE_SIZE, DMA_TO_DEVICE);
                dma_srcs[i] = unmap->addr[i];
+               ret = dma_mapping_error(dma_chan->device->dev, unmap->addr[i]);
+               if (ret) {
+                       err = -ENOMEM;
+                       goto free_resources;
+               }
                unmap->to_cnt++;
        }
 
        unmap->addr[src_count] = dma_map_page(dma_chan->device->dev, dest, 0, PAGE_SIZE,
                                      DMA_FROM_DEVICE);
        dest_dma = unmap->addr[src_count];
+       ret = dma_mapping_error(dma_chan->device->dev, unmap->addr[src_count]);
+       if (ret) {
+               err = -ENOMEM;
+               goto free_resources;
+       }
        unmap->from_cnt = 1;
        unmap->len = PAGE_SIZE;
 
        tx = mv_xor_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
                                 src_count, PAGE_SIZE, 0);
+       if (!tx) {
+               dev_err(dma_chan->device->dev,
+                       "Self-test cannot prepare operation, disabling\n");
+               err = -ENODEV;
+               goto free_resources;
+       }
 
        cookie = mv_xor_tx_submit(tx);
+       if (dma_submit_error(cookie)) {
+               dev_err(dma_chan->device->dev,
+                       "Self-test submit error, disabling\n");
+               err = -ENODEV;
+               goto free_resources;
+       }
+
        mv_xor_issue_pending(dma_chan);
        async_tx_ack(tx);
        msleep(8);
index 52396771acbe53951c3d080660621355b6500e3d..974794cdb6ed6e60699e7e5039f759c1b993aedf 100644 (file)
@@ -73,8 +73,7 @@ static void shdma_chan_xfer_ld_queue(struct shdma_chan *schan)
 static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
        struct shdma_desc *chunk, *c, *desc =
-               container_of(tx, struct shdma_desc, async_tx),
-               *last = desc;
+               container_of(tx, struct shdma_desc, async_tx);
        struct shdma_chan *schan = to_shdma_chan(tx->chan);
        dma_async_tx_callback callback = tx->callback;
        dma_cookie_t cookie;
@@ -98,19 +97,20 @@ static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx)
                                      &chunk->node == &schan->ld_free))
                        break;
                chunk->mark = DESC_SUBMITTED;
-               /* Callback goes to the last chunk */
-               chunk->async_tx.callback = NULL;
+               if (chunk->chunks == 1) {
+                       chunk->async_tx.callback = callback;
+                       chunk->async_tx.callback_param = tx->callback_param;
+               } else {
+                       /* Callback goes to the last chunk */
+                       chunk->async_tx.callback = NULL;
+               }
                chunk->cookie = cookie;
                list_move_tail(&chunk->node, &schan->ld_queue);
-               last = chunk;
 
                dev_dbg(schan->dev, "submit #%d@%p on %d\n",
-                       tx->cookie, &last->async_tx, schan->id);
+                       tx->cookie, &chunk->async_tx, schan->id);
        }
 
-       last->async_tx.callback = callback;
-       last->async_tx.callback_param = tx->callback_param;
-
        if (power_up) {
                int ret;
                schan->pm_state = SHDMA_PM_BUSY;
@@ -304,6 +304,7 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
        dma_async_tx_callback callback = NULL;
        void *param = NULL;
        unsigned long flags;
+       LIST_HEAD(cyclic_list);
 
        spin_lock_irqsave(&schan->chan_lock, flags);
        list_for_each_entry_safe(desc, _desc, &schan->ld_queue, node) {
@@ -369,10 +370,16 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
                if (((desc->mark == DESC_COMPLETED ||
                      desc->mark == DESC_WAITING) &&
                     async_tx_test_ack(&desc->async_tx)) || all) {
-                       /* Remove from ld_queue list */
-                       desc->mark = DESC_IDLE;
 
-                       list_move(&desc->node, &schan->ld_free);
+                       if (all || !desc->cyclic) {
+                               /* Remove from ld_queue list */
+                               desc->mark = DESC_IDLE;
+                               list_move(&desc->node, &schan->ld_free);
+                       } else {
+                               /* reuse as cyclic */
+                               desc->mark = DESC_SUBMITTED;
+                               list_move_tail(&desc->node, &cyclic_list);
+                       }
 
                        if (list_empty(&schan->ld_queue)) {
                                dev_dbg(schan->dev, "Bring down channel %d\n", schan->id);
@@ -389,6 +396,8 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
                 */
                schan->dma_chan.completed_cookie = schan->dma_chan.cookie;
 
+       list_splice_tail(&cyclic_list, &schan->ld_queue);
+
        spin_unlock_irqrestore(&schan->chan_lock, flags);
 
        if (callback)
@@ -521,7 +530,7 @@ static struct shdma_desc *shdma_add_desc(struct shdma_chan *schan,
  */
 static struct dma_async_tx_descriptor *shdma_prep_sg(struct shdma_chan *schan,
        struct scatterlist *sgl, unsigned int sg_len, dma_addr_t *addr,
-       enum dma_transfer_direction direction, unsigned long flags)
+       enum dma_transfer_direction direction, unsigned long flags, bool cyclic)
 {
        struct scatterlist *sg;
        struct shdma_desc *first = NULL, *new = NULL /* compiler... */;
@@ -569,7 +578,11 @@ static struct dma_async_tx_descriptor *shdma_prep_sg(struct shdma_chan *schan,
                        if (!new)
                                goto err_get_desc;
 
-                       new->chunks = chunks--;
+                       new->cyclic = cyclic;
+                       if (cyclic)
+                               new->chunks = 1;
+                       else
+                               new->chunks = chunks--;
                        list_add_tail(&new->node, &tx_list);
                } while (len);
        }
@@ -612,7 +625,8 @@ static struct dma_async_tx_descriptor *shdma_prep_memcpy(
        sg_dma_address(&sg) = dma_src;
        sg_dma_len(&sg) = len;
 
-       return shdma_prep_sg(schan, &sg, 1, &dma_dest, DMA_MEM_TO_MEM, flags);
+       return shdma_prep_sg(schan, &sg, 1, &dma_dest, DMA_MEM_TO_MEM,
+                            flags, false);
 }
 
 static struct dma_async_tx_descriptor *shdma_prep_slave_sg(
@@ -640,7 +654,50 @@ static struct dma_async_tx_descriptor *shdma_prep_slave_sg(
        slave_addr = ops->slave_addr(schan);
 
        return shdma_prep_sg(schan, sgl, sg_len, &slave_addr,
-                             direction, flags);
+                            direction, flags, false);
+}
+
+struct dma_async_tx_descriptor *shdma_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 shdma_chan *schan = to_shdma_chan(chan);
+       struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
+       const struct shdma_ops *ops = sdev->ops;
+       unsigned int sg_len = buf_len / period_len;
+       int slave_id = schan->slave_id;
+       dma_addr_t slave_addr;
+       struct scatterlist sgl[sg_len];
+       int i;
+
+       if (!chan)
+               return NULL;
+
+       BUG_ON(!schan->desc_num);
+
+       /* Someone calling slave DMA on a generic channel? */
+       if (slave_id < 0 || (buf_len < period_len)) {
+               dev_warn(schan->dev,
+                       "%s: bad parameter: buf_len=%d, period_len=%d, id=%d\n",
+                       __func__, buf_len, period_len, slave_id);
+               return NULL;
+       }
+
+       slave_addr = ops->slave_addr(schan);
+
+       sg_init_table(sgl, sg_len);
+       for (i = 0; i < sg_len; i++) {
+               dma_addr_t src = buf_addr + (period_len * i);
+
+               sg_set_page(&sgl[i], pfn_to_page(PFN_DOWN(src)), period_len,
+                           offset_in_page(src));
+               sg_dma_address(&sgl[i]) = src;
+               sg_dma_len(&sgl[i]) = period_len;
+       }
+
+       return shdma_prep_sg(schan, sgl, sg_len, &slave_addr,
+                            direction, flags, true);
 }
 
 static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -915,6 +972,7 @@ int shdma_init(struct device *dev, struct shdma_dev *sdev,
 
        /* Compulsory for DMA_SLAVE fields */
        dma_dev->device_prep_slave_sg = shdma_prep_slave_sg;
+       dma_dev->device_prep_dma_cyclic = shdma_prep_dma_cyclic;
        dma_dev->device_control = shdma_control;
 
        dma_dev->dev = dev;
diff --git a/drivers/dma/xilinx/Makefile b/drivers/dma/xilinx/Makefile
new file mode 100644 (file)
index 0000000..3c4e9f2
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
new file mode 100644 (file)
index 0000000..42a13e8
--- /dev/null
@@ -0,0 +1,1379 @@
+/*
+ * DMA driver for Xilinx Video DMA Engine
+ *
+ * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
+ *
+ * Based on the Freescale DMA driver.
+ *
+ * Description:
+ * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
+ * core that provides high-bandwidth direct memory access between memory
+ * and AXI4-Stream type video target peripherals. The core provides efficient
+ * two dimensional DMA operations with independent asynchronous read (S2MM)
+ * and write (MM2S) channel operation. It can be configured to have either
+ * one channel or two channels. If configured as two channels, one is to
+ * transmit to the video device (MM2S) and another is to receive from the
+ * video device (S2MM). Initialization, status, interrupt and management
+ * registers are accessed through an AXI4-Lite slave interface.
+ *
+ * This program is free software: 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/amba/xilinx_dma.h>
+#include <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+#include "../dmaengine.h"
+
+/* Register/Descriptor Offsets */
+#define XILINX_VDMA_MM2S_CTRL_OFFSET           0x0000
+#define XILINX_VDMA_S2MM_CTRL_OFFSET           0x0030
+#define XILINX_VDMA_MM2S_DESC_OFFSET           0x0050
+#define XILINX_VDMA_S2MM_DESC_OFFSET           0x00a0
+
+/* Control Registers */
+#define XILINX_VDMA_REG_DMACR                  0x0000
+#define XILINX_VDMA_DMACR_DELAY_MAX            0xff
+#define XILINX_VDMA_DMACR_DELAY_SHIFT          24
+#define XILINX_VDMA_DMACR_FRAME_COUNT_MAX      0xff
+#define XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT    16
+#define XILINX_VDMA_DMACR_ERR_IRQ              BIT(14)
+#define XILINX_VDMA_DMACR_DLY_CNT_IRQ          BIT(13)
+#define XILINX_VDMA_DMACR_FRM_CNT_IRQ          BIT(12)
+#define XILINX_VDMA_DMACR_MASTER_SHIFT         8
+#define XILINX_VDMA_DMACR_FSYNCSRC_SHIFT       5
+#define XILINX_VDMA_DMACR_FRAMECNT_EN          BIT(4)
+#define XILINX_VDMA_DMACR_GENLOCK_EN           BIT(3)
+#define XILINX_VDMA_DMACR_RESET                        BIT(2)
+#define XILINX_VDMA_DMACR_CIRC_EN              BIT(1)
+#define XILINX_VDMA_DMACR_RUNSTOP              BIT(0)
+#define XILINX_VDMA_DMACR_FSYNCSRC_MASK                GENMASK(6, 5)
+
+#define XILINX_VDMA_REG_DMASR                  0x0004
+#define XILINX_VDMA_DMASR_EOL_LATE_ERR         BIT(15)
+#define XILINX_VDMA_DMASR_ERR_IRQ              BIT(14)
+#define XILINX_VDMA_DMASR_DLY_CNT_IRQ          BIT(13)
+#define XILINX_VDMA_DMASR_FRM_CNT_IRQ          BIT(12)
+#define XILINX_VDMA_DMASR_SOF_LATE_ERR         BIT(11)
+#define XILINX_VDMA_DMASR_SG_DEC_ERR           BIT(10)
+#define XILINX_VDMA_DMASR_SG_SLV_ERR           BIT(9)
+#define XILINX_VDMA_DMASR_EOF_EARLY_ERR                BIT(8)
+#define XILINX_VDMA_DMASR_SOF_EARLY_ERR                BIT(7)
+#define XILINX_VDMA_DMASR_DMA_DEC_ERR          BIT(6)
+#define XILINX_VDMA_DMASR_DMA_SLAVE_ERR                BIT(5)
+#define XILINX_VDMA_DMASR_DMA_INT_ERR          BIT(4)
+#define XILINX_VDMA_DMASR_IDLE                 BIT(1)
+#define XILINX_VDMA_DMASR_HALTED               BIT(0)
+#define XILINX_VDMA_DMASR_DELAY_MASK           GENMASK(31, 24)
+#define XILINX_VDMA_DMASR_FRAME_COUNT_MASK     GENMASK(23, 16)
+
+#define XILINX_VDMA_REG_CURDESC                        0x0008
+#define XILINX_VDMA_REG_TAILDESC               0x0010
+#define XILINX_VDMA_REG_REG_INDEX              0x0014
+#define XILINX_VDMA_REG_FRMSTORE               0x0018
+#define XILINX_VDMA_REG_THRESHOLD              0x001c
+#define XILINX_VDMA_REG_FRMPTR_STS             0x0024
+#define XILINX_VDMA_REG_PARK_PTR               0x0028
+#define XILINX_VDMA_PARK_PTR_WR_REF_SHIFT      8
+#define XILINX_VDMA_PARK_PTR_RD_REF_SHIFT      0
+#define XILINX_VDMA_REG_VDMA_VERSION           0x002c
+
+/* Register Direct Mode Registers */
+#define XILINX_VDMA_REG_VSIZE                  0x0000
+#define XILINX_VDMA_REG_HSIZE                  0x0004
+
+#define XILINX_VDMA_REG_FRMDLY_STRIDE          0x0008
+#define XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT 24
+#define XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT 0
+
+#define XILINX_VDMA_REG_START_ADDRESS(n)       (0x000c + 4 * (n))
+
+/* HW specific definitions */
+#define XILINX_VDMA_MAX_CHANS_PER_DEVICE       0x2
+
+#define XILINX_VDMA_DMAXR_ALL_IRQ_MASK \
+               (XILINX_VDMA_DMASR_FRM_CNT_IRQ | \
+                XILINX_VDMA_DMASR_DLY_CNT_IRQ | \
+                XILINX_VDMA_DMASR_ERR_IRQ)
+
+#define XILINX_VDMA_DMASR_ALL_ERR_MASK \
+               (XILINX_VDMA_DMASR_EOL_LATE_ERR | \
+                XILINX_VDMA_DMASR_SOF_LATE_ERR | \
+                XILINX_VDMA_DMASR_SG_DEC_ERR | \
+                XILINX_VDMA_DMASR_SG_SLV_ERR | \
+                XILINX_VDMA_DMASR_EOF_EARLY_ERR | \
+                XILINX_VDMA_DMASR_SOF_EARLY_ERR | \
+                XILINX_VDMA_DMASR_DMA_DEC_ERR | \
+                XILINX_VDMA_DMASR_DMA_SLAVE_ERR | \
+                XILINX_VDMA_DMASR_DMA_INT_ERR)
+
+/*
+ * Recoverable errors are DMA Internal error, SOF Early, EOF Early
+ * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
+ * is enabled in the h/w system.
+ */
+#define XILINX_VDMA_DMASR_ERR_RECOVER_MASK     \
+               (XILINX_VDMA_DMASR_SOF_LATE_ERR | \
+                XILINX_VDMA_DMASR_EOF_EARLY_ERR | \
+                XILINX_VDMA_DMASR_SOF_EARLY_ERR | \
+                XILINX_VDMA_DMASR_DMA_INT_ERR)
+
+/* Axi VDMA Flush on Fsync bits */
+#define XILINX_VDMA_FLUSH_S2MM         3
+#define XILINX_VDMA_FLUSH_MM2S         2
+#define XILINX_VDMA_FLUSH_BOTH         1
+
+/* Delay loop counter to prevent hardware failure */
+#define XILINX_VDMA_LOOP_COUNT         1000000
+
+/**
+ * struct xilinx_vdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @pad1: Reserved @0x04
+ * @buf_addr: Buffer address @0x08
+ * @pad2: Reserved @0x0C
+ * @vsize: Vertical Size @0x10
+ * @hsize: Horizontal Size @0x14
+ * @stride: Number of bytes between the first
+ *         pixels of each horizontal line @0x18
+ */
+struct xilinx_vdma_desc_hw {
+       u32 next_desc;
+       u32 pad1;
+       u32 buf_addr;
+       u32 pad2;
+       u32 vsize;
+       u32 hsize;
+       u32 stride;
+} __aligned(64);
+
+/**
+ * struct xilinx_vdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_vdma_tx_segment {
+       struct xilinx_vdma_desc_hw hw;
+       struct list_head node;
+       dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_vdma_tx_descriptor - Per Transaction structure
+ * @async_tx: Async transaction descriptor
+ * @segments: TX segments list
+ * @node: Node in the channel descriptors list
+ */
+struct xilinx_vdma_tx_descriptor {
+       struct dma_async_tx_descriptor async_tx;
+       struct list_head segments;
+       struct list_head node;
+};
+
+/**
+ * struct xilinx_vdma_chan - Driver specific VDMA channel structure
+ * @xdev: Driver specific device structure
+ * @ctrl_offset: Control registers offset
+ * @desc_offset: TX descriptor registers offset
+ * @lock: Descriptor operation lock
+ * @pending_list: Descriptors waiting
+ * @active_desc: Active descriptor
+ * @allocated_desc: Allocated descriptor
+ * @done_list: Complete descriptors
+ * @common: DMA common channel
+ * @desc_pool: Descriptors pool
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @id: Channel ID
+ * @direction: Transfer direction
+ * @num_frms: Number of frames
+ * @has_sg: Support scatter transfers
+ * @genlock: Support genlock mode
+ * @err: Channel has errors
+ * @tasklet: Cleanup work after irq
+ * @config: Device configuration info
+ * @flush_on_fsync: Flush on Frame sync
+ */
+struct xilinx_vdma_chan {
+       struct xilinx_vdma_device *xdev;
+       u32 ctrl_offset;
+       u32 desc_offset;
+       spinlock_t lock;
+       struct list_head pending_list;
+       struct xilinx_vdma_tx_descriptor *active_desc;
+       struct xilinx_vdma_tx_descriptor *allocated_desc;
+       struct list_head done_list;
+       struct dma_chan common;
+       struct dma_pool *desc_pool;
+       struct device *dev;
+       int irq;
+       int id;
+       enum dma_transfer_direction direction;
+       int num_frms;
+       bool has_sg;
+       bool genlock;
+       bool err;
+       struct tasklet_struct tasklet;
+       struct xilinx_vdma_config config;
+       bool flush_on_fsync;
+};
+
+/**
+ * struct xilinx_vdma_device - VDMA device structure
+ * @regs: I/O mapped base address
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific VDMA channel
+ * @has_sg: Specifies whether Scatter-Gather is present or not
+ * @flush_on_fsync: Flush on frame sync
+ */
+struct xilinx_vdma_device {
+       void __iomem *regs;
+       struct device *dev;
+       struct dma_device common;
+       struct xilinx_vdma_chan *chan[XILINX_VDMA_MAX_CHANS_PER_DEVICE];
+       bool has_sg;
+       u32 flush_on_fsync;
+};
+
+/* Macros */
+#define to_xilinx_chan(chan) \
+       container_of(chan, struct xilinx_vdma_chan, common)
+#define to_vdma_tx_descriptor(tx) \
+       container_of(tx, struct xilinx_vdma_tx_descriptor, async_tx)
+
+/* IO accessors */
+static inline u32 vdma_read(struct xilinx_vdma_chan *chan, u32 reg)
+{
+       return ioread32(chan->xdev->regs + reg);
+}
+
+static inline void vdma_write(struct xilinx_vdma_chan *chan, u32 reg, u32 value)
+{
+       iowrite32(value, chan->xdev->regs + reg);
+}
+
+static inline void vdma_desc_write(struct xilinx_vdma_chan *chan, u32 reg,
+                                  u32 value)
+{
+       vdma_write(chan, chan->desc_offset + reg, value);
+}
+
+static inline u32 vdma_ctrl_read(struct xilinx_vdma_chan *chan, u32 reg)
+{
+       return vdma_read(chan, chan->ctrl_offset + reg);
+}
+
+static inline void vdma_ctrl_write(struct xilinx_vdma_chan *chan, u32 reg,
+                                  u32 value)
+{
+       vdma_write(chan, chan->ctrl_offset + reg, value);
+}
+
+static inline void vdma_ctrl_clr(struct xilinx_vdma_chan *chan, u32 reg,
+                                u32 clr)
+{
+       vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) & ~clr);
+}
+
+static inline void vdma_ctrl_set(struct xilinx_vdma_chan *chan, u32 reg,
+                                u32 set)
+{
+       vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) | set);
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors and segments alloc and free
+ */
+
+/**
+ * xilinx_vdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_vdma_tx_segment *
+xilinx_vdma_alloc_tx_segment(struct xilinx_vdma_chan *chan)
+{
+       struct xilinx_vdma_tx_segment *segment;
+       dma_addr_t phys;
+
+       segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
+       if (!segment)
+               return NULL;
+
+       memset(segment, 0, sizeof(*segment));
+       segment->phys = phys;
+
+       return segment;
+}
+
+/**
+ * xilinx_vdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific VDMA channel
+ * @segment: VDMA transaction segment
+ */
+static void xilinx_vdma_free_tx_segment(struct xilinx_vdma_chan *chan,
+                                       struct xilinx_vdma_tx_segment *segment)
+{
+       dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_vdma_tx_descriptor - Allocate transaction descriptor
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: The allocated descriptor on success and NULL on failure.
+ */
+static struct xilinx_vdma_tx_descriptor *
+xilinx_vdma_alloc_tx_descriptor(struct xilinx_vdma_chan *chan)
+{
+       struct xilinx_vdma_tx_descriptor *desc;
+       unsigned long flags;
+
+       if (chan->allocated_desc)
+               return chan->allocated_desc;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return NULL;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       chan->allocated_desc = desc;
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       INIT_LIST_HEAD(&desc->segments);
+
+       return desc;
+}
+
+/**
+ * xilinx_vdma_free_tx_descriptor - Free transaction descriptor
+ * @chan: Driver specific VDMA channel
+ * @desc: VDMA transaction descriptor
+ */
+static void
+xilinx_vdma_free_tx_descriptor(struct xilinx_vdma_chan *chan,
+                              struct xilinx_vdma_tx_descriptor *desc)
+{
+       struct xilinx_vdma_tx_segment *segment, *next;
+
+       if (!desc)
+               return;
+
+       list_for_each_entry_safe(segment, next, &desc->segments, node) {
+               list_del(&segment->node);
+               xilinx_vdma_free_tx_segment(chan, segment);
+       }
+
+       kfree(desc);
+}
+
+/* Required functions */
+
+/**
+ * xilinx_vdma_free_desc_list - Free descriptors list
+ * @chan: Driver specific VDMA channel
+ * @list: List to parse and delete the descriptor
+ */
+static void xilinx_vdma_free_desc_list(struct xilinx_vdma_chan *chan,
+                                       struct list_head *list)
+{
+       struct xilinx_vdma_tx_descriptor *desc, *next;
+
+       list_for_each_entry_safe(desc, next, list, node) {
+               list_del(&desc->node);
+               xilinx_vdma_free_tx_descriptor(chan, desc);
+       }
+}
+
+/**
+ * xilinx_vdma_free_descriptors - Free channel descriptors
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_free_descriptors(struct xilinx_vdma_chan *chan)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       xilinx_vdma_free_desc_list(chan, &chan->pending_list);
+       xilinx_vdma_free_desc_list(chan, &chan->done_list);
+
+       xilinx_vdma_free_tx_descriptor(chan, chan->active_desc);
+       chan->active_desc = NULL;
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel
+ */
+static void xilinx_vdma_free_chan_resources(struct dma_chan *dchan)
+{
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+       dev_dbg(chan->dev, "Free all channel resources.\n");
+
+       xilinx_vdma_free_descriptors(chan);
+       dma_pool_destroy(chan->desc_pool);
+       chan->desc_pool = NULL;
+}
+
+/**
+ * xilinx_vdma_chan_desc_cleanup - Clean channel descriptors
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_chan_desc_cleanup(struct xilinx_vdma_chan *chan)
+{
+       struct xilinx_vdma_tx_descriptor *desc, *next;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+               dma_async_tx_callback callback;
+               void *callback_param;
+
+               /* Remove from the list of running transactions */
+               list_del(&desc->node);
+
+               /* Run the link descriptor callback function */
+               callback = desc->async_tx.callback;
+               callback_param = desc->async_tx.callback_param;
+               if (callback) {
+                       spin_unlock_irqrestore(&chan->lock, flags);
+                       callback(callback_param);
+                       spin_lock_irqsave(&chan->lock, flags);
+               }
+
+               /* Run any dependencies, then free the descriptor */
+               dma_run_dependencies(&desc->async_tx);
+               xilinx_vdma_free_tx_descriptor(chan, desc);
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the Xilinx VDMA channel structure
+ */
+static void xilinx_vdma_do_tasklet(unsigned long data)
+{
+       struct xilinx_vdma_chan *chan = (struct xilinx_vdma_chan *)data;
+
+       xilinx_vdma_chan_desc_cleanup(chan);
+}
+
+/**
+ * xilinx_vdma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+       /* Has this channel already been allocated? */
+       if (chan->desc_pool)
+               return 0;
+
+       /*
+        * We need the descriptor to be aligned to 64bytes
+        * for meeting Xilinx VDMA specification requirement.
+        */
+       chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool",
+                               chan->dev,
+                               sizeof(struct xilinx_vdma_tx_segment),
+                               __alignof__(struct xilinx_vdma_tx_segment), 0);
+       if (!chan->desc_pool) {
+               dev_err(chan->dev,
+                       "unable to allocate channel %d descriptor pool\n",
+                       chan->id);
+               return -ENOMEM;
+       }
+
+       dma_cookie_init(dchan);
+       return 0;
+}
+
+/**
+ * xilinx_vdma_tx_status - Get VDMA transaction status
+ * @dchan: DMA channel
+ * @cookie: Transaction identifier
+ * @txstate: Transaction state
+ *
+ * Return: DMA transaction status
+ */
+static enum dma_status xilinx_vdma_tx_status(struct dma_chan *dchan,
+                                       dma_cookie_t cookie,
+                                       struct dma_tx_state *txstate)
+{
+       return dma_cookie_status(dchan, cookie, txstate);
+}
+
+/**
+ * xilinx_vdma_is_running - Check if VDMA channel is running
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '1' if running, '0' if not.
+ */
+static bool xilinx_vdma_is_running(struct xilinx_vdma_chan *chan)
+{
+       return !(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+                XILINX_VDMA_DMASR_HALTED) &&
+               (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
+                XILINX_VDMA_DMACR_RUNSTOP);
+}
+
+/**
+ * xilinx_vdma_is_idle - Check if VDMA channel is idle
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '1' if idle, '0' if not.
+ */
+static bool xilinx_vdma_is_idle(struct xilinx_vdma_chan *chan)
+{
+       return vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+               XILINX_VDMA_DMASR_IDLE;
+}
+
+/**
+ * xilinx_vdma_halt - Halt VDMA channel
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_halt(struct xilinx_vdma_chan *chan)
+{
+       int loop = XILINX_VDMA_LOOP_COUNT;
+
+       vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP);
+
+       /* Wait for the hardware to halt */
+       do {
+               if (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+                   XILINX_VDMA_DMASR_HALTED)
+                       break;
+       } while (loop--);
+
+       if (!loop) {
+               dev_err(chan->dev, "Cannot stop channel %p: %x\n",
+                       chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
+               chan->err = true;
+       }
+
+       return;
+}
+
+/**
+ * xilinx_vdma_start - Start VDMA channel
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_start(struct xilinx_vdma_chan *chan)
+{
+       int loop = XILINX_VDMA_LOOP_COUNT;
+
+       vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP);
+
+       /* Wait for the hardware to start */
+       do {
+               if (!(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) &
+                     XILINX_VDMA_DMASR_HALTED))
+                       break;
+       } while (loop--);
+
+       if (!loop) {
+               dev_err(chan->dev, "Cannot start channel %p: %x\n",
+                       chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
+
+               chan->err = true;
+       }
+
+       return;
+}
+
+/**
+ * xilinx_vdma_start_transfer - Starts VDMA transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
+{
+       struct xilinx_vdma_config *config = &chan->config;
+       struct xilinx_vdma_tx_descriptor *desc;
+       unsigned long flags;
+       u32 reg;
+       struct xilinx_vdma_tx_segment *head, *tail = NULL;
+
+       if (chan->err)
+               return;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       /* There's already an active descriptor, bail out. */
+       if (chan->active_desc)
+               goto out_unlock;
+
+       if (list_empty(&chan->pending_list))
+               goto out_unlock;
+
+       desc = list_first_entry(&chan->pending_list,
+                               struct xilinx_vdma_tx_descriptor, node);
+
+       /* If it is SG mode and hardware is busy, cannot submit */
+       if (chan->has_sg && xilinx_vdma_is_running(chan) &&
+           !xilinx_vdma_is_idle(chan)) {
+               dev_dbg(chan->dev, "DMA controller still busy\n");
+               goto out_unlock;
+       }
+
+       /*
+        * If hardware is idle, then all descriptors on the running lists are
+        * done, start new transfers
+        */
+       if (chan->has_sg) {
+               head = list_first_entry(&desc->segments,
+                                       struct xilinx_vdma_tx_segment, node);
+               tail = list_entry(desc->segments.prev,
+                                 struct xilinx_vdma_tx_segment, node);
+
+               vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC, head->phys);
+       }
+
+       /* Configure the hardware using info in the config structure */
+       reg = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR);
+
+       if (config->frm_cnt_en)
+               reg |= XILINX_VDMA_DMACR_FRAMECNT_EN;
+       else
+               reg &= ~XILINX_VDMA_DMACR_FRAMECNT_EN;
+
+       /*
+        * With SG, start with circular mode, so that BDs can be fetched.
+        * In direct register mode, if not parking, enable circular mode
+        */
+       if (chan->has_sg || !config->park)
+               reg |= XILINX_VDMA_DMACR_CIRC_EN;
+
+       if (config->park)
+               reg &= ~XILINX_VDMA_DMACR_CIRC_EN;
+
+       vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, reg);
+
+       if (config->park && (config->park_frm >= 0) &&
+                       (config->park_frm < chan->num_frms)) {
+               if (chan->direction == DMA_MEM_TO_DEV)
+                       vdma_write(chan, XILINX_VDMA_REG_PARK_PTR,
+                               config->park_frm <<
+                                       XILINX_VDMA_PARK_PTR_RD_REF_SHIFT);
+               else
+                       vdma_write(chan, XILINX_VDMA_REG_PARK_PTR,
+                               config->park_frm <<
+                                       XILINX_VDMA_PARK_PTR_WR_REF_SHIFT);
+       }
+
+       /* Start the hardware */
+       xilinx_vdma_start(chan);
+
+       if (chan->err)
+               goto out_unlock;
+
+       /* Start the transfer */
+       if (chan->has_sg) {
+               vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC, tail->phys);
+       } else {
+               struct xilinx_vdma_tx_segment *segment, *last = NULL;
+               int i = 0;
+
+               list_for_each_entry(segment, &desc->segments, node) {
+                       vdma_desc_write(chan,
+                                       XILINX_VDMA_REG_START_ADDRESS(i++),
+                                       segment->hw.buf_addr);
+                       last = segment;
+               }
+
+               if (!last)
+                       goto out_unlock;
+
+               /* HW expects these parameters to be same for one transaction */
+               vdma_desc_write(chan, XILINX_VDMA_REG_HSIZE, last->hw.hsize);
+               vdma_desc_write(chan, XILINX_VDMA_REG_FRMDLY_STRIDE,
+                               last->hw.stride);
+               vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE, last->hw.vsize);
+       }
+
+       list_del(&desc->node);
+       chan->active_desc = desc;
+
+out_unlock:
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+ */
+static void xilinx_vdma_issue_pending(struct dma_chan *dchan)
+{
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+       xilinx_vdma_start_transfer(chan);
+}
+
+/**
+ * xilinx_vdma_complete_descriptor - Mark the active descriptor as complete
+ * @chan : xilinx DMA channel
+ *
+ * CONTEXT: hardirq
+ */
+static void xilinx_vdma_complete_descriptor(struct xilinx_vdma_chan *chan)
+{
+       struct xilinx_vdma_tx_descriptor *desc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       desc = chan->active_desc;
+       if (!desc) {
+               dev_dbg(chan->dev, "no running descriptors\n");
+               goto out_unlock;
+       }
+
+       dma_cookie_complete(&desc->async_tx);
+       list_add_tail(&desc->node, &chan->done_list);
+
+       chan->active_desc = NULL;
+
+out_unlock:
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_vdma_reset - Reset VDMA channel
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_reset(struct xilinx_vdma_chan *chan)
+{
+       int loop = XILINX_VDMA_LOOP_COUNT;
+       u32 tmp;
+
+       vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RESET);
+
+       tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
+               XILINX_VDMA_DMACR_RESET;
+
+       /* Wait for the hardware to finish reset */
+       do {
+               tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) &
+                       XILINX_VDMA_DMACR_RESET;
+       } while (loop-- && tmp);
+
+       if (!loop) {
+               dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
+                       vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR),
+                       vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR));
+               return -ETIMEDOUT;
+       }
+
+       chan->err = false;
+
+       return 0;
+}
+
+/**
+ * xilinx_vdma_chan_reset - Reset VDMA channel and enable interrupts
+ * @chan: Driver specific VDMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_chan_reset(struct xilinx_vdma_chan *chan)
+{
+       int err;
+
+       /* Reset VDMA */
+       err = xilinx_vdma_reset(chan);
+       if (err)
+               return err;
+
+       /* Enable interrupts */
+       vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR,
+                     XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
+
+       return 0;
+}
+
+/**
+ * xilinx_vdma_irq_handler - VDMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the Xilinx VDMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data)
+{
+       struct xilinx_vdma_chan *chan = data;
+       u32 status;
+
+       /* Read the status and ack the interrupts. */
+       status = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR);
+       if (!(status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK))
+               return IRQ_NONE;
+
+       vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR,
+                       status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
+
+       if (status & XILINX_VDMA_DMASR_ERR_IRQ) {
+               /*
+                * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the
+                * error is recoverable, ignore it. Otherwise flag the error.
+                *
+                * Only recoverable errors can be cleared in the DMASR register,
+                * make sure not to write to other error bits to 1.
+                */
+               u32 errors = status & XILINX_VDMA_DMASR_ALL_ERR_MASK;
+               vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR,
+                               errors & XILINX_VDMA_DMASR_ERR_RECOVER_MASK);
+
+               if (!chan->flush_on_fsync ||
+                   (errors & ~XILINX_VDMA_DMASR_ERR_RECOVER_MASK)) {
+                       dev_err(chan->dev,
+                               "Channel %p has errors %x, cdr %x tdr %x\n",
+                               chan, errors,
+                               vdma_ctrl_read(chan, XILINX_VDMA_REG_CURDESC),
+                               vdma_ctrl_read(chan, XILINX_VDMA_REG_TAILDESC));
+                       chan->err = true;
+               }
+       }
+
+       if (status & XILINX_VDMA_DMASR_DLY_CNT_IRQ) {
+               /*
+                * Device takes too long to do the transfer when user requires
+                * responsiveness.
+                */
+               dev_dbg(chan->dev, "Inter-packet latency too long\n");
+       }
+
+       if (status & XILINX_VDMA_DMASR_FRM_CNT_IRQ) {
+               xilinx_vdma_complete_descriptor(chan);
+               xilinx_vdma_start_transfer(chan);
+       }
+
+       tasklet_schedule(&chan->tasklet);
+       return IRQ_HANDLED;
+}
+
+/**
+ * xilinx_vdma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor
+ *
+ * Return: cookie value on success and failure value on error
+ */
+static dma_cookie_t xilinx_vdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct xilinx_vdma_tx_descriptor *desc = to_vdma_tx_descriptor(tx);
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(tx->chan);
+       dma_cookie_t cookie;
+       unsigned long flags;
+       int err;
+
+       if (chan->err) {
+               /*
+                * If reset fails, need to hard reset the system.
+                * Channel is no longer functional
+                */
+               err = xilinx_vdma_chan_reset(chan);
+               if (err < 0)
+                       return err;
+       }
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       cookie = dma_cookie_assign(tx);
+
+       /* Append the transaction to the pending transactions queue. */
+       list_add_tail(&desc->node, &chan->pending_list);
+
+       /* Free the allocated desc */
+       chan->allocated_desc = NULL;
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return cookie;
+}
+
+/**
+ * xilinx_vdma_dma_prep_interleaved - prepare a descriptor for a
+ *     DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xt: Interleaved template pointer
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
+                                struct dma_interleaved_template *xt,
+                                unsigned long flags)
+{
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+       struct xilinx_vdma_tx_descriptor *desc;
+       struct xilinx_vdma_tx_segment *segment, *prev = NULL;
+       struct xilinx_vdma_desc_hw *hw;
+
+       if (!is_slave_direction(xt->dir))
+               return NULL;
+
+       if (!xt->numf || !xt->sgl[0].size)
+               return NULL;
+
+       /* Allocate a transaction descriptor. */
+       desc = xilinx_vdma_alloc_tx_descriptor(chan);
+       if (!desc)
+               return NULL;
+
+       dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+       desc->async_tx.tx_submit = xilinx_vdma_tx_submit;
+       async_tx_ack(&desc->async_tx);
+
+       /* Allocate the link descriptor from DMA pool */
+       segment = xilinx_vdma_alloc_tx_segment(chan);
+       if (!segment)
+               goto error;
+
+       /* Fill in the hardware descriptor */
+       hw = &segment->hw;
+       hw->vsize = xt->numf;
+       hw->hsize = xt->sgl[0].size;
+       hw->stride = xt->sgl[0].icg <<
+                       XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT;
+       hw->stride |= chan->config.frm_dly <<
+                       XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT;
+
+       if (xt->dir != DMA_MEM_TO_DEV)
+               hw->buf_addr = xt->dst_start;
+       else
+               hw->buf_addr = xt->src_start;
+
+       /* Link the previous next descriptor to current */
+       prev = list_last_entry(&desc->segments,
+                               struct xilinx_vdma_tx_segment, node);
+       prev->hw.next_desc = segment->phys;
+
+       /* Insert the segment into the descriptor segments list. */
+       list_add_tail(&segment->node, &desc->segments);
+
+       prev = segment;
+
+       /* Link the last hardware descriptor with the first. */
+       segment = list_first_entry(&desc->segments,
+                                  struct xilinx_vdma_tx_segment, node);
+       prev->hw.next_desc = segment->phys;
+
+       return &desc->async_tx;
+
+error:
+       xilinx_vdma_free_tx_descriptor(chan, desc);
+       return NULL;
+}
+
+/**
+ * xilinx_vdma_terminate_all - Halt the channel and free descriptors
+ * @chan: Driver specific VDMA Channel pointer
+ */
+static void xilinx_vdma_terminate_all(struct xilinx_vdma_chan *chan)
+{
+       /* Halt the DMA engine */
+       xilinx_vdma_halt(chan);
+
+       /* Remove and free all of the descriptors in the lists */
+       xilinx_vdma_free_descriptors(chan);
+}
+
+/**
+ * xilinx_vdma_channel_set_config - Configure VDMA channel
+ * Run-time configuration for Axi VDMA, supports:
+ * . halt the channel
+ * . configure interrupt coalescing and inter-packet delay threshold
+ * . start/stop parking
+ * . enable genlock
+ *
+ * @dchan: DMA channel
+ * @cfg: VDMA device configuration pointer
+ *
+ * Return: '0' on success and failure value on error
+ */
+int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
+                                       struct xilinx_vdma_config *cfg)
+{
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+       u32 dmacr;
+
+       if (cfg->reset)
+               return xilinx_vdma_chan_reset(chan);
+
+       dmacr = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR);
+
+       chan->config.frm_dly = cfg->frm_dly;
+       chan->config.park = cfg->park;
+
+       /* genlock settings */
+       chan->config.gen_lock = cfg->gen_lock;
+       chan->config.master = cfg->master;
+
+       if (cfg->gen_lock && chan->genlock) {
+               dmacr |= XILINX_VDMA_DMACR_GENLOCK_EN;
+               dmacr |= cfg->master << XILINX_VDMA_DMACR_MASTER_SHIFT;
+       }
+
+       chan->config.frm_cnt_en = cfg->frm_cnt_en;
+       if (cfg->park)
+               chan->config.park_frm = cfg->park_frm;
+       else
+               chan->config.park_frm = -1;
+
+       chan->config.coalesc = cfg->coalesc;
+       chan->config.delay = cfg->delay;
+
+       if (cfg->coalesc <= XILINX_VDMA_DMACR_FRAME_COUNT_MAX) {
+               dmacr |= cfg->coalesc << XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT;
+               chan->config.coalesc = cfg->coalesc;
+       }
+
+       if (cfg->delay <= XILINX_VDMA_DMACR_DELAY_MAX) {
+               dmacr |= cfg->delay << XILINX_VDMA_DMACR_DELAY_SHIFT;
+               chan->config.delay = cfg->delay;
+       }
+
+       /* FSync Source selection */
+       dmacr &= ~XILINX_VDMA_DMACR_FSYNCSRC_MASK;
+       dmacr |= cfg->ext_fsync << XILINX_VDMA_DMACR_FSYNCSRC_SHIFT;
+
+       vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, dmacr);
+
+       return 0;
+}
+EXPORT_SYMBOL(xilinx_vdma_channel_set_config);
+
+/**
+ * xilinx_vdma_device_control - Configure DMA channel of the device
+ * @dchan: DMA Channel pointer
+ * @cmd: DMA control command
+ * @arg: Channel configuration
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_device_control(struct dma_chan *dchan,
+                                     enum dma_ctrl_cmd cmd, unsigned long arg)
+{
+       struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
+       if (cmd != DMA_TERMINATE_ALL)
+               return -ENXIO;
+
+       xilinx_vdma_terminate_all(chan);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+/**
+ * xilinx_vdma_chan_remove - Per Channel remove function
+ * @chan: Driver specific VDMA channel
+ */
+static void xilinx_vdma_chan_remove(struct xilinx_vdma_chan *chan)
+{
+       /* Disable all interrupts */
+       vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR,
+                     XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
+
+       if (chan->irq > 0)
+               free_irq(chan->irq, chan);
+
+       tasklet_kill(&chan->tasklet);
+
+       list_del(&chan->common.device_node);
+}
+
+/**
+ * xilinx_vdma_chan_probe - Per Channel Probing
+ * It get channel features from the device tree entry and
+ * initialize special channel handling routines
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_chan_probe(struct xilinx_vdma_device *xdev,
+                                 struct device_node *node)
+{
+       struct xilinx_vdma_chan *chan;
+       bool has_dre = false;
+       u32 value, width;
+       int err;
+
+       /* Allocate and initialize the channel structure */
+       chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+
+       chan->dev = xdev->dev;
+       chan->xdev = xdev;
+       chan->has_sg = xdev->has_sg;
+
+       spin_lock_init(&chan->lock);
+       INIT_LIST_HEAD(&chan->pending_list);
+       INIT_LIST_HEAD(&chan->done_list);
+
+       /* Retrieve the channel properties from the device tree */
+       has_dre = of_property_read_bool(node, "xlnx,include-dre");
+
+       chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
+
+       err = of_property_read_u32(node, "xlnx,datawidth", &value);
+       if (err) {
+               dev_err(xdev->dev, "missing xlnx,datawidth property\n");
+               return err;
+       }
+       width = value >> 3; /* Convert bits to bytes */
+
+       /* If data width is greater than 8 bytes, DRE is not in hw */
+       if (width > 8)
+               has_dre = false;
+
+       if (!has_dre)
+               xdev->common.copy_align = fls(width - 1);
+
+       if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel")) {
+               chan->direction = DMA_MEM_TO_DEV;
+               chan->id = 0;
+
+               chan->ctrl_offset = XILINX_VDMA_MM2S_CTRL_OFFSET;
+               chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
+
+               if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
+                   xdev->flush_on_fsync == XILINX_VDMA_FLUSH_MM2S)
+                       chan->flush_on_fsync = true;
+       } else if (of_device_is_compatible(node,
+                                           "xlnx,axi-vdma-s2mm-channel")) {
+               chan->direction = DMA_DEV_TO_MEM;
+               chan->id = 1;
+
+               chan->ctrl_offset = XILINX_VDMA_S2MM_CTRL_OFFSET;
+               chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
+
+               if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
+                   xdev->flush_on_fsync == XILINX_VDMA_FLUSH_S2MM)
+                       chan->flush_on_fsync = true;
+       } else {
+               dev_err(xdev->dev, "Invalid channel compatible node\n");
+               return -EINVAL;
+       }
+
+       /* Request the interrupt */
+       chan->irq = irq_of_parse_and_map(node, 0);
+       err = request_irq(chan->irq, xilinx_vdma_irq_handler, IRQF_SHARED,
+                         "xilinx-vdma-controller", chan);
+       if (err) {
+               dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
+               return err;
+       }
+
+       /* Initialize the tasklet */
+       tasklet_init(&chan->tasklet, xilinx_vdma_do_tasklet,
+                       (unsigned long)chan);
+
+       /*
+        * Initialize the DMA channel and add it to the DMA engine channels
+        * list.
+        */
+       chan->common.device = &xdev->common;
+
+       list_add_tail(&chan->common.device_node, &xdev->common.channels);
+       xdev->chan[chan->id] = chan;
+
+       /* Reset the channel */
+       err = xilinx_vdma_chan_reset(chan);
+       if (err < 0) {
+               dev_err(xdev->dev, "Reset channel failed\n");
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * of_dma_xilinx_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
+                                               struct of_dma *ofdma)
+{
+       struct xilinx_vdma_device *xdev = ofdma->of_dma_data;
+       int chan_id = dma_spec->args[0];
+
+       if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE)
+               return NULL;
+
+       return dma_get_slave_channel(&xdev->chan[chan_id]->common);
+}
+
+/**
+ * xilinx_vdma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_vdma_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct xilinx_vdma_device *xdev;
+       struct device_node *child;
+       struct resource *io;
+       u32 num_frames;
+       int i, err;
+
+       /* Allocate and initialize the DMA engine structure */
+       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+       if (!xdev)
+               return -ENOMEM;
+
+       xdev->dev = &pdev->dev;
+
+       /* Request and map I/O memory */
+       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xdev->regs = devm_ioremap_resource(&pdev->dev, io);
+       if (IS_ERR(xdev->regs))
+               return PTR_ERR(xdev->regs);
+
+       /* Retrieve the DMA engine properties from the device tree */
+       xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
+
+       err = of_property_read_u32(node, "xlnx,num-fstores", &num_frames);
+       if (err < 0) {
+               dev_err(xdev->dev, "missing xlnx,num-fstores property\n");
+               return err;
+       }
+
+       err = of_property_read_u32(node, "xlnx,flush-fsync",
+                                       &xdev->flush_on_fsync);
+       if (err < 0)
+               dev_warn(xdev->dev, "missing xlnx,flush-fsync property\n");
+
+       /* Initialize the DMA engine */
+       xdev->common.dev = &pdev->dev;
+
+       INIT_LIST_HEAD(&xdev->common.channels);
+       dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);
+       dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
+
+       xdev->common.device_alloc_chan_resources =
+                               xilinx_vdma_alloc_chan_resources;
+       xdev->common.device_free_chan_resources =
+                               xilinx_vdma_free_chan_resources;
+       xdev->common.device_prep_interleaved_dma =
+                               xilinx_vdma_dma_prep_interleaved;
+       xdev->common.device_control = xilinx_vdma_device_control;
+       xdev->common.device_tx_status = xilinx_vdma_tx_status;
+       xdev->common.device_issue_pending = xilinx_vdma_issue_pending;
+
+       platform_set_drvdata(pdev, xdev);
+
+       /* Initialize the channels */
+       for_each_child_of_node(node, child) {
+               err = xilinx_vdma_chan_probe(xdev, child);
+               if (err < 0)
+                       goto error;
+       }
+
+       for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
+               if (xdev->chan[i])
+                       xdev->chan[i]->num_frms = num_frames;
+
+       /* Register the DMA engine with the core */
+       dma_async_device_register(&xdev->common);
+
+       err = of_dma_controller_register(node, of_dma_xilinx_xlate,
+                                        xdev);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+               dma_async_device_unregister(&xdev->common);
+               goto error;
+       }
+
+       dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n");
+
+       return 0;
+
+error:
+       for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
+               if (xdev->chan[i])
+                       xilinx_vdma_chan_remove(xdev->chan[i]);
+
+       return err;
+}
+
+/**
+ * xilinx_vdma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int xilinx_vdma_remove(struct platform_device *pdev)
+{
+       struct xilinx_vdma_device *xdev = platform_get_drvdata(pdev);
+       int i;
+
+       of_dma_controller_free(pdev->dev.of_node);
+
+       dma_async_device_unregister(&xdev->common);
+
+       for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
+               if (xdev->chan[i])
+                       xilinx_vdma_chan_remove(xdev->chan[i]);
+
+       return 0;
+}
+
+static const struct of_device_id xilinx_vdma_of_ids[] = {
+       { .compatible = "xlnx,axi-vdma-1.00.a",},
+       {}
+};
+
+static struct platform_driver xilinx_vdma_driver = {
+       .driver = {
+               .name = "xilinx-vdma",
+               .owner = THIS_MODULE,
+               .of_match_table = xilinx_vdma_of_ids,
+       },
+       .probe = xilinx_vdma_probe,
+       .remove = xilinx_vdma_remove,
+};
+
+module_platform_driver(xilinx_vdma_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx VDMA driver");
+MODULE_LICENSE("GPL v2");
index be56e8ac95e6e3d6240ec1039739f0efbaba74e1..aebde489c2914d07173558d0909203d9ffd04ee4 100644 (file)
@@ -28,13 +28,13 @@ config EXTCON_ADC_JACK
          Say Y here to enable extcon device driver based on ADC values.
 
 config EXTCON_MAX14577
-       tristate "MAX14577 EXTCON Support"
+       tristate "MAX14577/77836 EXTCON Support"
        depends on MFD_MAX14577
        select IRQ_DOMAIN
        select REGMAP_I2C
        help
          If you say yes here you get support for the MUIC device of
-         Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
+         Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
          detector and switch.
 
 config EXTCON_MAX77693
index 3846941801b8fdc4eb5cc2e9adfd2024cf3e29d3..c76734a70171756a351167b58601712b0258c4fd 100644 (file)
@@ -1,8 +1,9 @@
 /*
- * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
+ * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
  *
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2013,2014 Samsung Electrnoics
  * Chanwoo Choi <cw00.choi@samsung.com>
+ * Krzysztof Kozlowski <k.kozlowski@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
@@ -24,7 +25,6 @@
 #include <linux/mfd/max14577-private.h>
 #include <linux/extcon.h>
 
-#define        DEV_NAME                        "max14577-muic"
 #define        DELAY_MS_DEFAULT                17000           /* unit: millisecond */
 
 enum max14577_muic_adc_debounce_time {
@@ -40,6 +40,42 @@ enum max14577_muic_status {
        MAX14577_MUIC_STATUS_END,
 };
 
+/**
+ * struct max14577_muic_irq
+ * @irq: the index of irq list of MUIC device.
+ * @name: the name of irq.
+ * @virq: the virtual irq to use irq domain
+ */
+struct max14577_muic_irq {
+       unsigned int irq;
+       const char *name;
+       unsigned int virq;
+};
+
+static struct max14577_muic_irq max14577_muic_irqs[] = {
+       { MAX14577_IRQ_INT1_ADC,        "muic-ADC" },
+       { MAX14577_IRQ_INT1_ADCLOW,     "muic-ADCLOW" },
+       { MAX14577_IRQ_INT1_ADCERR,     "muic-ADCError" },
+       { MAX14577_IRQ_INT2_CHGTYP,     "muic-CHGTYP" },
+       { MAX14577_IRQ_INT2_CHGDETRUN,  "muic-CHGDETRUN" },
+       { MAX14577_IRQ_INT2_DCDTMR,     "muic-DCDTMR" },
+       { MAX14577_IRQ_INT2_DBCHG,      "muic-DBCHG" },
+       { MAX14577_IRQ_INT2_VBVOLT,     "muic-VBVOLT" },
+};
+
+static struct max14577_muic_irq max77836_muic_irqs[] = {
+       { MAX14577_IRQ_INT1_ADC,        "muic-ADC" },
+       { MAX14577_IRQ_INT1_ADCLOW,     "muic-ADCLOW" },
+       { MAX14577_IRQ_INT1_ADCERR,     "muic-ADCError" },
+       { MAX77836_IRQ_INT1_ADC1K,      "muic-ADC1K" },
+       { MAX14577_IRQ_INT2_CHGTYP,     "muic-CHGTYP" },
+       { MAX14577_IRQ_INT2_CHGDETRUN,  "muic-CHGDETRUN" },
+       { MAX14577_IRQ_INT2_DCDTMR,     "muic-DCDTMR" },
+       { MAX14577_IRQ_INT2_DBCHG,      "muic-DBCHG" },
+       { MAX14577_IRQ_INT2_VBVOLT,     "muic-VBVOLT" },
+       { MAX77836_IRQ_INT2_VIDRM,      "muic-VIDRM" },
+};
+
 struct max14577_muic_info {
        struct device *dev;
        struct max14577 *max14577;
@@ -48,6 +84,8 @@ struct max14577_muic_info {
        int prev_chg_type;
        u8 status[MAX14577_MUIC_STATUS_END];
 
+       struct max14577_muic_irq *muic_irqs;
+       unsigned int muic_irqs_num;
        bool irq_adc;
        bool irq_chg;
        struct work_struct irq_work;
@@ -74,29 +112,6 @@ enum max14577_muic_cable_group {
        MAX14577_CABLE_GROUP_CHG,
 };
 
-/**
- * struct max14577_muic_irq
- * @irq: the index of irq list of MUIC device.
- * @name: the name of irq.
- * @virq: the virtual irq to use irq domain
- */
-struct max14577_muic_irq {
-       unsigned int irq;
-       const char *name;
-       unsigned int virq;
-};
-
-static struct max14577_muic_irq muic_irqs[] = {
-       { MAX14577_IRQ_INT1_ADC,        "muic-ADC" },
-       { MAX14577_IRQ_INT1_ADCLOW,     "muic-ADCLOW" },
-       { MAX14577_IRQ_INT1_ADCERR,     "muic-ADCError" },
-       { MAX14577_IRQ_INT2_CHGTYP,     "muic-CHGTYP" },
-       { MAX14577_IRQ_INT2_CHGDETRUN,  "muic-CHGDETRUN" },
-       { MAX14577_IRQ_INT2_DCDTMR,     "muic-DCDTMR" },
-       { MAX14577_IRQ_INT2_DBCHG,      "muic-DBCHG" },
-       { MAX14577_IRQ_INT2_VBVOLT,     "muic-VBVOLT" },
-};
-
 /* Define supported accessory type */
 enum max14577_muic_acc_type {
        MAX14577_MUIC_ADC_GROUND = 0x0,
@@ -528,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
        return;
 }
 
-static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+/*
+ * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
+ * Returns 0 if irq_type does not match registered IRQ for this device type.
+ */
+static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
 {
-       struct max14577_muic_info *info = data;
-       int i, irq_type = -1;
-
-       /*
-        * We may be called multiple times for different nested IRQ-s.
-        * Including changes in INT1_ADC and INT2_CGHTYP at once.
-        * However we only need to know whether it was ADC, charger
-        * or both interrupts so decode IRQ and turn on proper flags.
-        */
-       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
-               if (irq == muic_irqs[i].virq)
-                       irq_type = muic_irqs[i].irq;
-
        switch (irq_type) {
        case MAX14577_IRQ_INT1_ADC:
        case MAX14577_IRQ_INT1_ADCLOW:
@@ -550,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
                /* Handle all of accessory except for
                   type of charger accessory */
                info->irq_adc = true;
-               break;
+               return 1;
        case MAX14577_IRQ_INT2_CHGTYP:
        case MAX14577_IRQ_INT2_CHGDETRUN:
        case MAX14577_IRQ_INT2_DCDTMR:
@@ -558,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
        case MAX14577_IRQ_INT2_VBVOLT:
                /* Handle charger accessory */
                info->irq_chg = true;
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
+ * Returns 0 if irq_type does not match registered IRQ for this device type.
+ */
+static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)
+{
+       /* First check common max14577 interrupts */
+       if (max14577_parse_irq(info, irq_type))
+               return 1;
+
+       switch (irq_type) {
+       case MAX77836_IRQ_INT1_ADC1K:
+               info->irq_adc = true;
+               return 1;
+       case MAX77836_IRQ_INT2_VIDRM:
+               /* Handle charger accessory */
+               info->irq_chg = true;
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+{
+       struct max14577_muic_info *info = data;
+       int i, irq_type = -1;
+       bool irq_parsed;
+
+       /*
+        * We may be called multiple times for different nested IRQ-s.
+        * Including changes in INT1_ADC and INT2_CGHTYP at once.
+        * However we only need to know whether it was ADC, charger
+        * or both interrupts so decode IRQ and turn on proper flags.
+        */
+       for (i = 0; i < info->muic_irqs_num; i++)
+               if (irq == info->muic_irqs[i].virq)
+                       irq_type = info->muic_irqs[i].irq;
+
+       switch (info->max14577->dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               irq_parsed = max77836_parse_irq(info, irq_type);
                break;
+       case MAXIM_DEVICE_TYPE_MAX14577:
        default:
+               irq_parsed = max14577_parse_irq(info, irq_type);
+               break;
+       }
+
+       if (!irq_parsed) {
                dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
                                irq_type);
                return IRQ_HANDLED;
@@ -644,9 +704,20 @@ static int max14577_muic_probe(struct platform_device *pdev)
 
        INIT_WORK(&info->irq_work, max14577_muic_irq_work);
 
+       switch (max14577->dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               info->muic_irqs = max77836_muic_irqs;
+               info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);
+               break;
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               info->muic_irqs = max14577_muic_irqs;
+               info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs);
+       }
+
        /* Support irq domain for max14577 MUIC device */
-       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
-               struct max14577_muic_irq *muic_irq = &muic_irqs[i];
+       for (i = 0; i < info->muic_irqs_num; i++) {
+               struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
                unsigned int virq = 0;
 
                virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
@@ -673,7 +744,8 @@ static int max14577_muic_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
                return -ENOMEM;
        }
-       info->edev->name = DEV_NAME;
+
+       info->edev->name = dev_name(&pdev->dev);
        info->edev->supported_cable = max14577_extcon_cable;
        ret = extcon_dev_register(info->edev);
        if (ret) {
@@ -735,18 +807,26 @@ static int max14577_muic_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id max14577_muic_id[] = {
+       { "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
+       { "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, max14577_muic_id);
+
 static struct platform_driver max14577_muic_driver = {
        .driver         = {
-               .name   = DEV_NAME,
+               .name   = "max14577-muic",
                .owner  = THIS_MODULE,
        },
        .probe          = max14577_muic_probe,
        .remove         = max14577_muic_remove,
+       .id_table       = max14577_muic_id,
 };
 
 module_platform_driver(max14577_muic_driver);
 
-MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:extcon-max14577");
index 32982da82694be753d1072c90136d842a8a866ec..567cfbde0883df7f26e9b81da62ef778503dd424 100644 (file)
@@ -173,7 +173,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto err_kms;
 
-       ret = drm_irq_install(dev);
+       ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
        if (ret)
                goto err_kms;
 
index 5137f15dba19e71a220ac38efb7e1fee2ebbbd4a..2ba39ac7d222119cb6ee7b505f1ae701bec0ed49 100644 (file)
@@ -198,7 +198,6 @@ static const struct file_operations ast_fops = {
 
 static struct drm_driver driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM,
-       .dev_priv_size = 0,
 
        .load = ast_driver_load,
        .unload = ast_driver_unload,
index 50535fd5a88d258492b90ca9e9e9cebfaf2de563..01bf9e730acf6087d499ed5fb1ade94cd5763124 100644 (file)
@@ -411,16 +411,13 @@ static void ast_bo_unref(struct ast_bo **bo)
 
        tbo = &((*bo)->bo);
        ttm_bo_unref(&tbo);
-       if (tbo == NULL)
-               *bo = NULL;
-
+       *bo = NULL;
 }
+
 void ast_gem_free_object(struct drm_gem_object *obj)
 {
        struct ast_bo *ast_bo = gem_to_ast_bo(obj);
 
-       if (!ast_bo)
-               return;
        ast_bo_unref(&ast_bo);
 }
 
index f488be55d650e332560e7bd83212007cac50c4a5..b9a695d92792ee224868d3f9f9ce32e0475d48c8 100644 (file)
@@ -434,17 +434,13 @@ static void bochs_bo_unref(struct bochs_bo **bo)
 
        tbo = &((*bo)->bo);
        ttm_bo_unref(&tbo);
-       if (tbo == NULL)
-               *bo = NULL;
-
+       *bo = NULL;
 }
 
 void bochs_gem_free_object(struct drm_gem_object *obj)
 {
        struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj);
 
-       if (!bochs_bo)
-               return;
        bochs_bo_unref(&bochs_bo);
 }
 
index 4b0170cf53fd9225f07f731766cb8fe71fb40e91..99c1983f99d228b77ce9c498236ad68b348440e2 100644 (file)
@@ -264,17 +264,13 @@ static void cirrus_bo_unref(struct cirrus_bo **bo)
 
        tbo = &((*bo)->bo);
        ttm_bo_unref(&tbo);
-       if (tbo == NULL)
-               *bo = NULL;
-
+       *bo = NULL;
 }
 
 void cirrus_gem_free_object(struct drm_gem_object *obj)
 {
        struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj);
 
-       if (!cirrus_bo)
-               return;
        cirrus_bo_unref(&cirrus_bo);
 }
 
index edec31fe3fed865aa2669e7c8e17aec912a82058..ef7f0199a0f1e59a0aab8682325db1ab44ceffd6 100644 (file)
@@ -656,13 +656,13 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                DRM_DEBUG("zone invalid\n");
                return -EINVAL;
        }
-       spin_lock(&dev->count_lock);
+       spin_lock(&dev->buf_lock);
        if (dev->buf_use) {
-               spin_unlock(&dev->count_lock);
+               spin_unlock(&dev->buf_lock);
                return -EBUSY;
        }
        atomic_inc(&dev->buf_alloc);
-       spin_unlock(&dev->count_lock);
+       spin_unlock(&dev->buf_lock);
 
        mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
@@ -805,13 +805,13 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
        total = PAGE_SIZE << page_order;
 
-       spin_lock(&dev->count_lock);
+       spin_lock(&dev->buf_lock);
        if (dev->buf_use) {
-               spin_unlock(&dev->count_lock);
+               spin_unlock(&dev->buf_lock);
                return -EBUSY;
        }
        atomic_inc(&dev->buf_alloc);
-       spin_unlock(&dev->count_lock);
+       spin_unlock(&dev->buf_lock);
 
        mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
@@ -1015,13 +1015,13 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
        if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
                return -EINVAL;
 
-       spin_lock(&dev->count_lock);
+       spin_lock(&dev->buf_lock);
        if (dev->buf_use) {
-               spin_unlock(&dev->count_lock);
+               spin_unlock(&dev->buf_lock);
                return -EBUSY;
        }
        atomic_inc(&dev->buf_alloc);
-       spin_unlock(&dev->count_lock);
+       spin_unlock(&dev->buf_lock);
 
        mutex_lock(&dev->struct_mutex);
        entry = &dma->bufs[order];
@@ -1175,7 +1175,7 @@ int drm_addbufs(struct drm_device *dev, void *data,
  * \param arg pointer to a drm_buf_info structure.
  * \return zero on success or a negative number on failure.
  *
- * Increments drm_device::buf_use while holding the drm_device::count_lock
+ * Increments drm_device::buf_use while holding the drm_device::buf_lock
  * lock, preventing of allocating more buffers after this call. Information
  * about each requested buffer is then copied into user space.
  */
@@ -1196,13 +1196,13 @@ int drm_infobufs(struct drm_device *dev, void *data,
        if (!dma)
                return -EINVAL;
 
-       spin_lock(&dev->count_lock);
+       spin_lock(&dev->buf_lock);
        if (atomic_read(&dev->buf_alloc)) {
-               spin_unlock(&dev->count_lock);
+               spin_unlock(&dev->buf_lock);
                return -EBUSY;
        }
        ++dev->buf_use;         /* Can't allocate more after this call */
-       spin_unlock(&dev->count_lock);
+       spin_unlock(&dev->buf_lock);
 
        for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
                if (dma->bufs[i].buf_count)
@@ -1381,13 +1381,13 @@ int drm_mapbufs(struct drm_device *dev, void *data,
        if (!dma)
                return -EINVAL;
 
-       spin_lock(&dev->count_lock);
+       spin_lock(&dev->buf_lock);
        if (atomic_read(&dev->buf_alloc)) {
-               spin_unlock(&dev->count_lock);
+               spin_unlock(&dev->buf_lock);
                return -EBUSY;
        }
        dev->buf_use++;         /* Can't allocate more after this call */
-       spin_unlock(&dev->count_lock);
+       spin_unlock(&dev->buf_lock);
 
        if (request->count >= dma->buf_count) {
                if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP))
index 534cb89b160d686d60218dad53082be9b0f331ea..ae251b8abd0ec08295aa294e62c277f5eef5d3c0 100644 (file)
@@ -131,11 +131,11 @@ drm_clflush_sg(struct sg_table *st)
 EXPORT_SYMBOL(drm_clflush_sg);
 
 void
-drm_clflush_virt_range(char *addr, unsigned long length)
+drm_clflush_virt_range(void *addr, unsigned long length)
 {
 #if defined(CONFIG_X86)
        if (cpu_has_clflush) {
-               char *end = addr + length;
+               void *end = addr + length;
                mb();
                for (; addr < end; addr += boot_cpu_data.x86_clflush_size)
                        clflush(addr);
index 7473035dd28b781ed8f382d0e8b6cd3743df772e..86feedd5e6f696f521e5fa0619c2f86b64598f60 100644 (file)
@@ -47,18 +47,16 @@ int drm_name_info(struct seq_file *m, void *data)
        struct drm_minor *minor = node->minor;
        struct drm_device *dev = minor->dev;
        struct drm_master *master = minor->master;
-       const char *bus_name;
        if (!master)
                return 0;
 
-       bus_name = dev->driver->bus->get_name(dev);
        if (master->unique) {
                seq_printf(m, "%s %s %s\n",
-                          bus_name,
+                          dev->driver->name,
                           dev_name(dev->dev), master->unique);
        } else {
                seq_printf(m, "%s %s\n",
-                          bus_name, dev_name(dev->dev));
+                          dev->driver->name, dev_name(dev->dev));
        }
        return 0;
 }
index 93a42040bedb38a2bd21c4a8409a6ad83081674f..38269d5aa3337739cb2c5e1da319908ed4e1cd73 100644 (file)
@@ -72,9 +72,6 @@ static void
 drm_unset_busid(struct drm_device *dev,
                struct drm_master *master)
 {
-       kfree(dev->devname);
-       dev->devname = NULL;
-
        kfree(master->unique);
        master->unique = NULL;
        master->unique_len = 0;
@@ -93,7 +90,8 @@ drm_unset_busid(struct drm_device *dev,
  * Copies the bus id from userspace into drm_device::unique, and verifies that
  * it matches the device this DRM is attached to (EINVAL otherwise).  Deprecated
  * in interface version 1.1 and will return EBUSY when setversion has requested
- * version 1.1 or greater.
+ * version 1.1 or greater. Also note that KMS is all version 1.1 and later and
+ * UMS was only ever supported on pci devices.
  */
 int drm_setunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
@@ -108,10 +106,13 @@ int drm_setunique(struct drm_device *dev, void *data,
        if (!u->unique_len || u->unique_len > 1024)
                return -EINVAL;
 
-       if (!dev->driver->bus->set_unique)
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+
+       if (WARN_ON(!dev->pdev))
                return -EINVAL;
 
-       ret = dev->driver->bus->set_unique(dev, master, u);
+       ret = drm_pci_set_unique(dev, master, u);
        if (ret)
                goto err;
 
index c2676b5908d9f6edbcf4dd8d9fb126cfb93cd5ab..7583767ec619aab7acda2702c2cc767a8dd9a7de 100644 (file)
  */
 #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
 
-/**
- * Get interrupt from bus id.
- *
- * \param inode device inode.
- * \param file_priv DRM file private.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_irq_busid structure.
- * \return zero on success or a negative number on failure.
- *
- * Finds the PCI device with the specified bus id and gets its IRQ number.
- * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
- * to that of the device that this DRM instance attached to.
- */
-int drm_irq_by_busid(struct drm_device *dev, void *data,
-                    struct drm_file *file_priv)
-{
-       struct drm_irq_busid *p = data;
-
-       if (!dev->driver->bus->irq_by_busid)
-               return -EINVAL;
-
-       if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
-               return -EINVAL;
-
-       return dev->driver->bus->irq_by_busid(dev, p);
-}
-
 /*
  * Clear vblank timestamp buffer for a crtc.
  */
@@ -269,34 +242,26 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
  * \c irq_preinstall() and \c irq_postinstall() functions
  * before and after the installation.
  */
-int drm_irq_install(struct drm_device *dev)
+int drm_irq_install(struct drm_device *dev, int irq)
 {
        int ret;
        unsigned long sh_flags = 0;
-       char *irqname;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       if (drm_dev_to_irq(dev) == 0)
+       if (irq == 0)
                return -EINVAL;
 
-       mutex_lock(&dev->struct_mutex);
-
        /* Driver must have been initialized */
-       if (!dev->dev_private) {
-               mutex_unlock(&dev->struct_mutex);
+       if (!dev->dev_private)
                return -EINVAL;
-       }
 
-       if (dev->irq_enabled) {
-               mutex_unlock(&dev->struct_mutex);
+       if (dev->irq_enabled)
                return -EBUSY;
-       }
        dev->irq_enabled = true;
-       mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
+       DRM_DEBUG("irq=%d\n", irq);
 
        /* Before installing handler */
        if (dev->driver->irq_preinstall)
@@ -306,18 +271,11 @@ int drm_irq_install(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
                sh_flags = IRQF_SHARED;
 
-       if (dev->devname)
-               irqname = dev->devname;
-       else
-               irqname = dev->driver->name;
-
-       ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,
-                         sh_flags, irqname, dev);
+       ret = request_irq(irq, dev->driver->irq_handler,
+                         sh_flags, dev->driver->name, dev);
 
        if (ret < 0) {
-               mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = false;
-               mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
@@ -329,12 +287,12 @@ int drm_irq_install(struct drm_device *dev)
                ret = dev->driver->irq_postinstall(dev);
 
        if (ret < 0) {
-               mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = false;
-               mutex_unlock(&dev->struct_mutex);
                if (!drm_core_check_feature(dev, DRIVER_MODESET))
                        vga_client_register(dev->pdev, NULL, NULL, NULL);
-               free_irq(drm_dev_to_irq(dev), dev);
+               free_irq(irq, dev);
+       } else {
+               dev->irq = irq;
        }
 
        return ret;
@@ -357,10 +315,8 @@ int drm_irq_uninstall(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       mutex_lock(&dev->struct_mutex);
        irq_enabled = dev->irq_enabled;
        dev->irq_enabled = false;
-       mutex_unlock(&dev->struct_mutex);
 
        /*
         * Wake up any waiters so they don't hang.
@@ -379,7 +335,7 @@ int drm_irq_uninstall(struct drm_device *dev)
        if (!irq_enabled)
                return -EINVAL;
 
-       DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
+       DRM_DEBUG("irq=%d\n", dev->irq);
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                vga_client_register(dev->pdev, NULL, NULL, NULL);
@@ -387,7 +343,7 @@ int drm_irq_uninstall(struct drm_device *dev)
        if (dev->driver->irq_uninstall)
                dev->driver->irq_uninstall(dev);
 
-       free_irq(drm_dev_to_irq(dev), dev);
+       free_irq(dev->irq, dev);
 
        return 0;
 }
@@ -408,28 +364,38 @@ int drm_control(struct drm_device *dev, void *data,
                struct drm_file *file_priv)
 {
        struct drm_control *ctl = data;
+       int ret = 0, irq;
 
        /* if we haven't irq we fallback for compatibility reasons -
         * this used to be a separate function in drm_dma.h
         */
 
+       if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+               return 0;
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+       /* UMS was only ever support on pci devices. */
+       if (WARN_ON(!dev->pdev))
+               return -EINVAL;
 
        switch (ctl->func) {
        case DRM_INST_HANDLER:
-               if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
-                       return 0;
-               if (drm_core_check_feature(dev, DRIVER_MODESET))
-                       return 0;
+               irq = dev->pdev->irq;
+
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
-                   ctl->irq != drm_dev_to_irq(dev))
+                   ctl->irq != irq)
                        return -EINVAL;
-               return drm_irq_install(dev);
+               mutex_lock(&dev->struct_mutex);
+               ret = drm_irq_install(dev, irq);
+               mutex_unlock(&dev->struct_mutex);
+
+               return ret;
        case DRM_UNINST_HANDLER:
-               if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
-                       return 0;
-               if (drm_core_check_feature(dev, DRIVER_MODESET))
-                       return 0;
-               return drm_irq_uninstall(dev);
+               mutex_lock(&dev->struct_mutex);
+               ret = drm_irq_uninstall(dev);
+               mutex_unlock(&dev->struct_mutex);
+
+               return ret;
        default:
                return -EINVAL;
        }
@@ -1160,9 +1126,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        int ret;
        unsigned int flags, seq, crtc, high_crtc;
 
-       if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
-               if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
-                       return -EINVAL;
+       if (!dev->irq_enabled)
+               return -EINVAL;
 
        if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
                return -EINVAL;
index 8b410576fce4b42998bb8e9a0334de5ff38207db..bedf1894e17e5fa0f8f6a028a970c976725e1dba 100644 (file)
@@ -1013,6 +1013,7 @@ EXPORT_SYMBOL(drm_mode_sort);
 /**
  * drm_mode_connector_list_update - update the mode list for the connector
  * @connector: the connector to update
+ * @merge_type_bits: whether to merge or overright type bits.
  *
  * This moves the modes from the @connector probed_modes list
  * to the actual mode list. It compares the probed mode against the current
@@ -1021,7 +1022,8 @@ EXPORT_SYMBOL(drm_mode_sort);
  * This is just a helper functions doesn't validate any modes itself and also
  * doesn't prune any invalid modes. Callers need to do that themselves.
  */
-void drm_mode_connector_list_update(struct drm_connector *connector)
+void drm_mode_connector_list_update(struct drm_connector *connector,
+                                   bool merge_type_bits)
 {
        struct drm_display_mode *mode;
        struct drm_display_mode *pmode, *pt;
@@ -1039,7 +1041,10 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
                                /* if equal delete the probed mode */
                                mode->status = pmode->status;
                                /* Merge type bits together */
-                               mode->type |= pmode->type;
+                               if (merge_type_bits)
+                                       mode->type |= pmode->type;
+                               else
+                                       mode->type = pmode->type;
                                list_del(&pmode->head);
                                drm_mode_destroy(connector->dev, pmode);
                                break;
index 9c696a5ad74de262244be248549f99173f4c3806..d237de36a07a97c645d41bf21657adc70bd52edd 100644 (file)
@@ -137,21 +137,9 @@ static int drm_get_pci_domain(struct drm_device *dev)
        return pci_domain_nr(dev->pdev->bus);
 }
 
-static int drm_pci_get_irq(struct drm_device *dev)
-{
-       return dev->pdev->irq;
-}
-
-static const char *drm_pci_get_name(struct drm_device *dev)
-{
-       struct pci_driver *pdriver = dev->driver->kdriver.pci;
-       return pdriver->name;
-}
-
 static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
 {
        int len, ret;
-       struct pci_driver *pdriver = dev->driver->kdriver.pci;
        master->unique_len = 40;
        master->unique_size = master->unique_len;
        master->unique = kmalloc(master->unique_size, GFP_KERNEL);
@@ -173,29 +161,16 @@ static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
        } else
                master->unique_len = len;
 
-       dev->devname =
-               kmalloc(strlen(pdriver->name) +
-                       master->unique_len + 2, GFP_KERNEL);
-
-       if (dev->devname == NULL) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       sprintf(dev->devname, "%s@%s", pdriver->name,
-               master->unique);
-
        return 0;
 err:
        return ret;
 }
 
-static int drm_pci_set_unique(struct drm_device *dev,
-                             struct drm_master *master,
-                             struct drm_unique *u)
+int drm_pci_set_unique(struct drm_device *dev,
+                      struct drm_master *master,
+                      struct drm_unique *u)
 {
        int domain, bus, slot, func, ret;
-       const char *bus_name;
 
        master->unique_len = u->unique_len;
        master->unique_size = u->unique_len + 1;
@@ -212,17 +187,6 @@ static int drm_pci_set_unique(struct drm_device *dev,
 
        master->unique[master->unique_len] = '\0';
 
-       bus_name = dev->driver->bus->get_name(dev);
-       dev->devname = kmalloc(strlen(bus_name) +
-                              strlen(master->unique) + 2, GFP_KERNEL);
-       if (!dev->devname) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       sprintf(dev->devname, "%s@%s", bus_name,
-               master->unique);
-
        /* Return error if the busid submitted doesn't match the device's actual
         * busid.
         */
@@ -247,7 +211,6 @@ err:
        return ret;
 }
 
-
 static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
 {
        if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
@@ -262,6 +225,37 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
        return 0;
 }
 
+/**
+ * Get interrupt from bus id.
+ *
+ * \param inode device inode.
+ * \param file_priv DRM file private.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_irq_busid structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Finds the PCI device with the specified bus id and gets its IRQ number.
+ * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
+ * to that of the device that this DRM instance attached to.
+ */
+int drm_irq_by_busid(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct drm_irq_busid *p = data;
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       /* UMS was only ever support on PCI devices. */
+       if (WARN_ON(!dev->pdev))
+               return -EINVAL;
+
+       if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+               return -EINVAL;
+
+       return drm_pci_irq_by_busid(dev, p);
+}
+
 static void drm_pci_agp_init(struct drm_device *dev)
 {
        if (drm_core_check_feature(dev, DRIVER_USE_AGP)) {
@@ -287,12 +281,7 @@ void drm_pci_agp_destroy(struct drm_device *dev)
 }
 
 static struct drm_bus drm_pci_bus = {
-       .bus_type = DRIVER_BUS_PCI,
-       .get_irq = drm_pci_get_irq,
-       .get_name = drm_pci_get_name,
        .set_busid = drm_pci_set_busid,
-       .set_unique = drm_pci_set_unique,
-       .irq_by_busid = drm_pci_irq_by_busid,
 };
 
 /**
@@ -375,7 +364,6 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 
        DRM_DEBUG("\n");
 
-       driver->kdriver.pci = pdriver;
        driver->bus = &drm_pci_bus;
 
        if (driver->driver_features & DRIVER_MODESET)
@@ -453,6 +441,19 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 }
 
 void drm_pci_agp_destroy(struct drm_device *dev) {}
+
+int drm_irq_by_busid(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       return -EINVAL;
+}
+
+int drm_pci_set_unique(struct drm_device *dev,
+                      struct drm_master *master,
+                      struct drm_unique *u)
+{
+       return -EINVAL;
+}
 #endif
 
 EXPORT_SYMBOL(drm_pci_init);
index 319ff538560119beda233eaff71d007d7aae3897..234e0bc1ae51091d4f564392b099d52eefefd8ad 100644 (file)
@@ -68,16 +68,6 @@ err_free:
        return ret;
 }
 
-static int drm_platform_get_irq(struct drm_device *dev)
-{
-       return platform_get_irq(dev->platformdev, 0);
-}
-
-static const char *drm_platform_get_name(struct drm_device *dev)
-{
-       return dev->platformdev->name;
-}
-
 static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
 {
        int len, ret, id;
@@ -106,26 +96,12 @@ static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *mas
                goto err;
        }
 
-       dev->devname =
-               kmalloc(strlen(dev->platformdev->name) +
-                       master->unique_len + 2, GFP_KERNEL);
-
-       if (dev->devname == NULL) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       sprintf(dev->devname, "%s@%s", dev->platformdev->name,
-               master->unique);
        return 0;
 err:
        return ret;
 }
 
 static struct drm_bus drm_platform_bus = {
-       .bus_type = DRIVER_BUS_PLATFORM,
-       .get_irq = drm_platform_get_irq,
-       .get_name = drm_platform_get_name,
        .set_busid = drm_platform_set_busid,
 };
 
@@ -145,7 +121,6 @@ int drm_platform_init(struct drm_driver *driver, struct platform_device *platfor
 {
        DRM_DEBUG("\n");
 
-       driver->kdriver.platform_device = platform_device;
        driver->bus = &drm_platform_bus;
        return drm_get_platform_dev(platform_device, driver);
 }
index e70f54d4a5810cec31f2c09a9a5e81a0bb1fe343..8afdd0998a8c7f33c4a092c8126a527a601b6f7a 100644 (file)
@@ -82,26 +82,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
        return;
 }
 
-/**
- * drm_helper_probe_single_connector_modes - get complete set of display modes
- * @connector: connector to probe
- * @maxX: max width for modes
- * @maxY: max height for modes
- *
- * Based on the helper callbacks implemented by @connector try to detect all
- * valid modes.  Modes will first be added to the connector's probed_modes list,
- * then culled (based on validity and the @maxX, @maxY parameters) and put into
- * the normal modes list.
- *
- * Intended to be use as a generic implementation of the ->fill_modes()
- * @connector vfunc for drivers that use the crtc helpers for output mode
- * filtering and detection.
- *
- * Returns:
- * The number of modes found on @connector.
- */
-int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
-                                           uint32_t maxX, uint32_t maxY)
+static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector,
+                                                             uint32_t maxX, uint32_t maxY, bool merge_type_bits)
 {
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode;
@@ -155,7 +137,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        if (count == 0)
                goto prune;
 
-       drm_mode_connector_list_update(connector);
+       drm_mode_connector_list_update(connector, merge_type_bits);
 
        if (maxX && maxY)
                drm_mode_validate_size(dev, &connector->modes, maxX, maxY);
@@ -194,8 +176,48 @@ prune:
 
        return count;
 }
+
+/**
+ * drm_helper_probe_single_connector_modes - get complete set of display modes
+ * @connector: connector to probe
+ * @maxX: max width for modes
+ * @maxY: max height for modes
+ *
+ * Based on the helper callbacks implemented by @connector try to detect all
+ * valid modes.  Modes will first be added to the connector's probed_modes list,
+ * then culled (based on validity and the @maxX, @maxY parameters) and put into
+ * the normal modes list.
+ *
+ * Intended to be use as a generic implementation of the ->fill_modes()
+ * @connector vfunc for drivers that use the crtc helpers for output mode
+ * filtering and detection.
+ *
+ * Returns:
+ * The number of modes found on @connector.
+ */
+int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
+                                           uint32_t maxX, uint32_t maxY)
+{
+       return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, true);
+}
 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
 
+/**
+ * drm_helper_probe_single_connector_modes_nomerge - get complete set of display modes
+ * @connector: connector to probe
+ * @maxX: max width for modes
+ * @maxY: max height for modes
+ *
+ * This operates like drm_hehlper_probe_single_connector_modes except it
+ * replaces the mode bits instead of merging them for preferred modes.
+ */
+int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector *connector,
+                                           uint32_t maxX, uint32_t maxY)
+{
+       return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, false);
+}
+EXPORT_SYMBOL(drm_helper_probe_single_connector_modes_nomerge);
+
 /**
  * drm_kms_helper_hotplug_event - fire off KMS hotplug events
  * @dev: drm_device whose connector state changed
index 4c24c3ac1efaf28225aa635834e982c9f5a6055b..1447b0ee367685a4d8435effa9ca6b10df513141 100644 (file)
@@ -128,7 +128,10 @@ struct drm_master *drm_master_create(struct drm_minor *minor)
        kref_init(&master->refcount);
        spin_lock_init(&master->lock.spinlock);
        init_waitqueue_head(&master->lock.lock_queue);
-       drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
+       if (drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER)) {
+               kfree(master);
+               return NULL;
+       }
        INIT_LIST_HEAD(&master->magicfree);
        master->minor = minor;
 
@@ -166,9 +169,6 @@ static void drm_master_destroy(struct kref *kref)
                master->unique_len = 0;
        }
 
-       kfree(dev->devname);
-       dev->devname = NULL;
-
        list_for_each_entry_safe(pt, next, &master->magicfree, head) {
                list_del(&pt->head);
                drm_ht_remove_item(&master->magiclist, &pt->hash_item);
@@ -569,7 +569,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
        INIT_LIST_HEAD(&dev->maplist);
        INIT_LIST_HEAD(&dev->vblank_event_list);
 
-       spin_lock_init(&dev->count_lock);
+       spin_lock_init(&dev->buf_lock);
        spin_lock_init(&dev->event_lock);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
@@ -648,8 +648,6 @@ static void drm_dev_release(struct kref *ref)
        drm_minor_free(dev, DRM_MINOR_RENDER);
        drm_minor_free(dev, DRM_MINOR_CONTROL);
 
-       kfree(dev->devname);
-
        mutex_destroy(&dev->master_mutex);
        kfree(dev);
 }
index c3406aad294463718ccdaf1d83fc7636a0322b17..c6c7c29ad46f43577ade9b7e7c1a238d46bad425 100644 (file)
@@ -36,16 +36,6 @@ err_free:
 }
 EXPORT_SYMBOL(drm_get_usb_dev);
 
-static int drm_usb_get_irq(struct drm_device *dev)
-{
-       return 0;
-}
-
-static const char *drm_usb_get_name(struct drm_device *dev)
-{
-       return "USB";
-}
-
 static int drm_usb_set_busid(struct drm_device *dev,
                               struct drm_master *master)
 {
@@ -53,9 +43,6 @@ static int drm_usb_set_busid(struct drm_device *dev,
 }
 
 static struct drm_bus drm_usb_bus = {
-       .bus_type = DRIVER_BUS_USB,
-       .get_irq = drm_usb_get_irq,
-       .get_name = drm_usb_get_name,
        .set_busid = drm_usb_set_busid,
 };
     
@@ -64,7 +51,6 @@ int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver)
        int res;
        DRM_DEBUG("\n");
 
-       driver->kdriver.usb = udriver;
        driver->bus = &drm_usb_bus;
 
        res = usb_register(udriver);
index e930d4fe29c71c2d82d2317bb6681ac8d3f39d6a..1ef5ab9c9d519d175b202dbf01cba243a870e1f7 100644 (file)
@@ -145,6 +145,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 
        plane->crtc = crtc;
        plane->fb = crtc->primary->fb;
+       drm_framebuffer_reference(plane->fb);
 
        return 0;
 }
index c786cd4f457bb8893fc4f02e8e27338832b1bc58..2a3ad24276f8380415940d00b87708f9cbe0d9e2 100644 (file)
@@ -263,7 +263,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
        buffer->sgt = sgt;
        exynos_gem_obj->base.import_attach = attach;
 
-       DRM_DEBUG_PRIME("dma_addr = 0x%x, size = 0x%lx\n", buffer->dma_addr,
+       DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr,
                                                                buffer->size);
 
        return &exynos_gem_obj->base;
index eb73e3bf2a0cbe6e56f9ae6b5d81b188038f05e3..4ac438187568ed4a6894436433e404c94b90a7a2 100644 (file)
@@ -1426,9 +1426,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (!dsi->reg_base) {
+       if (IS_ERR(dsi->reg_base)) {
                dev_err(&pdev->dev, "failed to remap io region\n");
-               return -EADDRNOTAVAIL;
+               return PTR_ERR(dsi->reg_base);
        }
 
        dsi->phy = devm_phy_get(&pdev->dev, "dsim");
index 7afead9c3f30258b7869e69e0f2015d9c2921fca..852f2dadaebdbbe3a385b5fe28cd65a560f0c210 100644 (file)
@@ -220,7 +220,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
 
        win_data->enabled = true;
 
-       DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
+       DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
 
        if (ctx->vblank_on)
                schedule_work(&ctx->work);
index b686e56646ebd4b8abe6ba53582dd4e595484f29..0a3101a3db19bb2fc068d7b34468b07826b09148 100644 (file)
@@ -354,7 +354,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
        PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R);
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
-       drm_irq_install(dev);
+       drm_irq_install(dev, dev->pdev->irq);
 
        dev->vblank_disable_allowed = true;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
index 48af5cac1902bbfa1360ee0a76918701baf83739..240c331405b92fac28ff40f83aebebed042d2125 100644 (file)
@@ -568,11 +568,11 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
 
 static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes)
 {
-       uint8_t sum = 0;
+       int sum = 0;
 
        while (bytes--)
-               sum += *buf++;
-       return (255 - sum) + 1;
+               sum -= *buf++;
+       return sum;
 }
 
 #define HB(x) (x)
index bea2d67196fb47b95f87d03ed80cd6dd53f250d4..e4e3c01b8cbc6676697730e8e5e524cbafc20748 100644 (file)
@@ -71,7 +71,7 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
 
 config DRM_I915_UMS
        bool "Enable userspace modesetting on Intel hardware (DEPRECATED)"
-       depends on DRM_I915
+       depends on DRM_I915 && BROKEN
        default n
        help
          Choose this option if you still need userspace modesetting.
index a0f5bdd694919a86206ab210e5eb30827d297232..80449f47596085406cb525fab2288c4489c2811e 100644 (file)
@@ -160,7 +160,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
-       };
+       }
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
index 0f1865d7d4d8412918e99cbf92841ba85d0ec5d8..0f2587ff347c9576581ab6d730099579196f8078 100644 (file)
@@ -195,7 +195,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
        if (i2c_transfer(adapter, msgs, 3) == 3) {
                *data = (in_buf[1] << 8) | in_buf[0];
                return true;
-       };
+       }
 
        if (!priv->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from "
index 8155ded79079dfdee1b513299a499efe054c20d4..74f2af7c2d3ed41688494a41b78e28390cf7c2b5 100644 (file)
@@ -121,7 +121,7 @@ static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
        if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
-       };
+       }
 
        if (!ns->quiet) {
                DRM_DEBUG_KMS
@@ -233,9 +233,8 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
                                              struct drm_display_mode *mode)
 {
        DRM_DEBUG_KMS
-           ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
-            __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
-            mode->vtotal);
+           ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
+            mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
 
        /*
         * Currently, these are all the modes I have data from.
@@ -261,9 +260,8 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
        struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
 
        DRM_DEBUG_KMS
-           ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
-            __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
-            mode->vtotal);
+           ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
+            mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
 
        /*
         * Where do I find the native resolution for which scaling is not required???
@@ -277,8 +275,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
                if (mode->hdisplay == 800 && mode->vdisplay == 600) {
                        /* mode 277 */
                        ns->reg_8_shadow &= ~NS2501_8_BPAS;
-                       DRM_DEBUG_KMS("%s: switching to 800x600\n",
-                                     __FUNCTION__);
+                       DRM_DEBUG_KMS("switching to 800x600\n");
 
                        /*
                         * No, I do not know where this data comes from.
@@ -341,8 +338,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
 
                } else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
                        /* mode 274 */
-                       DRM_DEBUG_KMS("%s: switching to 640x480\n",
-                                     __FUNCTION__);
+                       DRM_DEBUG_KMS("switching to 640x480\n");
                        /*
                         * No, I do not know where this data comes from.
                         * It is just what the video bios left in the DVO, so
@@ -406,8 +402,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
 
                } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) {
                        /* mode 280 */
-                       DRM_DEBUG_KMS("%s: switching to 1024x768\n",
-                                     __FUNCTION__);
+                       DRM_DEBUG_KMS("switching to 1024x768\n");
                        /*
                         * This might or might not work, actually. I'm silently
                         * assuming here that the native panel resolution is
@@ -458,8 +453,7 @@ static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
        struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
        unsigned char ch;
 
-       DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %i\n",
-                     __FUNCTION__, enable);
+       DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
 
        ch = ns->reg_8_shadow;
 
index 7b3e9e9362003461951dfa737809f8ac916db47e..fa011496707659a1e1439dad0297d2f920c34039 100644 (file)
@@ -93,7 +93,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
-       };
+       }
 
        if (!sil->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
index 12ea4b16469277d971f78a5b194079d67dcb7781..7853719a0e8132dc5af19dcdee0089f236ff2b45 100644 (file)
@@ -118,7 +118,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
-       };
+       }
 
        if (!tfp->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
index 4cf6d020d5135e3da688e5c1f586c362189b5629..69d34e47d3bc228517a01fc327719acc54d6f7ac 100644 (file)
@@ -28,7 +28,7 @@
 #include "i915_drv.h"
 
 /**
- * DOC: i915 batch buffer command parser
+ * DOC: batch buffer command parser
  *
  * Motivation:
  * Certain OpenGL features (e.g. transform feedback, performance monitoring)
  * general bitmasking mechanism.
  */
 
+#define STD_MI_OPCODE_MASK  0xFF800000
+#define STD_3D_OPCODE_MASK  0xFFFF0000
+#define STD_2D_OPCODE_MASK  0xFFC00000
+#define STD_MFX_OPCODE_MASK 0xFFFF0000
+
+#define CMD(op, opm, f, lm, fl, ...)                           \
+       {                                                       \
+               .flags = (fl) | ((f) ? CMD_DESC_FIXED : 0),     \
+               .cmd = { (op), (opm) },                         \
+               .length = { (lm) },                             \
+               __VA_ARGS__                                     \
+       }
+
+/* Convenience macros to compress the tables */
+#define SMI STD_MI_OPCODE_MASK
+#define S3D STD_3D_OPCODE_MASK
+#define S2D STD_2D_OPCODE_MASK
+#define SMFX STD_MFX_OPCODE_MASK
+#define F true
+#define S CMD_DESC_SKIP
+#define R CMD_DESC_REJECT
+#define W CMD_DESC_REGISTER
+#define B CMD_DESC_BITMASK
+#define M CMD_DESC_MASTER
+
+/*            Command                          Mask   Fixed Len   Action
+             ---------------------------------------------------------- */
+static const struct drm_i915_cmd_descriptor common_cmds[] = {
+       CMD(  MI_NOOP,                          SMI,    F,  1,      S  ),
+       CMD(  MI_USER_INTERRUPT,                SMI,    F,  1,      R  ),
+       CMD(  MI_WAIT_FOR_EVENT,                SMI,    F,  1,      M  ),
+       CMD(  MI_ARB_CHECK,                     SMI,    F,  1,      S  ),
+       CMD(  MI_REPORT_HEAD,                   SMI,    F,  1,      S  ),
+       CMD(  MI_SUSPEND_FLUSH,                 SMI,    F,  1,      S  ),
+       CMD(  MI_SEMAPHORE_MBOX,                SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_STORE_DWORD_INDEX,             SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_LOAD_REGISTER_IMM(1),          SMI,   !F,  0xFF,   W,
+             .reg = { .offset = 1, .mask = 0x007FFFFC }               ),
+       CMD(  MI_STORE_REGISTER_MEM(1),         SMI,   !F,  0xFF,   W | B,
+             .reg = { .offset = 1, .mask = 0x007FFFFC },
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_LOAD_REGISTER_MEM,             SMI,   !F,  0xFF,   W | B,
+             .reg = { .offset = 1, .mask = 0x007FFFFC },
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_BATCH_BUFFER_START,            SMI,   !F,  0xFF,   S  ),
+};
+
+static const struct drm_i915_cmd_descriptor render_cmds[] = {
+       CMD(  MI_FLUSH,                         SMI,    F,  1,      S  ),
+       CMD(  MI_ARB_ON_OFF,                    SMI,    F,  1,      R  ),
+       CMD(  MI_PREDICATE,                     SMI,    F,  1,      S  ),
+       CMD(  MI_TOPOLOGY_FILTER,               SMI,    F,  1,      S  ),
+       CMD(  MI_DISPLAY_FLIP,                  SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_SET_CONTEXT,                   SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_URB_CLEAR,                     SMI,   !F,  0xFF,   S  ),
+       CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0x3F,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_UPDATE_GTT,                    SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_CLFLUSH,                       SMI,   !F,  0x3FF,  B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_REPORT_PERF_COUNT,             SMI,   !F,  0x3F,   B,
+             .bits = {{
+                       .offset = 1,
+                       .mask = MI_REPORT_PERF_COUNT_GGTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_CONDITIONAL_BATCH_BUFFER_END,  SMI,   !F,  0xFF,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  GFX_OP_3DSTATE_VF_STATISTICS,     S3D,    F,  1,      S  ),
+       CMD(  PIPELINE_SELECT,                  S3D,    F,  1,      S  ),
+       CMD(  MEDIA_VFE_STATE,                  S3D,   !F,  0xFFFF, B,
+             .bits = {{
+                       .offset = 2,
+                       .mask = MEDIA_VFE_STATE_MMIO_ACCESS_MASK,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  GPGPU_OBJECT,                     S3D,   !F,  0xFF,   S  ),
+       CMD(  GPGPU_WALKER,                     S3D,   !F,  0xFF,   S  ),
+       CMD(  GFX_OP_3DSTATE_SO_DECL_LIST,      S3D,   !F,  0x1FF,  S  ),
+       CMD(  GFX_OP_PIPE_CONTROL(5),           S3D,   !F,  0xFF,   B,
+             .bits = {{
+                       .offset = 1,
+                       .mask = (PIPE_CONTROL_MMIO_WRITE | PIPE_CONTROL_NOTIFY),
+                       .expected = 0,
+             },
+             {
+                       .offset = 1,
+                       .mask = (PIPE_CONTROL_GLOBAL_GTT_IVB |
+                                PIPE_CONTROL_STORE_DATA_INDEX),
+                       .expected = 0,
+                       .condition_offset = 1,
+                       .condition_mask = PIPE_CONTROL_POST_SYNC_OP_MASK,
+             }},                                                      ),
+};
+
+static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = {
+       CMD(  MI_SET_PREDICATE,                 SMI,    F,  1,      S  ),
+       CMD(  MI_RS_CONTROL,                    SMI,    F,  1,      S  ),
+       CMD(  MI_URB_ATOMIC_ALLOC,              SMI,    F,  1,      S  ),
+       CMD(  MI_RS_CONTEXT,                    SMI,    F,  1,      S  ),
+       CMD(  MI_LOAD_SCAN_LINES_INCL,          SMI,   !F,  0x3F,   M  ),
+       CMD(  MI_LOAD_SCAN_LINES_EXCL,          SMI,   !F,  0x3F,   R  ),
+       CMD(  MI_LOAD_REGISTER_REG,             SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_RS_STORE_DATA_IMM,             SMI,   !F,  0xFF,   S  ),
+       CMD(  MI_LOAD_URB_MEM,                  SMI,   !F,  0xFF,   S  ),
+       CMD(  MI_STORE_URB_MEM,                 SMI,   !F,  0xFF,   S  ),
+       CMD(  GFX_OP_3DSTATE_DX9_CONSTANTF_VS,  S3D,   !F,  0x7FF,  S  ),
+       CMD(  GFX_OP_3DSTATE_DX9_CONSTANTF_PS,  S3D,   !F,  0x7FF,  S  ),
+
+       CMD(  GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS,  S3D,   !F,  0x1FF,  S  ),
+       CMD(  GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS,  S3D,   !F,  0x1FF,  S  ),
+       CMD(  GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS,  S3D,   !F,  0x1FF,  S  ),
+       CMD(  GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS,  S3D,   !F,  0x1FF,  S  ),
+       CMD(  GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS,  S3D,   !F,  0x1FF,  S  ),
+};
+
+static const struct drm_i915_cmd_descriptor video_cmds[] = {
+       CMD(  MI_ARB_ON_OFF,                    SMI,    F,  1,      R  ),
+       CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0xFF,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_UPDATE_GTT,                    SMI,   !F,  0x3F,   R  ),
+       CMD(  MI_FLUSH_DW,                      SMI,   !F,  0x3F,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_FLUSH_DW_NOTIFY,
+                       .expected = 0,
+             },
+             {
+                       .offset = 1,
+                       .mask = MI_FLUSH_DW_USE_GTT,
+                       .expected = 0,
+                       .condition_offset = 0,
+                       .condition_mask = MI_FLUSH_DW_OP_MASK,
+             },
+             {
+                       .offset = 0,
+                       .mask = MI_FLUSH_DW_STORE_INDEX,
+                       .expected = 0,
+                       .condition_offset = 0,
+                       .condition_mask = MI_FLUSH_DW_OP_MASK,
+             }},                                                      ),
+       CMD(  MI_CONDITIONAL_BATCH_BUFFER_END,  SMI,   !F,  0xFF,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       /*
+        * MFX_WAIT doesn't fit the way we handle length for most commands.
+        * It has a length field but it uses a non-standard length bias.
+        * It is always 1 dword though, so just treat it as fixed length.
+        */
+       CMD(  MFX_WAIT,                         SMFX,   F,  1,      S  ),
+};
+
+static const struct drm_i915_cmd_descriptor vecs_cmds[] = {
+       CMD(  MI_ARB_ON_OFF,                    SMI,    F,  1,      R  ),
+       CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0xFF,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_UPDATE_GTT,                    SMI,   !F,  0x3F,   R  ),
+       CMD(  MI_FLUSH_DW,                      SMI,   !F,  0x3F,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_FLUSH_DW_NOTIFY,
+                       .expected = 0,
+             },
+             {
+                       .offset = 1,
+                       .mask = MI_FLUSH_DW_USE_GTT,
+                       .expected = 0,
+                       .condition_offset = 0,
+                       .condition_mask = MI_FLUSH_DW_OP_MASK,
+             },
+             {
+                       .offset = 0,
+                       .mask = MI_FLUSH_DW_STORE_INDEX,
+                       .expected = 0,
+                       .condition_offset = 0,
+                       .condition_mask = MI_FLUSH_DW_OP_MASK,
+             }},                                                      ),
+       CMD(  MI_CONDITIONAL_BATCH_BUFFER_END,  SMI,   !F,  0xFF,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+};
+
+static const struct drm_i915_cmd_descriptor blt_cmds[] = {
+       CMD(  MI_DISPLAY_FLIP,                  SMI,   !F,  0xFF,   R  ),
+       CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0x3FF,  B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_GLOBAL_GTT,
+                       .expected = 0,
+             }},                                                      ),
+       CMD(  MI_UPDATE_GTT,                    SMI,   !F,  0x3F,   R  ),
+       CMD(  MI_FLUSH_DW,                      SMI,   !F,  0x3F,   B,
+             .bits = {{
+                       .offset = 0,
+                       .mask = MI_FLUSH_DW_NOTIFY,
+                       .expected = 0,
+             },
+             {
+                       .offset = 1,
+                       .mask = MI_FLUSH_DW_USE_GTT,
+                       .expected = 0,
+                       .condition_offset = 0,
+                       .condition_mask = MI_FLUSH_DW_OP_MASK,
+             },
+             {
+                       .offset = 0,
+                       .mask = MI_FLUSH_DW_STORE_INDEX,
+                       .expected = 0,
+                       .condition_offset = 0,
+                       .condition_mask = MI_FLUSH_DW_OP_MASK,
+             }},                                                      ),
+       CMD(  COLOR_BLT,                        S2D,   !F,  0x3F,   S  ),
+       CMD(  SRC_COPY_BLT,                     S2D,   !F,  0x3F,   S  ),
+};
+
+static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = {
+       CMD(  MI_LOAD_SCAN_LINES_INCL,          SMI,   !F,  0x3F,   M  ),
+       CMD(  MI_LOAD_SCAN_LINES_EXCL,          SMI,   !F,  0x3F,   R  ),
+};
+
+#undef CMD
+#undef SMI
+#undef S3D
+#undef S2D
+#undef SMFX
+#undef F
+#undef S
+#undef R
+#undef W
+#undef B
+#undef M
+
+static const struct drm_i915_cmd_table gen7_render_cmds[] = {
+       { common_cmds, ARRAY_SIZE(common_cmds) },
+       { render_cmds, ARRAY_SIZE(render_cmds) },
+};
+
+static const struct drm_i915_cmd_table hsw_render_ring_cmds[] = {
+       { common_cmds, ARRAY_SIZE(common_cmds) },
+       { render_cmds, ARRAY_SIZE(render_cmds) },
+       { hsw_render_cmds, ARRAY_SIZE(hsw_render_cmds) },
+};
+
+static const struct drm_i915_cmd_table gen7_video_cmds[] = {
+       { common_cmds, ARRAY_SIZE(common_cmds) },
+       { video_cmds, ARRAY_SIZE(video_cmds) },
+};
+
+static const struct drm_i915_cmd_table hsw_vebox_cmds[] = {
+       { common_cmds, ARRAY_SIZE(common_cmds) },
+       { vecs_cmds, ARRAY_SIZE(vecs_cmds) },
+};
+
+static const struct drm_i915_cmd_table gen7_blt_cmds[] = {
+       { common_cmds, ARRAY_SIZE(common_cmds) },
+       { blt_cmds, ARRAY_SIZE(blt_cmds) },
+};
+
+static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = {
+       { common_cmds, ARRAY_SIZE(common_cmds) },
+       { blt_cmds, ARRAY_SIZE(blt_cmds) },
+       { hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) },
+};
+
+/*
+ * Register whitelists, sorted by increasing register offset.
+ *
+ * Some registers that userspace accesses are 64 bits. The register
+ * access commands only allow 32-bit accesses. Hence, we have to include
+ * entries for both halves of the 64-bit registers.
+ */
+
+/* Convenience macro for adding 64-bit registers */
+#define REG64(addr) (addr), (addr + sizeof(u32))
+
+static const u32 gen7_render_regs[] = {
+       REG64(HS_INVOCATION_COUNT),
+       REG64(DS_INVOCATION_COUNT),
+       REG64(IA_VERTICES_COUNT),
+       REG64(IA_PRIMITIVES_COUNT),
+       REG64(VS_INVOCATION_COUNT),
+       REG64(GS_INVOCATION_COUNT),
+       REG64(GS_PRIMITIVES_COUNT),
+       REG64(CL_INVOCATION_COUNT),
+       REG64(CL_PRIMITIVES_COUNT),
+       REG64(PS_INVOCATION_COUNT),
+       REG64(PS_DEPTH_COUNT),
+       OACONTROL, /* Only allowed for LRI and SRM. See below. */
+       GEN7_3DPRIM_END_OFFSET,
+       GEN7_3DPRIM_START_VERTEX,
+       GEN7_3DPRIM_VERTEX_COUNT,
+       GEN7_3DPRIM_INSTANCE_COUNT,
+       GEN7_3DPRIM_START_INSTANCE,
+       GEN7_3DPRIM_BASE_VERTEX,
+       REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)),
+       REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)),
+       REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)),
+       REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)),
+       REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)),
+       REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)),
+       REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)),
+       REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)),
+       GEN7_SO_WRITE_OFFSET(0),
+       GEN7_SO_WRITE_OFFSET(1),
+       GEN7_SO_WRITE_OFFSET(2),
+       GEN7_SO_WRITE_OFFSET(3),
+};
+
+static const u32 gen7_blt_regs[] = {
+       BCS_SWCTRL,
+};
+
+static const u32 ivb_master_regs[] = {
+       FORCEWAKE_MT,
+       DERRMR,
+       GEN7_PIPE_DE_LOAD_SL(PIPE_A),
+       GEN7_PIPE_DE_LOAD_SL(PIPE_B),
+       GEN7_PIPE_DE_LOAD_SL(PIPE_C),
+};
+
+static const u32 hsw_master_regs[] = {
+       FORCEWAKE_MT,
+       DERRMR,
+};
+
+#undef REG64
+
 static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
 {
        u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
@@ -137,12 +498,13 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
        return 0;
 }
 
-static void validate_cmds_sorted(struct intel_ring_buffer *ring)
+static bool validate_cmds_sorted(struct intel_ring_buffer *ring)
 {
        int i;
+       bool ret = true;
 
        if (!ring->cmd_tables || ring->cmd_table_count == 0)
-               return;
+               return true;
 
        for (i = 0; i < ring->cmd_table_count; i++) {
                const struct drm_i915_cmd_table *table = &ring->cmd_tables[i];
@@ -154,35 +516,45 @@ static void validate_cmds_sorted(struct intel_ring_buffer *ring)
                                &table->table[i];
                        u32 curr = desc->cmd.value & desc->cmd.mask;
 
-                       if (curr < previous)
+                       if (curr < previous) {
                                DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n",
                                          ring->id, i, j, curr, previous);
+                               ret = false;
+                       }
 
                        previous = curr;
                }
        }
+
+       return ret;
 }
 
-static void check_sorted(int ring_id, const u32 *reg_table, int reg_count)
+static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count)
 {
        int i;
        u32 previous = 0;
+       bool ret = true;
 
        for (i = 0; i < reg_count; i++) {
                u32 curr = reg_table[i];
 
-               if (curr < previous)
+               if (curr < previous) {
                        DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n",
                                  ring_id, i, curr, previous);
+                       ret = false;
+               }
 
                previous = curr;
        }
+
+       return ret;
 }
 
-static void validate_regs_sorted(struct intel_ring_buffer *ring)
+static bool validate_regs_sorted(struct intel_ring_buffer *ring)
 {
-       check_sorted(ring->id, ring->reg_table, ring->reg_count);
-       check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count);
+       return check_sorted(ring->id, ring->reg_table, ring->reg_count) &&
+               check_sorted(ring->id, ring->master_reg_table,
+                            ring->master_reg_count);
 }
 
 /**
@@ -200,15 +572,58 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring)
 
        switch (ring->id) {
        case RCS:
+               if (IS_HASWELL(ring->dev)) {
+                       ring->cmd_tables = hsw_render_ring_cmds;
+                       ring->cmd_table_count =
+                               ARRAY_SIZE(hsw_render_ring_cmds);
+               } else {
+                       ring->cmd_tables = gen7_render_cmds;
+                       ring->cmd_table_count = ARRAY_SIZE(gen7_render_cmds);
+               }
+
+               ring->reg_table = gen7_render_regs;
+               ring->reg_count = ARRAY_SIZE(gen7_render_regs);
+
+               if (IS_HASWELL(ring->dev)) {
+                       ring->master_reg_table = hsw_master_regs;
+                       ring->master_reg_count = ARRAY_SIZE(hsw_master_regs);
+               } else {
+                       ring->master_reg_table = ivb_master_regs;
+                       ring->master_reg_count = ARRAY_SIZE(ivb_master_regs);
+               }
+
                ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
                break;
        case VCS:
+               ring->cmd_tables = gen7_video_cmds;
+               ring->cmd_table_count = ARRAY_SIZE(gen7_video_cmds);
                ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
                break;
        case BCS:
+               if (IS_HASWELL(ring->dev)) {
+                       ring->cmd_tables = hsw_blt_ring_cmds;
+                       ring->cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds);
+               } else {
+                       ring->cmd_tables = gen7_blt_cmds;
+                       ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds);
+               }
+
+               ring->reg_table = gen7_blt_regs;
+               ring->reg_count = ARRAY_SIZE(gen7_blt_regs);
+
+               if (IS_HASWELL(ring->dev)) {
+                       ring->master_reg_table = hsw_master_regs;
+                       ring->master_reg_count = ARRAY_SIZE(hsw_master_regs);
+               } else {
+                       ring->master_reg_table = ivb_master_regs;
+                       ring->master_reg_count = ARRAY_SIZE(ivb_master_regs);
+               }
+
                ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
                break;
        case VECS:
+               ring->cmd_tables = hsw_vebox_cmds;
+               ring->cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds);
                /* VECS can use the same length_mask function as VCS */
                ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
                break;
@@ -218,8 +633,8 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring)
                BUG();
        }
 
-       validate_cmds_sorted(ring);
-       validate_regs_sorted(ring);
+       BUG_ON(!validate_cmds_sorted(ring));
+       BUG_ON(!validate_regs_sorted(ring));
 }
 
 static const struct drm_i915_cmd_descriptor*
@@ -331,13 +746,111 @@ finish:
  */
 bool i915_needs_cmd_parser(struct intel_ring_buffer *ring)
 {
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
        /* No command tables indicates a platform without parsing */
        if (!ring->cmd_tables)
                return false;
 
+       /*
+        * XXX: VLV is Gen7 and therefore has cmd_tables, but has PPGTT
+        * disabled. That will cause all of the parser's PPGTT checks to
+        * fail. For now, disable parsing when PPGTT is off.
+        */
+       if (!dev_priv->mm.aliasing_ppgtt)
+               return false;
+
        return (i915.enable_cmd_parser == 1);
 }
 
+static bool check_cmd(const struct intel_ring_buffer *ring,
+                     const struct drm_i915_cmd_descriptor *desc,
+                     const u32 *cmd,
+                     const bool is_master,
+                     bool *oacontrol_set)
+{
+       if (desc->flags & CMD_DESC_REJECT) {
+               DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd);
+               return false;
+       }
+
+       if ((desc->flags & CMD_DESC_MASTER) && !is_master) {
+               DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n",
+                                *cmd);
+               return false;
+       }
+
+       if (desc->flags & CMD_DESC_REGISTER) {
+               u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask;
+
+               /*
+                * OACONTROL requires some special handling for writes. We
+                * want to make sure that any batch which enables OA also
+                * disables it before the end of the batch. The goal is to
+                * prevent one process from snooping on the perf data from
+                * another process. To do that, we need to check the value
+                * that will be written to the register. Hence, limit
+                * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands.
+                */
+               if (reg_addr == OACONTROL) {
+                       if (desc->cmd.value == MI_LOAD_REGISTER_MEM)
+                               return false;
+
+                       if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1))
+                               *oacontrol_set = (cmd[2] != 0);
+               }
+
+               if (!valid_reg(ring->reg_table,
+                              ring->reg_count, reg_addr)) {
+                       if (!is_master ||
+                           !valid_reg(ring->master_reg_table,
+                                      ring->master_reg_count,
+                                      reg_addr)) {
+                               DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n",
+                                                reg_addr,
+                                                *cmd,
+                                                ring->id);
+                               return false;
+                       }
+               }
+       }
+
+       if (desc->flags & CMD_DESC_BITMASK) {
+               int i;
+
+               for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) {
+                       u32 dword;
+
+                       if (desc->bits[i].mask == 0)
+                               break;
+
+                       if (desc->bits[i].condition_mask != 0) {
+                               u32 offset =
+                                       desc->bits[i].condition_offset;
+                               u32 condition = cmd[offset] &
+                                       desc->bits[i].condition_mask;
+
+                               if (condition == 0)
+                                       continue;
+                       }
+
+                       dword = cmd[desc->bits[i].offset] &
+                               desc->bits[i].mask;
+
+                       if (dword != desc->bits[i].expected) {
+                               DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n",
+                                                *cmd,
+                                                desc->bits[i].mask,
+                                                desc->bits[i].expected,
+                                                dword, ring->id);
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
 #define LENGTH_BIAS 2
 
 /**
@@ -361,6 +874,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring,
        u32 *cmd, *batch_base, *batch_end;
        struct drm_i915_cmd_descriptor default_desc = { 0 };
        int needs_clflush = 0;
+       bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
 
        ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush);
        if (ret) {
@@ -402,76 +916,27 @@ int i915_parse_cmds(struct intel_ring_buffer *ring,
                        length = ((*cmd & desc->length.mask) + LENGTH_BIAS);
 
                if ((batch_end - cmd) < length) {
-                       DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n",
+                       DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n",
                                         *cmd,
                                         length,
-                                        (unsigned long)(batch_end - cmd));
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (desc->flags & CMD_DESC_REJECT) {
-                       DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd);
+                                        batch_end - cmd);
                        ret = -EINVAL;
                        break;
                }
 
-               if ((desc->flags & CMD_DESC_MASTER) && !is_master) {
-                       DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n",
-                                        *cmd);
+               if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) {
                        ret = -EINVAL;
                        break;
                }
 
-               if (desc->flags & CMD_DESC_REGISTER) {
-                       u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask;
-
-                       if (!valid_reg(ring->reg_table,
-                                      ring->reg_count, reg_addr)) {
-                               if (!is_master ||
-                                   !valid_reg(ring->master_reg_table,
-                                              ring->master_reg_count,
-                                              reg_addr)) {
-                                       DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n",
-                                                        reg_addr,
-                                                        *cmd,
-                                                        ring->id);
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       }
-               }
-
-               if (desc->flags & CMD_DESC_BITMASK) {
-                       int i;
-
-                       for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) {
-                               u32 dword;
-
-                               if (desc->bits[i].mask == 0)
-                                       break;
-
-                               dword = cmd[desc->bits[i].offset] &
-                                       desc->bits[i].mask;
-
-                               if (dword != desc->bits[i].expected) {
-                                       DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n",
-                                                        *cmd,
-                                                        desc->bits[i].mask,
-                                                        desc->bits[i].expected,
-                                                        dword, ring->id);
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       }
-
-                       if (ret)
-                               break;
-               }
-
                cmd += length;
        }
 
+       if (oacontrol_set) {
+               DRM_DEBUG_DRIVER("CMD: batch set OACONTROL but did not clear it\n");
+               ret = -EINVAL;
+       }
+
        if (cmd >= batch_end) {
                DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n");
                ret = -EINVAL;
@@ -483,3 +948,22 @@ int i915_parse_cmds(struct intel_ring_buffer *ring,
 
        return ret;
 }
+
+/**
+ * i915_cmd_parser_get_version() - get the cmd parser version number
+ *
+ * The cmd parser maintains a simple increasing integer version number suitable
+ * for passing to userspace clients to determine what operations are permitted.
+ *
+ * Return: the current version number of the cmd parser
+ */
+int i915_cmd_parser_get_version(void)
+{
+       /*
+        * Command parser version history
+        *
+        * 1. Initial version. Checks batches and reports violations, but leaves
+        *    hardware parsing enabled (so does not allow new use cases).
+        */
+       return 1;
+}
index 195fe5bc0aacf56306ae01e87ed67660c0328646..18b3565f431a032ed6733c42649f5cc0f3c16f9f 100644 (file)
@@ -966,7 +966,7 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused)
        return 0;
 }
 
-static int i915_cur_delayinfo(struct seq_file *m, void *unused)
+static int i915_frequency_info(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
@@ -991,6 +991,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 rpmodectl, rpinclimit, rpdeclimit;
                u32 rpstat, cagf, reqf;
                u32 rpupei, rpcurup, rpprevup;
                u32 rpdownei, rpcurdown, rpprevdown;
@@ -1011,6 +1012,10 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                        reqf >>= 25;
                reqf *= GT_FREQUENCY_MULTIPLIER;
 
+               rpmodectl = I915_READ(GEN6_RP_CONTROL);
+               rpinclimit = I915_READ(GEN6_RP_UP_THRESHOLD);
+               rpdeclimit = I915_READ(GEN6_RP_DOWN_THRESHOLD);
+
                rpstat = I915_READ(GEN6_RPSTAT1);
                rpupei = I915_READ(GEN6_RP_CUR_UP_EI);
                rpcurup = I915_READ(GEN6_RP_CUR_UP);
@@ -1027,14 +1032,23 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
                mutex_unlock(&dev->struct_mutex);
 
+               seq_printf(m, "PM IER=0x%08x IMR=0x%08x ISR=0x%08x IIR=0x%08x, MASK=0x%08x\n",
+                          I915_READ(GEN6_PMIER),
+                          I915_READ(GEN6_PMIMR),
+                          I915_READ(GEN6_PMISR),
+                          I915_READ(GEN6_PMIIR),
+                          I915_READ(GEN6_PMINTRMSK));
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
-               seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat);
                seq_printf(m, "Render p-state ratio: %d\n",
                           (gt_perf_status & 0xff00) >> 8);
                seq_printf(m, "Render p-state VID: %d\n",
                           gt_perf_status & 0xff);
                seq_printf(m, "Render p-state limit: %d\n",
                           rp_state_limits & 0xff);
+               seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat);
+               seq_printf(m, "RPMODECTL: 0x%08x\n", rpmodectl);
+               seq_printf(m, "RPINCLIMIT: 0x%08x\n", rpinclimit);
+               seq_printf(m, "RPDECLIMIT: 0x%08x\n", rpdeclimit);
                seq_printf(m, "RPNSWREQ: %dMHz\n", reqf);
                seq_printf(m, "CAGF: %dMHz\n", cagf);
                seq_printf(m, "RP CUR UP EI: %dus\n", rpupei &
@@ -1225,9 +1239,13 @@ static int vlv_drpc_info(struct seq_file *m)
        u32 rpmodectl1, rcctl1;
        unsigned fw_rendercount = 0, fw_mediacount = 0;
 
+       intel_runtime_pm_get(dev_priv);
+
        rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
        rcctl1 = I915_READ(GEN6_RC_CONTROL);
 
+       intel_runtime_pm_put(dev_priv);
+
        seq_printf(m, "Video Turbo Mode: %s\n",
                   yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO));
        seq_printf(m, "Turbo enabled: %s\n",
@@ -1247,6 +1265,11 @@ static int vlv_drpc_info(struct seq_file *m)
                        (I915_READ(VLV_GTLC_PW_STATUS) &
                                VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down");
 
+       seq_printf(m, "Render RC6 residency since boot: %u\n",
+                  I915_READ(VLV_GT_RENDER_RC6));
+       seq_printf(m, "Media RC6 residency since boot: %u\n",
+                  I915_READ(VLV_GT_MEDIA_RC6));
+
        spin_lock_irq(&dev_priv->uncore.lock);
        fw_rendercount = dev_priv->uncore.fw_rendercount;
        fw_mediacount = dev_priv->uncore.fw_mediacount;
@@ -1675,6 +1698,9 @@ static int i915_context_status(struct seq_file *m, void *unused)
        }
 
        list_for_each_entry(ctx, &dev_priv->context_list, link) {
+               if (ctx->obj == NULL)
+                       continue;
+
                seq_puts(m, "HW context ");
                describe_ctx(m, ctx);
                for_each_ring(ring, dev_priv, i)
@@ -1816,8 +1842,7 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
                        u64 pdp = I915_READ(ring->mmio_base + offset + 4);
                        pdp <<= 32;
                        pdp |= I915_READ(ring->mmio_base + offset);
-                       for (i = 0; i < 4; i++)
-                               seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp);
+                       seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp);
                }
        }
 }
@@ -1885,53 +1910,6 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static int i915_dpio_info(struct seq_file *m, void *data)
-{
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
-
-
-       if (!IS_VALLEYVIEW(dev)) {
-               seq_puts(m, "unsupported\n");
-               return 0;
-       }
-
-       ret = mutex_lock_interruptible(&dev_priv->dpio_lock);
-       if (ret)
-               return ret;
-
-       seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
-
-       seq_printf(m, "DPIO PLL DW3 CH0 : 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(0)));
-       seq_printf(m, "DPIO PLL DW3 CH1: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(1)));
-
-       seq_printf(m, "DPIO PLL DW5 CH0: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(0)));
-       seq_printf(m, "DPIO PLL DW5 CH1: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(1)));
-
-       seq_printf(m, "DPIO PLL DW7 CH0: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(0)));
-       seq_printf(m, "DPIO PLL DW7 CH1: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(1)));
-
-       seq_printf(m, "DPIO PLL DW10 CH0: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(0)));
-       seq_printf(m, "DPIO PLL DW10 CH1: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(1)));
-
-       seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, VLV_CMN_DW0));
-
-       mutex_unlock(&dev_priv->dpio_lock);
-
-       return 0;
-}
-
 static int i915_llc(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -2044,7 +2022,7 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
        struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (!IS_HASWELL(dev)) {
+       if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
                seq_puts(m, "not supported\n");
                return 0;
        }
@@ -3286,9 +3264,15 @@ static int
 i915_wedged_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_runtime_pm_get(dev_priv);
 
        i915_handle_error(dev, val,
                          "Manually setting wedged to %llu", val);
+
+       intel_runtime_pm_put(dev_priv);
+
        return 0;
 }
 
@@ -3774,7 +3758,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
        {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
        {"i915_rstdby_delays", i915_rstdby_delays, 0},
-       {"i915_cur_delayinfo", i915_cur_delayinfo, 0},
+       {"i915_frequency_info", i915_frequency_info, 0},
        {"i915_delayfreq_table", i915_delayfreq_table, 0},
        {"i915_inttoext_table", i915_inttoext_table, 0},
        {"i915_drpc_info", i915_drpc_info, 0},
@@ -3790,7 +3774,6 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
        {"i915_swizzle_info", i915_swizzle_info, 0},
        {"i915_ppgtt_info", i915_ppgtt_info, 0},
-       {"i915_dpio", i915_dpio_info, 0},
        {"i915_llc", i915_llc, 0},
        {"i915_edp_psr_status", i915_edp_psr_status, 0},
        {"i915_sink_crc_eDP1", i915_sink_crc, 0},
index 96177eec0a0eb9a879493a54c79b3613f0bb9b34..d02c8de4bd6c5b49a8675016d6b046c6d6f31b66 100644 (file)
@@ -1017,6 +1017,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_EXEC_HANDLE_LUT:
                value = 1;
                break;
+       case I915_PARAM_CMD_PARSER_VERSION:
+               value = i915_cmd_parser_get_version();
+               break;
        default:
                DRM_DEBUG("Unknown parameter %d\n", param->param);
                return -EINVAL;
@@ -1277,12 +1280,13 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
 static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
-       bool can_switch;
 
-       spin_lock(&dev->count_lock);
-       can_switch = (dev->open_count == 0);
-       spin_unlock(&dev->count_lock);
-       return can_switch;
+       /*
+        * FIXME: open_count is protected by drm_global_mutex but that would lead to
+        * locking inversion with the driver load path. And the access here is
+        * completely racy anyway. So don't bother with locking for now.
+        */
+       return dev->open_count == 0;
 }
 
 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
@@ -1326,7 +1330,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        intel_power_domains_init_hw(dev_priv);
 
-       ret = drm_irq_install(dev);
+       ret = drm_irq_install(dev, dev->pdev->irq);
        if (ret)
                goto cleanup_gem_stolen;
 
@@ -1336,7 +1340,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        ret = i915_gem_init(dev);
        if (ret)
-               goto cleanup_power;
+               goto cleanup_irq;
 
        INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);
 
@@ -1345,10 +1349,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
        /* Always safe in the mode setting case. */
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = true;
-       if (INTEL_INFO(dev)->num_pipes == 0) {
-               intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
+       if (INTEL_INFO(dev)->num_pipes == 0)
                return 0;
-       }
 
        ret = intel_fbdev_init(dev);
        if (ret)
@@ -1383,8 +1385,7 @@ cleanup_gem:
        mutex_unlock(&dev->struct_mutex);
        WARN_ON(dev_priv->mm.aliasing_ppgtt);
        drm_mm_takedown(&dev_priv->gtt.base.mm);
-cleanup_power:
-       intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
+cleanup_irq:
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
        i915_gem_cleanup_stolen(dev);
@@ -1569,6 +1570,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        spin_lock_init(&dev_priv->backlight_lock);
        spin_lock_init(&dev_priv->uncore.lock);
        spin_lock_init(&dev_priv->mm.object_stat_lock);
+       dev_priv->ring_index = 0;
        mutex_init(&dev_priv->dpio_lock);
        mutex_init(&dev_priv->modeset_restore_lock);
 
@@ -1926,6 +1928,8 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
 
+       if (file_priv && file_priv->bsd_ring)
+               file_priv->bsd_ring = NULL;
        kfree(file_priv);
 }
 
index 82f4d1f47d3b734c582b1d2b02b770039fb042fa..208e185c16a9932d3537177c8d537052763a7a1d 100644 (file)
@@ -279,6 +279,26 @@ static const struct intel_device_info intel_broadwell_m_info = {
        GEN_DEFAULT_PIPEOFFSETS,
 };
 
+static const struct intel_device_info intel_broadwell_gt3d_info = {
+       .gen = 8, .num_pipes = 3,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
+       .has_llc = 1,
+       .has_ddi = 1,
+       .has_fbc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
+};
+
+static const struct intel_device_info intel_broadwell_gt3m_info = {
+       .gen = 8, .is_mobile = 1, .num_pipes = 3,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
+       .has_llc = 1,
+       .has_ddi = 1,
+       .has_fbc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
+};
+
 /*
  * Make sure any device matches here are from most specific to most
  * general.  For example, since the Quanta match is based on the subsystem
@@ -311,8 +331,10 @@ static const struct intel_device_info intel_broadwell_m_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),      \
-       INTEL_BDW_M_IDS(&intel_broadwell_m_info),       \
-       INTEL_BDW_D_IDS(&intel_broadwell_d_info)
+       INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),   \
+       INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),   \
+       INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \
+       INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info)
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
        INTEL_PCI_IDS,
@@ -551,7 +573,6 @@ static int i915_drm_thaw_early(struct drm_device *dev)
 static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int error = 0;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET) &&
            restore_gtt_mappings) {
@@ -569,12 +590,14 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
                drm_mode_config_reset(dev);
 
                mutex_lock(&dev->struct_mutex);
-
-               error = i915_gem_init_hw(dev);
+               if (i915_gem_init_hw(dev)) {
+                       DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
+                       atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
+               }
                mutex_unlock(&dev->struct_mutex);
 
                /* We need working interrupts for modeset enabling ... */
-               drm_irq_install(dev);
+               drm_irq_install(dev, dev->pdev->irq);
 
                intel_modeset_init_hw(dev);
 
@@ -613,7 +636,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
        mutex_unlock(&dev_priv->modeset_restore_lock);
 
        intel_runtime_pm_put(dev_priv);
-       return error;
+       return 0;
 }
 
 static int i915_drm_thaw(struct drm_device *dev)
@@ -746,18 +769,20 @@ int i915_reset(struct drm_device *dev)
                        return ret;
                }
 
+               /*
+                * FIXME: This is horribly race against concurrent pageflip and
+                * vblank wait ioctls since they can observe dev->irqs_disabled
+                * being false when they shouldn't be able to.
+                */
                drm_irq_uninstall(dev);
-               drm_irq_install(dev);
+               drm_irq_install(dev, dev->pdev->irq);
 
                /* rps/rc6 re-init is necessary to restore state lost after the
                 * reset and the re-install of drm irq. Skip for ironlake per
                 * previous concerns that it doesn't respond well to some forms
                 * of re-init after reset. */
-               if (INTEL_INFO(dev)->gen > 5) {
-                       mutex_lock(&dev->struct_mutex);
-                       intel_enable_gt_powersave(dev);
-                       mutex_unlock(&dev->struct_mutex);
-               }
+               if (INTEL_INFO(dev)->gen > 5)
+                       intel_reset_gt_powersave(dev);
 
                intel_hpd_init(dev);
        } else {
@@ -891,19 +916,88 @@ static int i915_pm_poweroff(struct device *dev)
        return i915_drm_freeze(drm_dev);
 }
 
-static int i915_runtime_suspend(struct device *device)
+static void hsw_runtime_suspend(struct drm_i915_private *dev_priv)
+{
+       hsw_enable_pc8(dev_priv);
+}
+
+static void snb_runtime_resume(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       intel_init_pch_refclk(dev);
+}
+
+static void hsw_runtime_resume(struct drm_i915_private *dev_priv)
+{
+       hsw_disable_pc8(dev_priv);
+}
+
+int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on)
+{
+       u32 val;
+       int err;
+
+       val = I915_READ(VLV_GTLC_SURVIVABILITY_REG);
+       WARN_ON(!!(val & VLV_GFX_CLK_FORCE_ON_BIT) == force_on);
+
+#define COND (I915_READ(VLV_GTLC_SURVIVABILITY_REG) & VLV_GFX_CLK_STATUS_BIT)
+       /* Wait for a previous force-off to settle */
+       if (force_on) {
+               err = wait_for(!COND, 20);
+               if (err) {
+                       DRM_ERROR("timeout waiting for GFX clock force-off (%08x)\n",
+                                 I915_READ(VLV_GTLC_SURVIVABILITY_REG));
+                       return err;
+               }
+       }
+
+       val = I915_READ(VLV_GTLC_SURVIVABILITY_REG);
+       val &= ~VLV_GFX_CLK_FORCE_ON_BIT;
+       if (force_on)
+               val |= VLV_GFX_CLK_FORCE_ON_BIT;
+       I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, val);
+
+       if (!force_on)
+               return 0;
+
+       err = wait_for(COND, 20);
+       if (err)
+               DRM_ERROR("timeout waiting for GFX clock force-on (%08x)\n",
+                         I915_READ(VLV_GTLC_SURVIVABILITY_REG));
+
+       return err;
+#undef COND
+}
+
+static int intel_runtime_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (WARN_ON_ONCE(!(dev_priv->rps.enabled && intel_enable_rc6(dev))))
+               return -ENODEV;
+
        WARN_ON(!HAS_RUNTIME_PM(dev));
        assert_force_wake_inactive(dev_priv);
 
        DRM_DEBUG_KMS("Suspending device\n");
 
-       if (HAS_PC8(dev))
-               hsw_enable_pc8(dev_priv);
+       /*
+        * rps.work can't be rearmed here, since we get here only after making
+        * sure the GPU is idle and the RPS freq is set to the minimum. See
+        * intel_mark_idle().
+        */
+       cancel_work_sync(&dev_priv->rps.work);
+       intel_runtime_pm_disable_interrupts(dev);
+
+       if (IS_GEN6(dev))
+               ;
+       else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               hsw_runtime_suspend(dev_priv);
+       else
+               WARN_ON(1);
 
        i915_gem_release_all_mmaps(dev_priv);
 
@@ -923,7 +1017,7 @@ static int i915_runtime_suspend(struct device *device)
        return 0;
 }
 
-static int i915_runtime_resume(struct device *device)
+static int intel_runtime_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct drm_device *dev = pci_get_drvdata(pdev);
@@ -936,8 +1030,18 @@ static int i915_runtime_resume(struct device *device)
        intel_opregion_notify_adapter(dev, PCI_D0);
        dev_priv->pm.suspended = false;
 
-       if (HAS_PC8(dev))
-               hsw_disable_pc8(dev_priv);
+       if (IS_GEN6(dev))
+               snb_runtime_resume(dev_priv);
+       else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               hsw_runtime_resume(dev_priv);
+       else
+               WARN_ON(1);
+
+       i915_gem_init_swizzling(dev);
+       gen6_update_ring_freq(dev);
+
+       intel_runtime_pm_restore_interrupts(dev);
+       intel_reset_gt_powersave(dev);
 
        DRM_DEBUG_KMS("Device resumed\n");
        return 0;
@@ -954,8 +1058,8 @@ static const struct dev_pm_ops i915_pm_ops = {
        .poweroff = i915_pm_poweroff,
        .restore_early = i915_pm_resume_early,
        .restore = i915_pm_resume,
-       .runtime_suspend = i915_runtime_suspend,
-       .runtime_resume = i915_runtime_resume,
+       .runtime_suspend = intel_runtime_suspend,
+       .runtime_resume = intel_runtime_resume,
 };
 
 static const struct vm_operations_struct i915_gem_vm_ops = {
index ec82f6bff1225dc06e5b591838c59778f65cecb5..3fc2e3d7113657722eadeda090d84e65dd7d21e8 100644 (file)
@@ -35,6 +35,7 @@
 #include "i915_reg.h"
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
+#include "i915_gem_gtt.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -324,7 +325,6 @@ struct drm_i915_error_state {
        u32 gab_ctl;
        u32 gfx_mode;
        u32 extra_instdone[I915_NUM_INSTDONE_REG];
-       u32 pipestat[I915_MAX_PIPES];
        u64 fence[I915_MAX_NUM_FENCES];
        struct intel_overlay_error_state *overlay;
        struct intel_display_error_state *display;
@@ -358,7 +358,7 @@ struct drm_i915_error_state {
                u64 bbaddr;
                u64 acthd;
                u32 fault_reg;
-               u32 faddr;
+               u64 faddr;
                u32 rc_psmi; /* sleep state */
                u32 semaphore_mboxes[I915_NUM_RINGS - 1];
 
@@ -572,168 +572,6 @@ enum i915_cache_level {
        I915_CACHE_WT, /* hsw:gt3e WriteThrough for scanouts */
 };
 
-typedef uint32_t gen6_gtt_pte_t;
-
-/**
- * A VMA represents a GEM BO that is bound into an address space. Therefore, a
- * VMA's presence cannot be guaranteed before binding, or after unbinding the
- * object into/from the address space.
- *
- * To make things as simple as possible (ie. no refcounting), a VMA's lifetime
- * will always be <= an objects lifetime. So object refcounting should cover us.
- */
-struct i915_vma {
-       struct drm_mm_node node;
-       struct drm_i915_gem_object *obj;
-       struct i915_address_space *vm;
-
-       /** This object's place on the active/inactive lists */
-       struct list_head mm_list;
-
-       struct list_head vma_link; /* Link in the object's VMA list */
-
-       /** This vma's place in the batchbuffer or on the eviction list */
-       struct list_head exec_list;
-
-       /**
-        * Used for performing relocations during execbuffer insertion.
-        */
-       struct hlist_node exec_node;
-       unsigned long exec_handle;
-       struct drm_i915_gem_exec_object2 *exec_entry;
-
-       /**
-        * How many users have pinned this object in GTT space. The following
-        * users can each hold at most one reference: pwrite/pread, pin_ioctl
-        * (via user_pin_count), execbuffer (objects are not allowed multiple
-        * times for the same batchbuffer), and the framebuffer code. When
-        * switching/pageflipping, the framebuffer code has at most two buffers
-        * pinned per crtc.
-        *
-        * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
-        * bits with absolutely no headroom. So use 4 bits. */
-       unsigned int pin_count:4;
-#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
-
-       /** Unmap an object from an address space. This usually consists of
-        * setting the valid PTE entries to a reserved scratch page. */
-       void (*unbind_vma)(struct i915_vma *vma);
-       /* Map an object into an address space with the given cache flags. */
-#define GLOBAL_BIND (1<<0)
-       void (*bind_vma)(struct i915_vma *vma,
-                        enum i915_cache_level cache_level,
-                        u32 flags);
-};
-
-struct i915_address_space {
-       struct drm_mm mm;
-       struct drm_device *dev;
-       struct list_head global_link;
-       unsigned long start;            /* Start offset always 0 for dri2 */
-       size_t total;           /* size addr space maps (ex. 2GB for ggtt) */
-
-       struct {
-               dma_addr_t addr;
-               struct page *page;
-       } scratch;
-
-       /**
-        * List of objects currently involved in rendering.
-        *
-        * Includes buffers having the contents of their GPU caches
-        * flushed, not necessarily primitives.  last_rendering_seqno
-        * represents when the rendering involved will be completed.
-        *
-        * A reference is held on the buffer while on this list.
-        */
-       struct list_head active_list;
-
-       /**
-        * LRU list of objects which are not in the ringbuffer and
-        * are ready to unbind, but are still in the GTT.
-        *
-        * last_rendering_seqno is 0 while an object is in this list.
-        *
-        * A reference is not held on the buffer while on this list,
-        * as merely being GTT-bound shouldn't prevent its being
-        * freed, and we'll pull it off the list in the free path.
-        */
-       struct list_head inactive_list;
-
-       /* FIXME: Need a more generic return type */
-       gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
-                                    enum i915_cache_level level,
-                                    bool valid); /* Create a valid PTE */
-       void (*clear_range)(struct i915_address_space *vm,
-                           uint64_t start,
-                           uint64_t length,
-                           bool use_scratch);
-       void (*insert_entries)(struct i915_address_space *vm,
-                              struct sg_table *st,
-                              uint64_t start,
-                              enum i915_cache_level cache_level);
-       void (*cleanup)(struct i915_address_space *vm);
-};
-
-/* The Graphics Translation Table is the way in which GEN hardware translates a
- * Graphics Virtual Address into a Physical Address. In addition to the normal
- * collateral associated with any va->pa translations GEN hardware also has a
- * portion of the GTT which can be mapped by the CPU and remain both coherent
- * and correct (in cases like swizzling). That region is referred to as GMADR in
- * the spec.
- */
-struct i915_gtt {
-       struct i915_address_space base;
-       size_t stolen_size;             /* Total size of stolen memory */
-
-       unsigned long mappable_end;     /* End offset that we can CPU map */
-       struct io_mapping *mappable;    /* Mapping to our CPU mappable region */
-       phys_addr_t mappable_base;      /* PA of our GMADR */
-
-       /** "Graphics Stolen Memory" holds the global PTEs */
-       void __iomem *gsm;
-
-       bool do_idle_maps;
-
-       int mtrr;
-
-       /* global gtt ops */
-       int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total,
-                         size_t *stolen, phys_addr_t *mappable_base,
-                         unsigned long *mappable_end);
-};
-#define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
-
-#define GEN8_LEGACY_PDPS 4
-struct i915_hw_ppgtt {
-       struct i915_address_space base;
-       struct kref ref;
-       struct drm_mm_node node;
-       unsigned num_pd_entries;
-       unsigned num_pd_pages; /* gen8+ */
-       union {
-               struct page **pt_pages;
-               struct page **gen8_pt_pages[GEN8_LEGACY_PDPS];
-       };
-       struct page *pd_pages;
-       union {
-               uint32_t pd_offset;
-               dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS];
-       };
-       union {
-               dma_addr_t *pt_dma_addr;
-               dma_addr_t *gen8_pt_dma_addr[4];
-       };
-
-       struct i915_hw_context *ctx;
-
-       int (*enable)(struct i915_hw_ppgtt *ppgtt);
-       int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
-                        struct intel_ring_buffer *ring,
-                        bool synchronous);
-       void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
-};
-
 struct i915_ctx_hang_stats {
        /* This context had batch pending when hang was declared */
        unsigned batch_pending;
@@ -794,6 +632,10 @@ struct i915_fbc {
        } no_fbc_reason;
 };
 
+struct i915_drrs {
+       struct intel_connector *connector;
+};
+
 struct i915_psr {
        bool sink_support;
        bool source_ok;
@@ -1086,6 +928,7 @@ struct i915_power_domains {
         * time are on. They are kept on until after the first modeset.
         */
        bool init_power_on;
+       bool initializing;
        int power_well_count;
 
        struct mutex lock;
@@ -1260,8 +1103,12 @@ struct i915_gpu_error {
         */
        wait_queue_head_t reset_queue;
 
-       /* For gpu hang simulation. */
-       unsigned int stop_rings;
+       /* Userspace knobs for gpu hang simulation;
+        * combines both a ring mask, and extra flags
+        */
+       u32 stop_rings;
+#define I915_STOP_RING_ALLOW_BAN       (1 << 31)
+#define I915_STOP_RING_ALLOW_WARN      (1 << 30)
 
        /* For missed irq/seqno simulation. */
        unsigned int test_irq_rings;
@@ -1281,6 +1128,12 @@ struct ddi_vbt_port_info {
        uint8_t supports_dp:1;
 };
 
+enum drrs_support_type {
+       DRRS_NOT_SUPPORTED = 0,
+       STATIC_DRRS_SUPPORT = 1,
+       SEAMLESS_DRRS_SUPPORT = 2
+};
+
 struct intel_vbt_data {
        struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
        struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -1296,6 +1149,8 @@ struct intel_vbt_data {
        int lvds_ssc_freq;
        unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
 
+       enum drrs_support_type drrs_type;
+
        /* eDP */
        int edp_rate;
        int edp_lanes;
@@ -1315,6 +1170,12 @@ struct intel_vbt_data {
        /* MIPI DSI */
        struct {
                u16 panel_id;
+               struct mipi_config *config;
+               struct mipi_pps_data *pps;
+               u8 seq_version;
+               u32 size;
+               u8 *data;
+               u8 *sequence[MIPI_SEQ_MAX];
        } dsi;
 
        int crt_ddc_pin;
@@ -1366,23 +1227,13 @@ struct ilk_wm_values {
  * goes back to false exactly before we reenable the IRQs. We use this variable
  * to check if someone is trying to enable/disable IRQs while they're supposed
  * to be disabled. This shouldn't happen and we'll print some error messages in
- * case it happens, but if it actually happens we'll also update the variables
- * inside struct regsave so when we restore the IRQs they will contain the
- * latest expected values.
+ * case it happens.
  *
  * For more, read the Documentation/power/runtime_pm.txt.
  */
 struct i915_runtime_pm {
        bool suspended;
        bool irqs_disabled;
-
-       struct {
-               uint32_t deimr;
-               uint32_t sdeimr;
-               uint32_t gtimr;
-               uint32_t gtier;
-               uint32_t gen6_pmimr;
-       } regsave;
 };
 
 enum intel_pipe_crc_source {
@@ -1415,7 +1266,7 @@ struct intel_pipe_crc {
        wait_queue_head_t wq;
 };
 
-typedef struct drm_i915_private {
+struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *slab;
 
@@ -1484,6 +1335,7 @@ typedef struct drm_i915_private {
        struct timer_list hotplug_reenable_timer;
 
        struct i915_fbc fbc;
+       struct i915_drrs drrs;
        struct intel_opregion opregion;
        struct intel_vbt_data vbt;
 
@@ -1501,6 +1353,7 @@ typedef struct drm_i915_private {
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
 
        unsigned int fsb_freq, mem_freq, is_ddr3;
+       unsigned int vlv_cdclk_freq;
 
        /**
         * wq - Driver workqueue for GEM.
@@ -1524,7 +1377,7 @@ typedef struct drm_i915_private {
        struct mutex modeset_restore_lock;
 
        struct list_head vm_list; /* Global list of all address spaces */
-       struct i915_gtt gtt; /* VMA representing the global address space */
+       struct i915_gtt gtt; /* VM representing the global address space */
 
        struct i915_gem_mm mm;
 
@@ -1620,7 +1473,9 @@ typedef struct drm_i915_private {
        struct i915_dri1_state dri1;
        /* Old ums support infrastructure, same warning applies. */
        struct i915_ums_state ums;
-} drm_i915_private_t;
+       /* the indicator for dispatch video commands on two BSD rings */
+       int ring_index;
+};
 
 static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
 {
@@ -1827,6 +1682,7 @@ struct drm_i915_file_private {
 
        struct i915_hw_context *private_default_ctx;
        atomic_t rps_wait_boost;
+       struct  intel_ring_buffer *bsd_ring;
 };
 
 /*
@@ -1894,11 +1750,17 @@ struct drm_i915_cmd_descriptor {
         * the expected value, the parser rejects it. Only valid if flags has
         * the CMD_DESC_BITMASK bit set. Only entries where mask is non-zero
         * are valid.
+        *
+        * If the check specifies a non-zero condition_mask then the parser
+        * only performs the check when the bits specified by condition_mask
+        * are non-zero.
         */
        struct {
                u32 offset;
                u32 mask;
                u32 expected;
+               u32 condition_offset;
+               u32 condition_mask;
        } bits[MAX_CMD_DESC_BITMASKS];
 };
 
@@ -1940,8 +1802,9 @@ struct drm_i915_cmd_table {
                                 (dev)->pdev->device == 0x0106 || \
                                 (dev)->pdev->device == 0x010A)
 #define IS_VALLEYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview)
+#define IS_CHERRYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_HASWELL(dev)        (INTEL_INFO(dev)->is_haswell)
-#define IS_BROADWELL(dev)      (INTEL_INFO(dev)->gen == 8)
+#define IS_BROADWELL(dev)      (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 #define IS_HSW_EARLY_SDV(dev)  (IS_HASWELL(dev) && \
                                 ((dev)->pdev->device & 0xFF00) == 0x0C00)
@@ -1974,11 +1837,14 @@ struct drm_i915_cmd_table {
 #define BSD_RING               (1<<VCS)
 #define BLT_RING               (1<<BCS)
 #define VEBOX_RING             (1<<VECS)
-#define HAS_BSD(dev)            (INTEL_INFO(dev)->ring_mask & BSD_RING)
-#define HAS_BLT(dev)            (INTEL_INFO(dev)->ring_mask & BLT_RING)
-#define HAS_VEBOX(dev)            (INTEL_INFO(dev)->ring_mask & VEBOX_RING)
-#define HAS_LLC(dev)            (INTEL_INFO(dev)->has_llc)
-#define HAS_WT(dev)            (IS_HASWELL(dev) && to_i915(dev)->ellc_size)
+#define BSD2_RING              (1<<VCS2)
+#define HAS_BSD(dev)           (INTEL_INFO(dev)->ring_mask & BSD_RING)
+#define HAS_BSD2(dev)          (INTEL_INFO(dev)->ring_mask & BSD2_RING)
+#define HAS_BLT(dev)           (INTEL_INFO(dev)->ring_mask & BLT_RING)
+#define HAS_VEBOX(dev)         (INTEL_INFO(dev)->ring_mask & VEBOX_RING)
+#define HAS_LLC(dev)           (INTEL_INFO(dev)->has_llc)
+#define HAS_WT(dev)            ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && \
+                                to_i915(dev)->ellc_size)
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
 #define HAS_HW_CONTEXTS(dev)   (INTEL_INFO(dev)->gen >= 6)
@@ -2022,8 +1888,8 @@ struct drm_i915_cmd_table {
 #define HAS_DDI(dev)           (INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)    (INTEL_INFO(dev)->has_fpga_dbg)
 #define HAS_PSR(dev)           (IS_HASWELL(dev) || IS_BROADWELL(dev))
-#define HAS_PC8(dev)           (IS_HASWELL(dev)) /* XXX HSW:ULX */
-#define HAS_RUNTIME_PM(dev)    (IS_HASWELL(dev))
+#define HAS_RUNTIME_PM(dev)    (IS_GEN6(dev) || IS_HASWELL(dev) || \
+                                IS_BROADWELL(dev))
 
 #define INTEL_PCH_DEVICE_ID_MASK               0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE           0x3b00
@@ -2080,6 +1946,7 @@ struct i915_params {
        bool prefault_disable;
        bool reset;
        bool disable_display;
+       bool disable_vtd_wa;
 };
 extern struct i915_params i915 __read_mostly;
 
@@ -2108,6 +1975,7 @@ extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
 extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
+int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
 
 extern void intel_console_resume(struct work_struct *work);
 
@@ -2302,6 +2170,18 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error)
        return ((atomic_read(&error->reset_counter) & ~I915_WEDGED) + 1) / 2;
 }
 
+static inline bool i915_stop_ring_allow_ban(struct drm_i915_private *dev_priv)
+{
+       return dev_priv->gpu_error.stop_rings == 0 ||
+               dev_priv->gpu_error.stop_rings & I915_STOP_RING_ALLOW_BAN;
+}
+
+static inline bool i915_stop_ring_allow_warn(struct drm_i915_private *dev_priv)
+{
+       return dev_priv->gpu_error.stop_rings == 0 ||
+               dev_priv->gpu_error.stop_rings & I915_STOP_RING_ALLOW_WARN;
+}
+
 void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
@@ -2466,23 +2346,12 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
 int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
 int i915_gem_evict_everything(struct drm_device *dev);
 
-/* i915_gem_gtt.c */
-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_finish_object(struct drm_i915_gem_object *obj);
-void i915_gem_init_global_gtt(struct drm_device *dev);
-void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
-                              unsigned long mappable_end, unsigned long end);
-int i915_gem_gtt_init(struct drm_device *dev);
+/* belongs in i915_gem_gtt.h */
 static inline void i915_gem_chipset_flush(struct drm_device *dev)
 {
        if (INTEL_INFO(dev)->gen < 6)
                intel_gtt_chipset_flush();
 }
-int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
-bool intel_enable_ppgtt(struct drm_device *dev, bool full);
 
 /* i915_gem_stolen.c */
 int i915_gem_init_stolen(struct drm_device *dev);
@@ -2550,6 +2419,7 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
 const char *i915_cache_level_str(int type);
 
 /* i915_cmd_parser.c */
+int i915_cmd_parser_get_version(void);
 void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring);
 bool i915_needs_cmd_parser(struct intel_ring_buffer *ring);
 int i915_parse_cmds(struct intel_ring_buffer *ring,
@@ -2701,20 +2571,6 @@ void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
 int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val);
 int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val);
 
-void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine);
-void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
-
-#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \
-       (((reg) >= 0x2000 && (reg) < 0x4000) ||\
-       ((reg) >= 0x5000 && (reg) < 0x8000) ||\
-       ((reg) >= 0xB000 && (reg) < 0x12000) ||\
-       ((reg) >= 0x2E000 && (reg) < 0x30000))
-
-#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\
-       (((reg) >= 0x12000 && (reg) < 0x14000) ||\
-       ((reg) >= 0x22000 && (reg) < 0x24000) ||\
-       ((reg) >= 0x30000 && (reg) < 0x40000))
-
 #define FORCEWAKE_RENDER       (1 << 0)
 #define FORCEWAKE_MEDIA                (1 << 1)
 #define FORCEWAKE_ALL          (FORCEWAKE_RENDER | FORCEWAKE_MEDIA)
index 2871ce75f438641b34bef7749545d4fedfde5744..e1fa919017e2e6dfe84a924a40828f19a5d52f45 100644 (file)
@@ -43,6 +43,9 @@ static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *o
 static __must_check int
 i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
                               bool readonly);
+static void
+i915_gem_object_retire(struct drm_i915_gem_object *obj);
+
 static int i915_gem_phys_pwrite(struct drm_device *dev,
                                struct drm_i915_gem_object *obj,
                                struct drm_i915_gem_pwrite *args,
@@ -352,6 +355,8 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
                ret = i915_gem_object_wait_rendering(obj, true);
                if (ret)
                        return ret;
+
+               i915_gem_object_retire(obj);
        }
 
        ret = i915_gem_object_get_pages(obj);
@@ -767,6 +772,8 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
                ret = i915_gem_object_wait_rendering(obj, false);
                if (ret)
                        return ret;
+
+               i915_gem_object_retire(obj);
        }
        /* Same trick applies to invalidate partially written cachelines read
         * before writing. */
@@ -1154,7 +1161,8 @@ static int
 i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj,
                                     struct intel_ring_buffer *ring)
 {
-       i915_gem_retire_requests_ring(ring);
+       if (!obj->active)
+               return 0;
 
        /* Manually manage the write flush as we may have not yet
         * retired the buffer.
@@ -1164,7 +1172,6 @@ i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj,
         * we know we have passed the last write.
         */
        obj->last_write_seqno = 0;
-       obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
 
        return 0;
 }
@@ -1785,58 +1792,58 @@ static unsigned 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;
+       struct list_head still_in_list;
+       struct drm_i915_gem_object *obj;
        unsigned long count = 0;
 
-       list_for_each_entry_safe(obj, next,
-                                &dev_priv->mm.unbound_list,
-                                global_list) {
-               if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
-                   i915_gem_object_put_pages(obj) == 0) {
-                       count += obj->base.size >> PAGE_SHIFT;
-                       if (count >= target)
-                               return count;
-               }
-       }
-
        /*
-        * As we may completely rewrite the bound list whilst unbinding
+        * As we may completely rewrite the (un)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.
+        *
+        * In particular, we must hold a reference whilst removing the
+        * object as we may end up waiting for and/or retiring the objects.
+        * This might release the final reference (held by the active list)
+        * and result in the object being freed from under us. This is
+        * similar to the precautions the eviction code must take whilst
+        * removing objects.
+        *
+        * Also note that although these lists do not 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.
         */
-       INIT_LIST_HEAD(&still_bound_list);
+       INIT_LIST_HEAD(&still_in_list);
+       while (count < target && !list_empty(&dev_priv->mm.unbound_list)) {
+               obj = list_first_entry(&dev_priv->mm.unbound_list,
+                                      typeof(*obj), global_list);
+               list_move_tail(&obj->global_list, &still_in_list);
+
+               if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
+                       continue;
+
+               drm_gem_object_reference(&obj->base);
+
+               if (i915_gem_object_put_pages(obj) == 0)
+                       count += obj->base.size >> PAGE_SHIFT;
+
+               drm_gem_object_unreference(&obj->base);
+       }
+       list_splice(&still_in_list, &dev_priv->mm.unbound_list);
+
+       INIT_LIST_HEAD(&still_in_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);
+               list_move_tail(&obj->global_list, &still_in_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)
@@ -1848,7 +1855,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
 
                drm_gem_object_unreference(&obj->base);
        }
-       list_splice(&still_bound_list, &dev_priv->mm.bound_list);
+       list_splice(&still_in_list, &dev_priv->mm.bound_list);
 
        return count;
 }
@@ -1862,17 +1869,8 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
 static unsigned 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) {
-               if (i915_gem_object_put_pages(obj) == 0)
-                       freed += obj->base.size >> PAGE_SHIFT;
-       }
-       return freed;
+       return __i915_gem_shrink(dev_priv, LONG_MAX, false);
 }
 
 static int
@@ -2089,6 +2087,19 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
        WARN_ON(i915_verify_lists(dev));
 }
 
+static void
+i915_gem_object_retire(struct drm_i915_gem_object *obj)
+{
+       struct intel_ring_buffer *ring = obj->ring;
+
+       if (ring == NULL)
+               return;
+
+       if (i915_seqno_passed(ring->get_seqno(ring, true),
+                             obj->last_read_seqno))
+               i915_gem_object_move_to_inactive(obj);
+}
+
 static int
 i915_gem_init_seqno(struct drm_device *dev, u32 seqno)
 {
@@ -2108,8 +2119,8 @@ i915_gem_init_seqno(struct drm_device *dev, u32 seqno)
        for_each_ring(ring, dev_priv, i) {
                intel_ring_init_seqno(ring, seqno);
 
-               for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++)
-                       ring->sync_seqno[j] = 0;
+               for (j = 0; j < ARRAY_SIZE(ring->semaphore.sync_seqno); j++)
+                       ring->semaphore.sync_seqno[j] = 0;
        }
 
        return 0;
@@ -2277,8 +2288,9 @@ static bool i915_context_is_banned(struct drm_i915_private *dev_priv,
                if (!i915_gem_context_is_default(ctx)) {
                        DRM_DEBUG("context hanging too fast, banning!\n");
                        return true;
-               } else if (dev_priv->gpu_error.stop_rings == 0) {
-                       DRM_ERROR("gpu hanging too fast, banning!\n");
+               } else if (i915_stop_ring_allow_ban(dev_priv)) {
+                       if (i915_stop_ring_allow_warn(dev_priv))
+                               DRM_ERROR("gpu hanging too fast, banning!\n");
                        return true;
                }
        }
@@ -2383,6 +2395,11 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 
                i915_gem_free_request(request);
        }
+
+       /* These may not have been flush before the reset, do so now */
+       kfree(ring->preallocated_lazy_request);
+       ring->preallocated_lazy_request = NULL;
+       ring->outstanding_lazy_seqno = 0;
 }
 
 void i915_gem_restore_fences(struct drm_device *dev)
@@ -2423,8 +2440,6 @@ void i915_gem_reset(struct drm_device *dev)
        for_each_ring(ring, dev_priv, i)
                i915_gem_reset_ring_cleanup(dev_priv, ring);
 
-       i915_gem_cleanup_ringbuffer(dev);
-
        i915_gem_context_reset(dev);
 
        i915_gem_restore_fences(dev);
@@ -2677,7 +2692,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj,
        idx = intel_ring_sync_index(from, to);
 
        seqno = obj->last_read_seqno;
-       if (seqno <= from->sync_seqno[idx])
+       if (seqno <= from->semaphore.sync_seqno[idx])
                return 0;
 
        ret = i915_gem_check_olr(obj->ring, seqno);
@@ -2685,13 +2700,13 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj,
                return ret;
 
        trace_i915_gem_ring_sync_to(from, to, seqno);
-       ret = to->sync_to(to, from, seqno);
+       ret = to->semaphore.sync_to(to, from, seqno);
        if (!ret)
                /* We use last_read_seqno because sync_to()
                 * might have just caused seqno wrap under
                 * the radar.
                 */
-               from->sync_seqno[idx] = obj->last_read_seqno;
+               from->semaphore.sync_seqno[idx] = obj->last_read_seqno;
 
        return ret;
 }
@@ -3425,6 +3440,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
        if (ret)
                return ret;
 
+       i915_gem_object_retire(obj);
        i915_gem_object_flush_cpu_write_domain(obj, false);
 
        /* Serialise direct access to this object with the barriers for
@@ -3523,6 +3539,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                 * in obj->write_domain and have been skipping the clflushes.
                 * Just set it to the CPU cache for now.
                 */
+               i915_gem_object_retire(obj);
                WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU);
 
                old_read_domains = obj->base.read_domains;
@@ -3745,6 +3762,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
        if (ret)
                return ret;
 
+       i915_gem_object_retire(obj);
        i915_gem_object_flush_gtt_write_domain(obj);
 
        old_write_domain = obj->base.write_domain;
@@ -4232,6 +4250,17 @@ void i915_gem_vma_destroy(struct i915_vma *vma)
        kfree(vma);
 }
 
+static void
+i915_gem_stop_ringbuffers(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       int i;
+
+       for_each_ring(ring, dev_priv, i)
+               intel_stop_ring_buffer(ring);
+}
+
 int
 i915_gem_suspend(struct drm_device *dev)
 {
@@ -4253,7 +4282,7 @@ i915_gem_suspend(struct drm_device *dev)
                i915_gem_evict_everything(dev);
 
        i915_kernel_lost_context(dev);
-       i915_gem_cleanup_ringbuffer(dev);
+       i915_gem_stop_ringbuffers(dev);
 
        /* Hack!  Don't let anybody do execbuf while we don't control the chip.
         * We need to replace this with a semaphore, or something.
@@ -4373,13 +4402,20 @@ static int i915_gem_init_rings(struct drm_device *dev)
                        goto cleanup_blt_ring;
        }
 
+       if (HAS_BSD2(dev)) {
+               ret = intel_init_bsd2_ring_buffer(dev);
+               if (ret)
+                       goto cleanup_vebox_ring;
+       }
 
        ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
        if (ret)
-               goto cleanup_vebox_ring;
+               goto cleanup_bsd2_ring;
 
        return 0;
 
+cleanup_bsd2_ring:
+       intel_cleanup_ring_buffer(&dev_priv->ring[VCS2]);
 cleanup_vebox_ring:
        intel_cleanup_ring_buffer(&dev_priv->ring[VECS]);
 cleanup_blt_ring:
@@ -4437,15 +4473,11 @@ i915_gem_init_hw(struct drm_device *dev)
         * the do_switch), but before enabling PPGTT. So don't move this.
         */
        ret = i915_gem_context_enable(dev_priv);
-       if (ret) {
+       if (ret && ret != -EIO) {
                DRM_ERROR("Context enable failed %d\n", ret);
-               goto err_out;
+               i915_gem_cleanup_ringbuffer(dev);
        }
 
-       return 0;
-
-err_out:
-       i915_gem_cleanup_ringbuffer(dev);
        return ret;
 }
 
@@ -4458,8 +4490,9 @@ int i915_gem_init(struct drm_device *dev)
 
        if (IS_VALLEYVIEW(dev)) {
                /* VLVA0 (potential hack), BIOS isn't actually waking us */
-               I915_WRITE(VLV_GTLC_WAKE_CTRL, 1);
-               if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10))
+               I915_WRITE(VLV_GTLC_WAKE_CTRL, VLV_GTLC_ALLOWWAKEREQ);
+               if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) &
+                             VLV_GTLC_ALLOWWAKEACK), 10))
                        DRM_DEBUG_DRIVER("allow wake ack timed out\n");
        }
 
@@ -4472,18 +4505,21 @@ int i915_gem_init(struct drm_device *dev)
        }
 
        ret = i915_gem_init_hw(dev);
-       mutex_unlock(&dev->struct_mutex);
-       if (ret) {
-               WARN_ON(dev_priv->mm.aliasing_ppgtt);
-               i915_gem_context_fini(dev);
-               drm_mm_takedown(&dev_priv->gtt.base.mm);
-               return ret;
+       if (ret == -EIO) {
+               /* Allow ring initialisation to fail by marking the GPU as
+                * wedged. But we only want to do this where the GPU is angry,
+                * for all other failure, such as an allocation failure, bail.
+                */
+               DRM_ERROR("Failed to initialize GPU, declaring it wedged\n");
+               atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
+               ret = 0;
        }
+       mutex_unlock(&dev->struct_mutex);
 
        /* Allow hardware batchbuffers unless told otherwise, but not for KMS. */
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                dev_priv->dri1.allow_batchbuffer = 1;
-       return 0;
+       return ret;
 }
 
 void
@@ -4522,16 +4558,15 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
        }
 
        BUG_ON(!list_empty(&dev_priv->gtt.base.active_list));
-       mutex_unlock(&dev->struct_mutex);
 
-       ret = drm_irq_install(dev);
+       ret = drm_irq_install(dev, dev->pdev->irq);
        if (ret)
                goto cleanup_ringbuffer;
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 
 cleanup_ringbuffer:
-       mutex_lock(&dev->struct_mutex);
        i915_gem_cleanup_ringbuffer(dev);
        dev_priv->ums.mm_suspended = 1;
        mutex_unlock(&dev->struct_mutex);
@@ -4546,7 +4581,9 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return 0;
 
+       mutex_lock(&dev->struct_mutex);
        drm_irq_uninstall(dev);
+       mutex_unlock(&dev->struct_mutex);
 
        return i915_gem_suspend(dev);
 }
index d72db15afa02fde49c56693bbf84ce227038298d..f77b4c126465e1cec2a63f9f7614a079bc6e0d27 100644 (file)
@@ -240,7 +240,15 @@ __create_hw_context(struct drm_device *dev,
                        goto err_out;
                }
 
-               if (INTEL_INFO(dev)->gen >= 7) {
+               /*
+                * Try to make the context utilize L3 as well as LLC.
+                *
+                * On VLV we don't have L3 controls in the PTEs so we
+                * shouldn't touch the cache level, especially as that
+                * would make the object snooped which might have a
+                * negative performance impact.
+                */
+               if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) {
                        ret = i915_gem_object_set_cache_level(ctx->obj,
                                                              I915_CACHE_L3_LLC);
                        /* Failure shouldn't ever happen this early */
@@ -549,7 +557,7 @@ mi_set_context(struct intel_ring_buffer *ring,
         * explicitly, so we rely on the value at ring init, stored in
         * itlb_before_ctx_switch.
         */
-       if (IS_GEN6(ring->dev) && ring->itlb_before_ctx_switch) {
+       if (IS_GEN6(ring->dev)) {
                ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, 0);
                if (ret)
                        return ret;
@@ -559,8 +567,8 @@ mi_set_context(struct intel_ring_buffer *ring,
        if (ret)
                return ret;
 
-       /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw */
-       if (IS_GEN7(ring->dev))
+       /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw */
+       if (INTEL_INFO(ring->dev)->gen >= 7)
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
        else
                intel_ring_emit(ring, MI_NOOP);
@@ -578,7 +586,7 @@ mi_set_context(struct intel_ring_buffer *ring,
         */
        intel_ring_emit(ring, MI_NOOP);
 
-       if (IS_GEN7(ring->dev))
+       if (INTEL_INFO(ring->dev)->gen >= 7)
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
        else
                intel_ring_emit(ring, MI_NOOP);
index 9bb533e0d76234cdc14ec6d9da31a310114080a5..321102a8374ba0d0ea8870620b78b4a2327131c1 100644 (file)
@@ -161,12 +161,8 @@ static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
 {
        struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
        struct drm_device *dev = obj->base.dev;
-       int ret;
-
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return;
 
+       mutex_lock(&dev->struct_mutex);
        if (--obj->vmapping_count == 0) {
                vunmap(obj->dma_buf_vmapping);
                obj->dma_buf_vmapping = NULL;
index 2c9d9cbaf653307aff52e037f596f4343219a3ee..47fe8ecef135faacd0967805e213f23e764e4f1b 100644 (file)
@@ -262,10 +262,12 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
 
 static int
 relocate_entry_cpu(struct drm_i915_gem_object *obj,
-                  struct drm_i915_gem_relocation_entry *reloc)
+                  struct drm_i915_gem_relocation_entry *reloc,
+                  uint64_t target_offset)
 {
        struct drm_device *dev = obj->base.dev;
        uint32_t page_offset = offset_in_page(reloc->offset);
+       uint64_t delta = reloc->delta + target_offset;
        char *vaddr;
        int ret;
 
@@ -275,7 +277,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
 
        vaddr = kmap_atomic(i915_gem_object_get_page(obj,
                                reloc->offset >> PAGE_SHIFT));
-       *(uint32_t *)(vaddr + page_offset) = reloc->delta;
+       *(uint32_t *)(vaddr + page_offset) = lower_32_bits(delta);
 
        if (INTEL_INFO(dev)->gen >= 8) {
                page_offset = offset_in_page(page_offset + sizeof(uint32_t));
@@ -286,7 +288,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
                            (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
                }
 
-               *(uint32_t *)(vaddr + page_offset) = 0;
+               *(uint32_t *)(vaddr + page_offset) = upper_32_bits(delta);
        }
 
        kunmap_atomic(vaddr);
@@ -296,10 +298,12 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
 
 static int
 relocate_entry_gtt(struct drm_i915_gem_object *obj,
-                  struct drm_i915_gem_relocation_entry *reloc)
+                  struct drm_i915_gem_relocation_entry *reloc,
+                  uint64_t target_offset)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       uint64_t delta = reloc->delta + target_offset;
        uint32_t __iomem *reloc_entry;
        void __iomem *reloc_page;
        int ret;
@@ -318,7 +322,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
                        reloc->offset & PAGE_MASK);
        reloc_entry = (uint32_t __iomem *)
                (reloc_page + offset_in_page(reloc->offset));
-       iowrite32(reloc->delta, reloc_entry);
+       iowrite32(lower_32_bits(delta), reloc_entry);
 
        if (INTEL_INFO(dev)->gen >= 8) {
                reloc_entry += 1;
@@ -331,7 +335,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
                        reloc_entry = reloc_page;
                }
 
-               iowrite32(0, reloc_entry);
+               iowrite32(upper_32_bits(delta), reloc_entry);
        }
 
        io_mapping_unmap_atomic(reloc_page);
@@ -348,7 +352,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        struct drm_gem_object *target_obj;
        struct drm_i915_gem_object *target_i915_obj;
        struct i915_vma *target_vma;
-       uint32_t target_offset;
+       uint64_t target_offset;
        int ret;
 
        /* we've already hold a reference to all valid objects */
@@ -426,11 +430,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        if (obj->active && in_atomic())
                return -EFAULT;
 
-       reloc->delta += target_offset;
        if (use_cpu_reloc(obj))
-               ret = relocate_entry_cpu(obj, reloc);
+               ret = relocate_entry_cpu(obj, reloc, target_offset);
        else
-               ret = relocate_entry_gtt(obj, reloc);
+               ret = relocate_entry_gtt(obj, reloc, target_offset);
 
        if (ret)
                return ret;
@@ -955,6 +958,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                        if (i915_gem_obj_ggtt_bound(obj) &&
                            i915_gem_obj_to_ggtt(obj)->pin_count)
                                intel_mark_fb_busy(obj, ring);
+
+                       /* update for the implicit flush after a batch */
+                       obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
                }
 
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
@@ -981,8 +987,10 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret, i;
 
-       if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS])
-               return 0;
+       if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS]) {
+               DRM_DEBUG("sol reset is gen7/rcs only\n");
+               return -EINVAL;
+       }
 
        ret = intel_ring_begin(ring, 4 * 3);
        if (ret)
@@ -999,6 +1007,37 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
        return 0;
 }
 
+/**
+ * Find one BSD ring to dispatch the corresponding BSD command.
+ * The Ring ID is returned.
+ */
+static int gen8_dispatch_bsd_ring(struct drm_device *dev,
+                                 struct drm_file *file)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
+
+       /* Check whether the file_priv is using one ring */
+       if (file_priv->bsd_ring)
+               return file_priv->bsd_ring->id;
+       else {
+               /* If no, use the ping-pong mechanism to select one ring */
+               int ring_id;
+
+               mutex_lock(&dev->struct_mutex);
+               if (dev_priv->ring_index == 0) {
+                       ring_id = VCS;
+                       dev_priv->ring_index = 1;
+               } else {
+                       ring_id = VCS2;
+                       dev_priv->ring_index = 0;
+               }
+               file_priv->bsd_ring = &dev_priv->ring[ring_id];
+               mutex_unlock(&dev->struct_mutex);
+               return ring_id;
+       }
+}
+
 static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                       struct drm_file *file,
@@ -1013,7 +1052,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        struct i915_hw_context *ctx;
        struct i915_address_space *vm;
        const u32 ctx_id = i915_execbuffer2_get_context_id(*args);
-       u32 exec_start = args->batch_start_offset, exec_len;
+       u64 exec_start = args->batch_start_offset, exec_len;
        u32 mask, flags;
        int ret, mode, i;
        bool need_relocs;
@@ -1035,7 +1074,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (args->flags & I915_EXEC_IS_PINNED)
                flags |= I915_DISPATCH_PINNED;
 
-       if ((args->flags & I915_EXEC_RING_MASK) > I915_NUM_RINGS) {
+       if ((args->flags & I915_EXEC_RING_MASK) > LAST_USER_RING) {
                DRM_DEBUG("execbuf with unknown ring: %d\n",
                          (int)(args->flags & I915_EXEC_RING_MASK));
                return -EINVAL;
@@ -1043,7 +1082,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
                ring = &dev_priv->ring[RCS];
-       else
+       else if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_BSD) {
+               if (HAS_BSD2(dev)) {
+                       int ring_id;
+                       ring_id = gen8_dispatch_bsd_ring(dev, file);
+                       ring = &dev_priv->ring[ring_id];
+               } else
+                       ring = &dev_priv->ring[VCS];
+       } else
                ring = &dev_priv->ring[(args->flags & I915_EXEC_RING_MASK) - 1];
 
        if (!intel_ring_initialized(ring)) {
@@ -1058,14 +1104,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        case I915_EXEC_CONSTANTS_REL_GENERAL:
        case I915_EXEC_CONSTANTS_ABSOLUTE:
        case I915_EXEC_CONSTANTS_REL_SURFACE:
-               if (ring == &dev_priv->ring[RCS] &&
-                   mode != dev_priv->relative_constants_mode) {
-                       if (INTEL_INFO(dev)->gen < 4)
+               if (mode != 0 && ring != &dev_priv->ring[RCS]) {
+                       DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
+                       return -EINVAL;
+               }
+
+               if (mode != dev_priv->relative_constants_mode) {
+                       if (INTEL_INFO(dev)->gen < 4) {
+                               DRM_DEBUG("no rel constants on pre-gen4\n");
                                return -EINVAL;
+                       }
 
                        if (INTEL_INFO(dev)->gen > 5 &&
-                           mode == I915_EXEC_CONSTANTS_REL_SURFACE)
+                           mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
+                               DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
                                return -EINVAL;
+                       }
 
                        /* The HW changed the meaning on this bit on gen6 */
                        if (INTEL_INFO(dev)->gen >= 6)
@@ -1113,6 +1167,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        ret = -EFAULT;
                        goto pre_mutex_err;
                }
+       } else {
+               if (args->DR1 || args->DR4 || args->cliprects_ptr) {
+                       DRM_DEBUG("0 cliprects but dirt in cliprects fields\n");
+                       return -EINVAL;
+               }
        }
 
        intel_runtime_pm_get(dev_priv);
@@ -1132,7 +1191,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                mutex_unlock(&dev->struct_mutex);
                ret = PTR_ERR(ctx);
                goto pre_mutex_err;
-       } 
+       }
 
        i915_gem_context_reference(ctx);
 
@@ -1142,6 +1201,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        eb = eb_create(args);
        if (eb == NULL) {
+               i915_gem_context_unreference(ctx);
                mutex_unlock(&dev->struct_mutex);
                ret = -ENOMEM;
                goto pre_mutex_err;
@@ -1389,6 +1449,11 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
+       if (args->rsvd2 != 0) {
+               DRM_DEBUG("dirty rvsd2 field\n");
+               return -EINVAL;
+       }
+
        exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count,
                             GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
        if (exec2_list == NULL)
index ab5e93c30aa2bde43b1ed892f0437b7b5d0c8289..496916298e8a59ef89323e53a97a1beae44d909b 100644 (file)
@@ -50,64 +50,11 @@ bool intel_enable_ppgtt(struct drm_device *dev, bool full)
 
        /* Full ppgtt disabled by default for now due to issues. */
        if (full)
-               return false; /* HAS_PPGTT(dev) */
+               return HAS_PPGTT(dev) && (i915.enable_ppgtt == 2);
        else
                return HAS_ALIASING_PPGTT(dev);
 }
 
-#define GEN6_PPGTT_PD_ENTRIES 512
-#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
-typedef uint64_t gen8_gtt_pte_t;
-typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
-
-/* PPGTT stuff */
-#define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
-#define HSW_GTT_ADDR_ENCODE(addr)      ((addr) | (((addr) >> 28) & 0x7f0))
-
-#define GEN6_PDE_VALID                 (1 << 0)
-/* gen6+ has bit 11-4 for physical addr bit 39-32 */
-#define GEN6_PDE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
-
-#define GEN6_PTE_VALID                 (1 << 0)
-#define GEN6_PTE_UNCACHED              (1 << 1)
-#define HSW_PTE_UNCACHED               (0)
-#define GEN6_PTE_CACHE_LLC             (2 << 1)
-#define GEN7_PTE_CACHE_L3_LLC          (3 << 1)
-#define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
-#define HSW_PTE_ADDR_ENCODE(addr)      HSW_GTT_ADDR_ENCODE(addr)
-
-/* Cacheability Control is a 4-bit value. The low three bits are stored in *
- * bits 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE.
- */
-#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \
-                                        (((bits) & 0x8) << (11 - 3)))
-#define HSW_WB_LLC_AGE3                        HSW_CACHEABILITY_CONTROL(0x2)
-#define HSW_WB_LLC_AGE0                        HSW_CACHEABILITY_CONTROL(0x3)
-#define HSW_WB_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0xb)
-#define HSW_WB_ELLC_LLC_AGE3           HSW_CACHEABILITY_CONTROL(0x8)
-#define HSW_WT_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0x6)
-#define HSW_WT_ELLC_LLC_AGE3           HSW_CACHEABILITY_CONTROL(0x7)
-
-#define GEN8_PTES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_gtt_pte_t))
-#define GEN8_PDES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
-
-/* GEN8 legacy style addressis defined as a 3 level page table:
- * 31:30 | 29:21 | 20:12 |  11:0
- * PDPE  |  PDE  |  PTE  | offset
- * The difference as compared to normal x86 3 level page table is the PDPEs are
- * programmed via register.
- */
-#define GEN8_PDPE_SHIFT                        30
-#define GEN8_PDPE_MASK                 0x3
-#define GEN8_PDE_SHIFT                 21
-#define GEN8_PDE_MASK                  0x1ff
-#define GEN8_PTE_SHIFT                 12
-#define GEN8_PTE_MASK                  0x1ff
-
-#define PPAT_UNCACHED_INDEX            (_PAGE_PWT | _PAGE_PCD)
-#define PPAT_CACHED_PDE_INDEX          0 /* WB LLC */
-#define PPAT_CACHED_INDEX              _PAGE_PAT /* WB LLCeLLC */
-#define PPAT_DISPLAY_ELLC_INDEX                _PAGE_PCD /* WT eLLC */
 
 static void ppgtt_bind_vma(struct i915_vma *vma,
                           enum i915_cache_level cache_level,
@@ -121,10 +68,19 @@ static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
 {
        gen8_gtt_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0;
        pte |= addr;
-       if (level != I915_CACHE_NONE)
-               pte |= PPAT_CACHED_INDEX;
-       else
+
+       switch (level) {
+       case I915_CACHE_NONE:
                pte |= PPAT_UNCACHED_INDEX;
+               break;
+       case I915_CACHE_WT:
+               pte |= PPAT_DISPLAY_ELLC_INDEX;
+               break;
+       default:
+               pte |= PPAT_CACHED_INDEX;
+               break;
+       }
+
        return pte;
 }
 
@@ -187,9 +143,6 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-#define BYT_PTE_WRITEABLE              (1 << 1)
-#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,
                                     bool valid)
@@ -1057,8 +1010,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 
 static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
 {
-#define GEN6_PD_ALIGN (PAGE_SIZE * 16)
-#define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE)
        struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        bool retried = false;
@@ -1426,7 +1377,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
-       dma_addr_t addr;
+       dma_addr_t addr = 0;
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_dma_address(sg_iter.sg) +
@@ -1848,17 +1799,6 @@ static int ggtt_probe_common(struct drm_device *dev,
  * writing this data shouldn't be harmful even in those cases. */
 static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv)
 {
-#define GEN8_PPAT_UC           (0<<0)
-#define GEN8_PPAT_WC           (1<<0)
-#define GEN8_PPAT_WT           (2<<0)
-#define GEN8_PPAT_WB           (3<<0)
-#define GEN8_PPAT_ELLC_OVERRIDE        (0<<2)
-/* FIXME(BDW): Bspec is completely confused about cache control bits. */
-#define GEN8_PPAT_LLC          (1<<2)
-#define GEN8_PPAT_LLCELLC      (2<<2)
-#define GEN8_PPAT_LLCeLLC      (3<<2)
-#define GEN8_PPAT_AGE(x)       (x<<4)
-#define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8))
        uint64_t pat;
 
        pat = GEN8_PPAT(0, GEN8_PPAT_WB | GEN8_PPAT_LLC)     | /* for normal objects, no eLLC */
@@ -2031,6 +1971,10 @@ int i915_gem_gtt_init(struct drm_device *dev)
                 gtt->base.total >> 20);
        DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20);
        DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20);
+#ifdef CONFIG_INTEL_IOMMU
+       if (intel_iommu_gfx_mapped)
+               DRM_INFO("VT-d active for gfx access\n");
+#endif
 
        return 0;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
new file mode 100644 (file)
index 0000000..b5e8ac0
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Please try to maintain the following order within this file unless it makes
+ * sense to do otherwise. From top to bottom:
+ * 1. typedefs
+ * 2. #defines, and macros
+ * 3. structure definitions
+ * 4. function prototypes
+ *
+ * Within each section, please try to order by generation in ascending order,
+ * from top to bottom (ie. gen6 on the top, gen8 on the bottom).
+ */
+
+#ifndef __I915_GEM_GTT_H__
+#define __I915_GEM_GTT_H__
+
+typedef uint32_t gen6_gtt_pte_t;
+typedef uint64_t gen8_gtt_pte_t;
+typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
+
+#define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
+
+#define I915_PPGTT_PT_ENTRIES          (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
+/* gen6-hsw has bit 11-4 for physical addr bit 39-32 */
+#define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
+#define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
+#define GEN6_PDE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
+#define GEN6_PTE_CACHE_LLC             (2 << 1)
+#define GEN6_PTE_UNCACHED              (1 << 1)
+#define GEN6_PTE_VALID                 (1 << 0)
+
+#define GEN6_PPGTT_PD_ENTRIES          512
+#define GEN6_PD_SIZE                   (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE)
+#define GEN6_PD_ALIGN                  (PAGE_SIZE * 16)
+#define GEN6_PDE_VALID                 (1 << 0)
+
+#define GEN7_PTE_CACHE_L3_LLC          (3 << 1)
+
+#define BYT_PTE_SNOOPED_BY_CPU_CACHES  (1 << 2)
+#define BYT_PTE_WRITEABLE              (1 << 1)
+
+/* Cacheability Control is a 4-bit value. The low three bits are stored in bits
+ * 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE.
+ */
+#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \
+                                        (((bits) & 0x8) << (11 - 3)))
+#define HSW_WB_LLC_AGE3                        HSW_CACHEABILITY_CONTROL(0x2)
+#define HSW_WB_LLC_AGE0                        HSW_CACHEABILITY_CONTROL(0x3)
+#define HSW_WB_ELLC_LLC_AGE3           HSW_CACHEABILITY_CONTROL(0x8)
+#define HSW_WB_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0xb)
+#define HSW_WT_ELLC_LLC_AGE3           HSW_CACHEABILITY_CONTROL(0x7)
+#define HSW_WT_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0x6)
+#define HSW_PTE_UNCACHED               (0)
+#define HSW_GTT_ADDR_ENCODE(addr)      ((addr) | (((addr) >> 28) & 0x7f0))
+#define HSW_PTE_ADDR_ENCODE(addr)      HSW_GTT_ADDR_ENCODE(addr)
+
+/* GEN8 legacy style address is defined as a 3 level page table:
+ * 31:30 | 29:21 | 20:12 |  11:0
+ * PDPE  |  PDE  |  PTE  | offset
+ * The difference as compared to normal x86 3 level page table is the PDPEs are
+ * programmed via register.
+ */
+#define GEN8_PDPE_SHIFT                        30
+#define GEN8_PDPE_MASK                 0x3
+#define GEN8_PDE_SHIFT                 21
+#define GEN8_PDE_MASK                  0x1ff
+#define GEN8_PTE_SHIFT                 12
+#define GEN8_PTE_MASK                  0x1ff
+#define GEN8_LEGACY_PDPS               4
+#define GEN8_PTES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_gtt_pte_t))
+#define GEN8_PDES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
+
+#define PPAT_UNCACHED_INDEX            (_PAGE_PWT | _PAGE_PCD)
+#define PPAT_CACHED_PDE_INDEX          0 /* WB LLC */
+#define PPAT_CACHED_INDEX              _PAGE_PAT /* WB LLCeLLC */
+#define PPAT_DISPLAY_ELLC_INDEX                _PAGE_PCD /* WT eLLC */
+
+#define GEN8_PPAT_AGE(x)               (x<<4)
+#define GEN8_PPAT_LLCeLLC              (3<<2)
+#define GEN8_PPAT_LLCELLC              (2<<2)
+#define GEN8_PPAT_LLC                  (1<<2)
+#define GEN8_PPAT_WB                   (3<<0)
+#define GEN8_PPAT_WT                   (2<<0)
+#define GEN8_PPAT_WC                   (1<<0)
+#define GEN8_PPAT_UC                   (0<<0)
+#define GEN8_PPAT_ELLC_OVERRIDE                (0<<2)
+#define GEN8_PPAT(i, x)                        ((uint64_t) (x) << ((i) * 8))
+
+enum i915_cache_level;
+/**
+ * A VMA represents a GEM BO that is bound into an address space. Therefore, a
+ * VMA's presence cannot be guaranteed before binding, or after unbinding the
+ * object into/from the address space.
+ *
+ * To make things as simple as possible (ie. no refcounting), a VMA's lifetime
+ * will always be <= an objects lifetime. So object refcounting should cover us.
+ */
+struct i915_vma {
+       struct drm_mm_node node;
+       struct drm_i915_gem_object *obj;
+       struct i915_address_space *vm;
+
+       /** This object's place on the active/inactive lists */
+       struct list_head mm_list;
+
+       struct list_head vma_link; /* Link in the object's VMA list */
+
+       /** This vma's place in the batchbuffer or on the eviction list */
+       struct list_head exec_list;
+
+       /**
+        * Used for performing relocations during execbuffer insertion.
+        */
+       struct hlist_node exec_node;
+       unsigned long exec_handle;
+       struct drm_i915_gem_exec_object2 *exec_entry;
+
+       /**
+        * How many users have pinned this object in GTT space. The following
+        * users can each hold at most one reference: pwrite/pread, pin_ioctl
+        * (via user_pin_count), execbuffer (objects are not allowed multiple
+        * times for the same batchbuffer), and the framebuffer code. When
+        * switching/pageflipping, the framebuffer code has at most two buffers
+        * pinned per crtc.
+        *
+        * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
+        * bits with absolutely no headroom. So use 4 bits. */
+       unsigned int pin_count:4;
+#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
+
+       /** Unmap an object from an address space. This usually consists of
+        * setting the valid PTE entries to a reserved scratch page. */
+       void (*unbind_vma)(struct i915_vma *vma);
+       /* Map an object into an address space with the given cache flags. */
+#define GLOBAL_BIND (1<<0)
+       void (*bind_vma)(struct i915_vma *vma,
+                        enum i915_cache_level cache_level,
+                        u32 flags);
+};
+
+struct i915_address_space {
+       struct drm_mm mm;
+       struct drm_device *dev;
+       struct list_head global_link;
+       unsigned long start;            /* Start offset always 0 for dri2 */
+       size_t total;           /* size addr space maps (ex. 2GB for ggtt) */
+
+       struct {
+               dma_addr_t addr;
+               struct page *page;
+       } scratch;
+
+       /**
+        * List of objects currently involved in rendering.
+        *
+        * Includes buffers having the contents of their GPU caches
+        * flushed, not necessarily primitives.  last_rendering_seqno
+        * represents when the rendering involved will be completed.
+        *
+        * A reference is held on the buffer while on this list.
+        */
+       struct list_head active_list;
+
+       /**
+        * LRU list of objects which are not in the ringbuffer and
+        * are ready to unbind, but are still in the GTT.
+        *
+        * last_rendering_seqno is 0 while an object is in this list.
+        *
+        * A reference is not held on the buffer while on this list,
+        * as merely being GTT-bound shouldn't prevent its being
+        * freed, and we'll pull it off the list in the free path.
+        */
+       struct list_head inactive_list;
+
+       /* FIXME: Need a more generic return type */
+       gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
+                                    enum i915_cache_level level,
+                                    bool valid); /* Create a valid PTE */
+       void (*clear_range)(struct i915_address_space *vm,
+                           uint64_t start,
+                           uint64_t length,
+                           bool use_scratch);
+       void (*insert_entries)(struct i915_address_space *vm,
+                              struct sg_table *st,
+                              uint64_t start,
+                              enum i915_cache_level cache_level);
+       void (*cleanup)(struct i915_address_space *vm);
+};
+
+/* The Graphics Translation Table is the way in which GEN hardware translates a
+ * Graphics Virtual Address into a Physical Address. In addition to the normal
+ * collateral associated with any va->pa translations GEN hardware also has a
+ * portion of the GTT which can be mapped by the CPU and remain both coherent
+ * and correct (in cases like swizzling). That region is referred to as GMADR in
+ * the spec.
+ */
+struct i915_gtt {
+       struct i915_address_space base;
+       size_t stolen_size;             /* Total size of stolen memory */
+
+       unsigned long mappable_end;     /* End offset that we can CPU map */
+       struct io_mapping *mappable;    /* Mapping to our CPU mappable region */
+       phys_addr_t mappable_base;      /* PA of our GMADR */
+
+       /** "Graphics Stolen Memory" holds the global PTEs */
+       void __iomem *gsm;
+
+       bool do_idle_maps;
+
+       int mtrr;
+
+       /* global gtt ops */
+       int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total,
+                         size_t *stolen, phys_addr_t *mappable_base,
+                         unsigned long *mappable_end);
+};
+
+struct i915_hw_ppgtt {
+       struct i915_address_space base;
+       struct kref ref;
+       struct drm_mm_node node;
+       unsigned num_pd_entries;
+       unsigned num_pd_pages; /* gen8+ */
+       union {
+               struct page **pt_pages;
+               struct page **gen8_pt_pages[GEN8_LEGACY_PDPS];
+       };
+       struct page *pd_pages;
+       union {
+               uint32_t pd_offset;
+               dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS];
+       };
+       union {
+               dma_addr_t *pt_dma_addr;
+               dma_addr_t *gen8_pt_dma_addr[4];
+       };
+
+       struct i915_hw_context *ctx;
+
+       int (*enable)(struct i915_hw_ppgtt *ppgtt);
+       int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
+                        struct intel_ring_buffer *ring,
+                        bool synchronous);
+       void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
+};
+
+int i915_gem_gtt_init(struct drm_device *dev);
+void i915_gem_init_global_gtt(struct drm_device *dev);
+void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
+                              unsigned long mappable_end, unsigned long end);
+
+bool intel_enable_ppgtt(struct drm_device *dev, bool full);
+int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
+
+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_finish_object(struct drm_i915_gem_object *obj);
+
+#endif
index 12f1d43b2d68fbf28f8f0aeeb2ec6c727825eb88..2d819858c19b03fa47978485e392e1897c7a6862 100644 (file)
@@ -42,6 +42,7 @@ static const char *ring_str(int ring)
        case VCS: return "bsd";
        case BCS: return "blt";
        case VECS: return "vebox";
+       case VCS2: return "bsd2";
        default: return "";
        }
 }
@@ -257,7 +258,8 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
                err_printf(m, "  INSTPS: 0x%08x\n", ring->instps);
        }
        err_printf(m, "  INSTPM: 0x%08x\n", ring->instpm);
-       err_printf(m, "  FADDR: 0x%08x\n", ring->faddr);
+       err_printf(m, "  FADDR: 0x%08x %08x\n", upper_32_bits(ring->faddr),
+                  lower_32_bits(ring->faddr));
        if (INTEL_INFO(dev)->gen >= 6) {
                err_printf(m, "  RC PSMI: 0x%08x\n", ring->rc_psmi);
                err_printf(m, "  FAULT_REG: 0x%08x\n", ring->fault_reg);
@@ -452,16 +454,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        err_printf(m, "%s --- HW Context = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
-                       offset = 0;
-                       for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
-                               err_printf(m, "[%04x] %08x %08x %08x %08x\n",
-                                          offset,
-                                          obj->pages[0][elt],
-                                          obj->pages[0][elt+1],
-                                          obj->pages[0][elt+2],
-                                          obj->pages[0][elt+3]);
-                                       offset += 16;
-                       }
+                       print_error_obj(m, obj);
                }
        }
 
@@ -764,14 +757,14 @@ static void i915_record_ring_state(struct drm_device *dev,
                        = I915_READ(RING_SYNC_0(ring->mmio_base));
                ering->semaphore_mboxes[1]
                        = I915_READ(RING_SYNC_1(ring->mmio_base));
-               ering->semaphore_seqno[0] = ring->sync_seqno[0];
-               ering->semaphore_seqno[1] = ring->sync_seqno[1];
+               ering->semaphore_seqno[0] = ring->semaphore.sync_seqno[0];
+               ering->semaphore_seqno[1] = ring->semaphore.sync_seqno[1];
        }
 
        if (HAS_VEBOX(dev)) {
                ering->semaphore_mboxes[2] =
                        I915_READ(RING_SYNC_2(ring->mmio_base));
-               ering->semaphore_seqno[2] = ring->sync_seqno[2];
+               ering->semaphore_seqno[2] = ring->semaphore.sync_seqno[2];
        }
 
        if (INTEL_INFO(dev)->gen >= 4) {
@@ -781,8 +774,10 @@ static void i915_record_ring_state(struct drm_device *dev,
                ering->instdone = I915_READ(RING_INSTDONE(ring->mmio_base));
                ering->instps = I915_READ(RING_INSTPS(ring->mmio_base));
                ering->bbaddr = I915_READ(RING_BBADDR(ring->mmio_base));
-               if (INTEL_INFO(dev)->gen >= 8)
+               if (INTEL_INFO(dev)->gen >= 8) {
+                       ering->faddr |= (u64) I915_READ(RING_DMA_FADD_UDW(ring->mmio_base)) << 32;
                        ering->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32;
+               }
                ering->bbstate = I915_READ(RING_BBSTATE(ring->mmio_base));
        } else {
                ering->faddr = I915_READ(DMA_FADD_I8XX);
@@ -875,10 +870,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) {
-                       ering->ctx = i915_error_object_create_sized(dev_priv,
-                                                                   obj,
-                                                                   &dev_priv->gtt.base,
-                                                                   1);
+                       ering->ctx = i915_error_ggtt_object_create(dev_priv, obj);
                        break;
                }
        }
@@ -1037,7 +1029,6 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
                                   struct drm_i915_error_state *error)
 {
        struct drm_device *dev = dev_priv->dev;
-       int pipe;
 
        /* General organization
         * 1. Registers specific to a single generation
@@ -1062,9 +1053,6 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
                error->gfx_mode = I915_READ(GFX_MODE);
        }
 
-       if (IS_GEN2(dev))
-               error->ier = I915_READ16(IER);
-
        /* 2: Registers which belong to multiple generations */
        if (INTEL_INFO(dev)->gen >= 7)
                error->forcewake = I915_READ(FORCEWAKE_MT);
@@ -1088,9 +1076,10 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
        if (HAS_PCH_SPLIT(dev))
                error->ier = I915_READ(DEIER) | I915_READ(GTIER);
        else {
-               error->ier = I915_READ(IER);
-               for_each_pipe(pipe)
-                       error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
+               if (IS_GEN2(dev))
+                       error->ier = I915_READ16(IER);
+               else
+                       error->ier = I915_READ(IER);
        }
 
        /* 4: Everything else */
index 7753249b3a959cce7f31b8c9cf1ba0b36c18dce8..1e60f24736da66d740b9e0e65fee6c3e9e67358b 100644 (file)
@@ -80,17 +80,64 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
+/* IIR can theoretically queue up two events. Be paranoid. */
+#define GEN8_IRQ_RESET_NDX(type, which) do { \
+       I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
+       POSTING_READ(GEN8_##type##_IMR(which)); \
+       I915_WRITE(GEN8_##type##_IER(which), 0); \
+       I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+       POSTING_READ(GEN8_##type##_IIR(which)); \
+       I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+       POSTING_READ(GEN8_##type##_IIR(which)); \
+} while (0)
+
+#define GEN5_IRQ_RESET(type) do { \
+       I915_WRITE(type##IMR, 0xffffffff); \
+       POSTING_READ(type##IMR); \
+       I915_WRITE(type##IER, 0); \
+       I915_WRITE(type##IIR, 0xffffffff); \
+       POSTING_READ(type##IIR); \
+       I915_WRITE(type##IIR, 0xffffffff); \
+       POSTING_READ(type##IIR); \
+} while (0)
+
+/*
+ * We should clear IMR at preinstall/uninstall, and just check at postinstall.
+ */
+#define GEN5_ASSERT_IIR_IS_ZERO(reg) do { \
+       u32 val = I915_READ(reg); \
+       if (val) { \
+               WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", \
+                    (reg), val); \
+               I915_WRITE((reg), 0xffffffff); \
+               POSTING_READ(reg); \
+               I915_WRITE((reg), 0xffffffff); \
+               POSTING_READ(reg); \
+       } \
+} while (0)
+
+#define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \
+       GEN5_ASSERT_IIR_IS_ZERO(GEN8_##type##_IIR(which)); \
+       I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \
+       I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \
+       POSTING_READ(GEN8_##type##_IER(which)); \
+} while (0)
+
+#define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \
+       GEN5_ASSERT_IIR_IS_ZERO(type##IIR); \
+       I915_WRITE(type##IMR, (imr_val)); \
+       I915_WRITE(type##IER, (ier_val)); \
+       POSTING_READ(type##IER); \
+} while (0)
+
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.deimr &= ~mask;
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        if ((dev_priv->irq_mask & mask) != 0) {
                dev_priv->irq_mask &= ~mask;
@@ -104,11 +151,8 @@ ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.deimr |= mask;
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        if ((dev_priv->irq_mask & mask) != mask) {
                dev_priv->irq_mask |= mask;
@@ -129,13 +173,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.gtimr &= ~interrupt_mask;
-               dev_priv->pm.regsave.gtimr |= (~enabled_irq_mask &
-                                               interrupt_mask);
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        dev_priv->gt_irq_mask &= ~interrupt_mask;
        dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask);
@@ -167,13 +206,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.gen6_pmimr &= ~interrupt_mask;
-               dev_priv->pm.regsave.gen6_pmimr |= (~enabled_irq_mask &
-                                                    interrupt_mask);
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        new_val = dev_priv->pm_irq_mask;
        new_val &= ~interrupt_mask;
@@ -313,14 +347,8 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled &&
-           (interrupt_mask & SDE_HOTPLUG_MASK_CPT)) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.sdeimr &= ~interrupt_mask;
-               dev_priv->pm.regsave.sdeimr |= (~enabled_irq_mask &
-                                                interrupt_mask);
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        I915_WRITE(SDEIMR, sdeimr);
        POSTING_READ(SDEIMR);
@@ -503,8 +531,10 @@ __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
-                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
+       if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                     status_mask & ~PIPESTAT_INT_STATUS_MASK,
+                     "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
+                     pipe_name(pipe), enable_mask, status_mask))
                return;
 
        if ((pipestat & enable_mask) == enable_mask)
@@ -527,8 +557,10 @@ __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
-                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
+       if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                     status_mask & ~PIPESTAT_INT_STATUS_MASK,
+                     "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
+                     pipe_name(pipe), enable_mask, status_mask))
                return;
 
        if ((pipestat & enable_mask) == 0)
@@ -719,24 +751,32 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 /* raw reads, only for fast reads of display block, no need for forcewake etc. */
 #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
 
-static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
+static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
 {
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t status;
-       int reg;
+       const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+       enum pipe pipe = crtc->pipe;
+       int vtotal = mode->crtc_vtotal;
+       int position;
 
-       if (INTEL_INFO(dev)->gen >= 8) {
-               status = GEN8_PIPE_VBLANK;
-               reg = GEN8_DE_PIPE_ISR(pipe);
-       } else if (INTEL_INFO(dev)->gen >= 7) {
-               status = DE_PIPE_VBLANK_IVB(pipe);
-               reg = DEISR;
-       } else {
-               status = DE_PIPE_VBLANK(pipe);
-               reg = DEISR;
-       }
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               vtotal /= 2;
+
+       if (IS_GEN2(dev))
+               position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
+       else
+               position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
-       return __raw_i915_read32(dev_priv, reg) & status;
+       /*
+        * Scanline counter increments at leading edge of hsync, and
+        * it starts counting from vtotal-1 on the first active line.
+        * That means the scanline counter value is always one less
+        * than what we would expect. Ie. just after start of vblank,
+        * which also occurs at start of hsync (on the last active line),
+        * the scanline counter will read vblank_start-1.
+        */
+       return (position + 1) % vtotal;
 }
 
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -748,7 +788,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
        int position;
-       int vbl_start, vbl_end, htotal, vtotal;
+       int vbl_start, vbl_end, hsync_start, htotal, vtotal;
        bool in_vbl = true;
        int ret = 0;
        unsigned long irqflags;
@@ -760,6 +800,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        }
 
        htotal = mode->crtc_htotal;
+       hsync_start = mode->crtc_hsync_start;
        vtotal = mode->crtc_vtotal;
        vbl_start = mode->crtc_vblank_start;
        vbl_end = mode->crtc_vblank_end;
@@ -778,7 +819,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
         * following code must not block on uncore.lock.
         */
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-       
+
        /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
 
        /* Get optional system timestamp before query. */
@@ -789,68 +830,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                /* No obvious pixelcount register. Only query vertical
                 * scanout position from Display scan line register.
                 */
-               if (IS_GEN2(dev))
-                       position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
-               else
-                       position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
-
-               if (HAS_DDI(dev)) {
-                       /*
-                        * On HSW HDMI outputs there seems to be a 2 line
-                        * difference, whereas eDP has the normal 1 line
-                        * difference that earlier platforms have. External
-                        * DP is unknown. For now just check for the 2 line
-                        * difference case on all output types on HSW+.
-                        *
-                        * This might misinterpret the scanline counter being
-                        * one line too far along on eDP, but that's less
-                        * dangerous than the alternative since that would lead
-                        * the vblank timestamp code astray when it sees a
-                        * scanline count before vblank_start during a vblank
-                        * interrupt.
-                        */
-                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
-                       if ((in_vbl && (position == vbl_start - 2 ||
-                                       position == vbl_start - 1)) ||
-                           (!in_vbl && (position == vbl_end - 2 ||
-                                        position == vbl_end - 1)))
-                               position = (position + 2) % vtotal;
-               } else if (HAS_PCH_SPLIT(dev)) {
-                       /*
-                        * The scanline counter increments at the leading edge
-                        * of hsync, ie. it completely misses the active portion
-                        * of the line. Fix up the counter at both edges of vblank
-                        * to get a more accurate picture whether we're in vblank
-                        * or not.
-                        */
-                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
-                       if ((in_vbl && position == vbl_start - 1) ||
-                           (!in_vbl && position == vbl_end - 1))
-                               position = (position + 1) % vtotal;
-               } else {
-                       /*
-                        * ISR vblank status bits don't work the way we'd want
-                        * them to work on non-PCH platforms (for
-                        * ilk_pipe_in_vblank_locked()), and there doesn't
-                        * appear any other way to determine if we're currently
-                        * in vblank.
-                        *
-                        * Instead let's assume that we're already in vblank if
-                        * we got called from the vblank interrupt and the
-                        * scanline counter value indicates that we're on the
-                        * line just prior to vblank start. This should result
-                        * in the correct answer, unless the vblank interrupt
-                        * delivery really got delayed for almost exactly one
-                        * full frame/field.
-                        */
-                       if (flags & DRM_CALLED_FROM_VBLIRQ &&
-                           position == vbl_start - 1) {
-                               position = (position + 1) % vtotal;
-
-                               /* Signal this correction as "applied". */
-                               ret |= 0x8;
-                       }
-               }
+               position = __intel_get_crtc_scanline(intel_crtc);
        } else {
                /* Have access to pixelcount since start of frame.
                 * We can split this into vertical and horizontal
@@ -862,6 +842,17 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                vbl_start *= htotal;
                vbl_end *= htotal;
                vtotal *= htotal;
+
+               /*
+                * Start of vblank interrupt is triggered at start of hsync,
+                * just prior to the first active line of vblank. However we
+                * consider lines to start at the leading edge of horizontal
+                * active. So, should we get here before we've crossed into
+                * the horizontal active of the first line in vblank, we would
+                * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
+                * always add htotal-hsync_start to the current pixel position.
+                */
+               position = (position + htotal - hsync_start) % vtotal;
        }
 
        /* Get optional system timestamp after query. */
@@ -900,6 +891,19 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        return ret;
 }
 
+int intel_get_crtc_scanline(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       unsigned long irqflags;
+       int position;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       position = __intel_get_crtc_scanline(crtc);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+
+       return position;
+}
+
 static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                              int *max_error,
                              struct timeval *vblank_time,
@@ -1315,13 +1319,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
 
-       if (master_ctl & GEN8_GT_VCS1_IRQ) {
+       if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
                tmp = I915_READ(GEN8_GT_IIR(1));
                if (tmp) {
                        ret = IRQ_HANDLED;
                        vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, &dev_priv->ring[VCS]);
+                       vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+                       if (vcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[VCS2]);
                        I915_WRITE(GEN8_GT_IIR(1), tmp);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
@@ -1362,10 +1369,20 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
        spin_lock(&dev_priv->irq_lock);
        for (i = 1; i < HPD_NUM_PINS; i++) {
 
-               WARN_ONCE(hpd[i] & hotplug_trigger &&
-                         dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED,
-                         "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n",
-                         hotplug_trigger, i, hpd[i]);
+               if (hpd[i] & hotplug_trigger &&
+                   dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED) {
+                       /*
+                        * On GMCH platforms the interrupt mask bits only
+                        * prevent irq generation, not the setting of the
+                        * hotplug bits itself. So only WARN about unexpected
+                        * interrupts on saner platforms.
+                        */
+                       WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev),
+                                 "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n",
+                                 hotplug_trigger, i, hpd[i]);
+
+                       continue;
+               }
 
                if (!(hpd[i] & hotplug_trigger) ||
                    dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
@@ -1609,6 +1626,33 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
                gmbus_irq_handler(dev);
 }
 
+static void i9xx_hpd_irq_handler(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+
+       if (IS_G4X(dev)) {
+               u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
+
+               intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_g4x);
+       } else {
+               u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
+
+               intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+       }
+
+       if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) &&
+           hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
+               dp_aux_irq_handler(dev);
+
+       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
+       /*
+        * Make sure hotplug status is cleared before we clear IIR, or else we
+        * may miss hotplug events.
+        */
+       POSTING_READ(PORT_HOTPLUG_STAT);
+}
+
 static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -1631,19 +1675,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                valleyview_pipestat_irq_handler(dev, iir);
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if (iir & I915_DISPLAY_PORT_INTERRUPT) {
-                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-                       u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
-
-                       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-
-                       if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
-                               dp_aux_irq_handler(dev);
-
-                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-                       I915_READ(PORT_HOTPLUG_STAT);
-               }
-
+               if (iir & I915_DISPLAY_PORT_INTERRUPT)
+                       i9xx_hpd_irq_handler(dev);
 
                if (pm_iir)
                        gen6_rps_irq_handler(dev_priv, pm_iir);
@@ -2012,7 +2045,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir & GEN8_PIPE_VBLANK)
                        drm_handle_vblank(dev, pipe);
 
-               if (pipe_iir & GEN8_PIPE_FLIP_DONE) {
+               if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
                        intel_prepare_page_flip(dev, pipe);
                        intel_finish_page_flip_plane(dev, pipe);
                }
@@ -2126,6 +2159,14 @@ static void i915_error_work_func(struct work_struct *work)
                kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
                                   reset_event);
 
+               /*
+                * In most cases it's guaranteed that we get here with an RPM
+                * reference held, for example because there is a pending GPU
+                * request that won't finish until the reset is done. This
+                * isn't the case at least when we get here by doing a
+                * simulated reset via debugs, so get an RPM reference.
+                */
+               intel_runtime_pm_get(dev_priv);
                /*
                 * All state reset _must_ be completed before we update the
                 * reset counter, for otherwise waiters might miss the reset
@@ -2136,6 +2177,8 @@ static void i915_error_work_func(struct work_struct *work)
 
                intel_display_handle_reset(dev);
 
+               intel_runtime_pm_put(dev_priv);
+
                if (ret == 0) {
                        /*
                         * After all the gem state is reset, increment the reset
@@ -2501,6 +2544,55 @@ ring_idle(struct intel_ring_buffer *ring, u32 seqno)
                i915_seqno_passed(seqno, ring_last_seqno(ring)));
 }
 
+static bool
+ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr)
+{
+       if (INTEL_INFO(dev)->gen >= 8) {
+               /*
+                * FIXME: gen8 semaphore support - currently we don't emit
+                * semaphores on bdw anyway, but this needs to be addressed when
+                * we merge that code.
+                */
+               return false;
+       } else {
+               ipehr &= ~MI_SEMAPHORE_SYNC_MASK;
+               return ipehr == (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE |
+                                MI_SEMAPHORE_REGISTER);
+       }
+}
+
+static struct intel_ring_buffer *
+semaphore_wait_to_signaller_ring(struct intel_ring_buffer *ring, u32 ipehr)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct intel_ring_buffer *signaller;
+       int i;
+
+       if (INTEL_INFO(dev_priv->dev)->gen >= 8) {
+               /*
+                * FIXME: gen8 semaphore support - currently we don't emit
+                * semaphores on bdw anyway, but this needs to be addressed when
+                * we merge that code.
+                */
+               return NULL;
+       } else {
+               u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK;
+
+               for_each_ring(signaller, dev_priv, i) {
+                       if(ring == signaller)
+                               continue;
+
+                       if (sync_bits == signaller->semaphore.mbox.wait[ring->id])
+                               return signaller;
+               }
+       }
+
+       DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x\n",
+                 ring->id, ipehr);
+
+       return NULL;
+}
+
 static struct intel_ring_buffer *
 semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
 {
@@ -2509,8 +2601,7 @@ semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
        int i;
 
        ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
-       if ((ipehr & ~(0x3 << 16)) !=
-           (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
+       if (!ipehr_is_semaphore_wait(ring->dev, ipehr))
                return NULL;
 
        /*
@@ -2542,7 +2633,7 @@ semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
                return NULL;
 
        *seqno = ioread32(ring->virtual_start + head + 4) + 1;
-       return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
+       return semaphore_wait_to_signaller_ring(ring, ipehr);
 }
 
 static int semaphore_passed(struct intel_ring_buffer *ring)
@@ -2749,57 +2840,68 @@ void i915_queue_hangcheck(struct drm_device *dev)
                  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
 }
 
-static void ibx_irq_preinstall(struct drm_device *dev)
+static void ibx_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (HAS_PCH_NOP(dev))
                return;
 
-       /* south display irq */
-       I915_WRITE(SDEIMR, 0xffffffff);
-       /*
-        * SDEIER is also touched by the interrupt handler to work around missed
-        * PCH interrupts. Hence we can't update it after the interrupt handler
-        * is enabled - instead we unconditionally enable all PCH interrupt
-        * sources here, but then only unmask them as needed with SDEIMR.
-        */
+       GEN5_IRQ_RESET(SDE);
+
+       if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
+               I915_WRITE(SERR_INT, 0xffffffff);
+}
+
+/*
+ * SDEIER is also touched by the interrupt handler to work around missed PCH
+ * interrupts. Hence we can't update it after the interrupt handler is enabled -
+ * instead we unconditionally enable all PCH interrupt sources here, but then
+ * only unmask them as needed with SDEIMR.
+ *
+ * This function needs to be called before interrupts are enabled.
+ */
+static void ibx_irq_pre_postinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (HAS_PCH_NOP(dev))
+               return;
+
+       WARN_ON(I915_READ(SDEIER) != 0);
        I915_WRITE(SDEIER, 0xffffffff);
        POSTING_READ(SDEIER);
 }
 
-static void gen5_gt_irq_preinstall(struct drm_device *dev)
+static void gen5_gt_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* and GT */
-       I915_WRITE(GTIMR, 0xffffffff);
-       I915_WRITE(GTIER, 0x0);
-       POSTING_READ(GTIER);
-
-       if (INTEL_INFO(dev)->gen >= 6) {
-               /* and PM */
-               I915_WRITE(GEN6_PMIMR, 0xffffffff);
-               I915_WRITE(GEN6_PMIER, 0x0);
-               POSTING_READ(GEN6_PMIER);
-       }
+       GEN5_IRQ_RESET(GT);
+       if (INTEL_INFO(dev)->gen >= 6)
+               GEN5_IRQ_RESET(GEN6_PM);
 }
 
 /* drm_dma.h hooks
 */
-static void ironlake_irq_preinstall(struct drm_device *dev)
+static void ironlake_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       I915_WRITE(HWSTAM, 0xeffe);
+       I915_WRITE(HWSTAM, 0xffffffff);
 
-       I915_WRITE(DEIMR, 0xffffffff);
-       I915_WRITE(DEIER, 0x0);
-       POSTING_READ(DEIER);
+       GEN5_IRQ_RESET(DE);
+       if (IS_GEN7(dev))
+               I915_WRITE(GEN7_ERR_INT, 0xffffffff);
 
-       gen5_gt_irq_preinstall(dev);
+       gen5_gt_irq_reset(dev);
 
-       ibx_irq_preinstall(dev);
+       ibx_irq_reset(dev);
+}
+
+static void ironlake_irq_preinstall(struct drm_device *dev)
+{
+       ironlake_irq_reset(dev);
 }
 
 static void valleyview_irq_preinstall(struct drm_device *dev)
@@ -2817,7 +2919,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIIR, I915_READ(GTIIR));
 
-       gen5_gt_irq_preinstall(dev);
+       gen5_gt_irq_reset(dev);
 
        I915_WRITE(DPINVGTT, 0xff);
 
@@ -2831,7 +2933,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 }
 
-static void gen8_irq_preinstall(struct drm_device *dev)
+static void gen8_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
@@ -2839,43 +2941,24 @@ static void gen8_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GEN8_MASTER_IRQ, 0);
        POSTING_READ(GEN8_MASTER_IRQ);
 
-       /* IIR can theoretically queue up two events. Be paranoid */
-#define GEN8_IRQ_INIT_NDX(type, which) do { \
-               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IMR(which)); \
-               I915_WRITE(GEN8_##type##_IER(which), 0); \
-               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IIR(which)); \
-               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
-       } while (0)
-
-#define GEN8_IRQ_INIT(type) do { \
-               I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IMR); \
-               I915_WRITE(GEN8_##type##_IER, 0); \
-               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IIR); \
-               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
-       } while (0)
-
-       GEN8_IRQ_INIT_NDX(GT, 0);
-       GEN8_IRQ_INIT_NDX(GT, 1);
-       GEN8_IRQ_INIT_NDX(GT, 2);
-       GEN8_IRQ_INIT_NDX(GT, 3);
+       GEN8_IRQ_RESET_NDX(GT, 0);
+       GEN8_IRQ_RESET_NDX(GT, 1);
+       GEN8_IRQ_RESET_NDX(GT, 2);
+       GEN8_IRQ_RESET_NDX(GT, 3);
 
-       for_each_pipe(pipe) {
-               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe);
-       }
+       for_each_pipe(pipe)
+               GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
 
-       GEN8_IRQ_INIT(DE_PORT);
-       GEN8_IRQ_INIT(DE_MISC);
-       GEN8_IRQ_INIT(PCU);
-#undef GEN8_IRQ_INIT
-#undef GEN8_IRQ_INIT_NDX
+       GEN5_IRQ_RESET(GEN8_DE_PORT_);
+       GEN5_IRQ_RESET(GEN8_DE_MISC_);
+       GEN5_IRQ_RESET(GEN8_PCU_);
 
-       POSTING_READ(GEN8_PCU_IIR);
+       ibx_irq_reset(dev);
+}
 
-       ibx_irq_preinstall(dev);
+static void gen8_irq_preinstall(struct drm_device *dev)
+{
+       gen8_irq_reset(dev);
 }
 
 static void ibx_hpd_irq_setup(struct drm_device *dev)
@@ -2921,15 +3004,12 @@ static void ibx_irq_postinstall(struct drm_device *dev)
        if (HAS_PCH_NOP(dev))
                return;
 
-       if (HAS_PCH_IBX(dev)) {
+       if (HAS_PCH_IBX(dev))
                mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
-       } else {
+       else
                mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
 
-               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
-       }
-
-       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+       GEN5_ASSERT_IIR_IS_ZERO(SDEIIR);
        I915_WRITE(SDEIMR, ~mask);
 }
 
@@ -2955,10 +3035,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
                gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
        }
 
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-       I915_WRITE(GTIER, gt_irqs);
-       POSTING_READ(GTIER);
+       GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
 
        if (INTEL_INFO(dev)->gen >= 6) {
                pm_irqs |= dev_priv->pm_rps_events;
@@ -2967,10 +3044,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
                        pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
                dev_priv->pm_irq_mask = 0xffffffff;
-               I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-               I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask);
-               I915_WRITE(GEN6_PMIER, pm_irqs);
-               POSTING_READ(GEN6_PMIER);
+               GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_irq_mask, pm_irqs);
        }
 }
 
@@ -2987,8 +3061,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                                DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
                extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
                              DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
-
-               I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
        } else {
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                                DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
@@ -3001,11 +3073,11 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 
        dev_priv->irq_mask = ~display_mask;
 
-       /* should always can generate irq */
-       I915_WRITE(DEIIR, I915_READ(DEIIR));
-       I915_WRITE(DEIMR, dev_priv->irq_mask);
-       I915_WRITE(DEIER, display_mask | extra_mask);
-       POSTING_READ(DEIER);
+       I915_WRITE(HWSTAM, 0xeffe);
+
+       ibx_irq_pre_postinstall(dev);
+
+       GEN5_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask);
 
        gen5_gt_irq_postinstall(dev);
 
@@ -3165,21 +3237,14 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
                GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
                };
 
-       for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) {
-               u32 tmp = I915_READ(GEN8_GT_IIR(i));
-               if (tmp)
-                       DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
-                                 i, tmp);
-               I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]);
-               I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]);
-       }
-       POSTING_READ(GEN8_GT_IER(0));
+       for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
+               GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]);
 }
 
 static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
-       uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
+       uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_FLIP_DONE |
                GEN8_PIPE_CDCLK_CRC_DONE |
                GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
        uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
@@ -3189,25 +3254,19 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
 
-       for_each_pipe(pipe) {
-               u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe));
-               if (tmp)
-                       DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
-                                 pipe, tmp);
-               I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
-               I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables);
-       }
-       POSTING_READ(GEN8_DE_PIPE_ISR(0));
+       for_each_pipe(pipe)
+               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe, dev_priv->de_irq_mask[pipe],
+                                 de_pipe_enables);
 
-       I915_WRITE(GEN8_DE_PORT_IMR, ~GEN8_AUX_CHANNEL_A);
-       I915_WRITE(GEN8_DE_PORT_IER, GEN8_AUX_CHANNEL_A);
-       POSTING_READ(GEN8_DE_PORT_IER);
+       GEN5_IRQ_INIT(GEN8_DE_PORT_, ~GEN8_AUX_CHANNEL_A, GEN8_AUX_CHANNEL_A);
 }
 
 static int gen8_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       ibx_irq_pre_postinstall(dev);
+
        gen8_gt_irq_postinstall(dev_priv);
        gen8_de_irq_postinstall(dev_priv);
 
@@ -3222,41 +3281,13 @@ static int gen8_irq_postinstall(struct drm_device *dev)
 static void gen8_irq_uninstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe;
 
        if (!dev_priv)
                return;
 
-       I915_WRITE(GEN8_MASTER_IRQ, 0);
-
-#define GEN8_IRQ_FINI_NDX(type, which) do { \
-               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
-               I915_WRITE(GEN8_##type##_IER(which), 0); \
-               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
-       } while (0)
-
-#define GEN8_IRQ_FINI(type) do { \
-               I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
-               I915_WRITE(GEN8_##type##_IER, 0); \
-               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
-       } while (0)
-
-       GEN8_IRQ_FINI_NDX(GT, 0);
-       GEN8_IRQ_FINI_NDX(GT, 1);
-       GEN8_IRQ_FINI_NDX(GT, 2);
-       GEN8_IRQ_FINI_NDX(GT, 3);
-
-       for_each_pipe(pipe) {
-               GEN8_IRQ_FINI_NDX(DE_PIPE, pipe);
-       }
-
-       GEN8_IRQ_FINI(DE_PORT);
-       GEN8_IRQ_FINI(DE_MISC);
-       GEN8_IRQ_FINI(PCU);
-#undef GEN8_IRQ_FINI
-#undef GEN8_IRQ_FINI_NDX
+       intel_hpd_irq_uninstall(dev_priv);
 
-       POSTING_READ(GEN8_PCU_IIR);
+       gen8_irq_reset(dev);
 }
 
 static void valleyview_irq_uninstall(struct drm_device *dev)
@@ -3268,6 +3299,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
+       I915_WRITE(VLV_MASTER_IER, 0);
+
        intel_hpd_irq_uninstall(dev_priv);
 
        for_each_pipe(pipe)
@@ -3299,26 +3332,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
 
        intel_hpd_irq_uninstall(dev_priv);
 
-       I915_WRITE(HWSTAM, 0xffffffff);
-
-       I915_WRITE(DEIMR, 0xffffffff);
-       I915_WRITE(DEIER, 0x0);
-       I915_WRITE(DEIIR, I915_READ(DEIIR));
-       if (IS_GEN7(dev))
-               I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
-
-       I915_WRITE(GTIMR, 0xffffffff);
-       I915_WRITE(GTIER, 0x0);
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
-
-       if (HAS_PCH_NOP(dev))
-               return;
-
-       I915_WRITE(SDEIMR, 0xffffffff);
-       I915_WRITE(SDEIER, 0x0);
-       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
-       if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
-               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
+       ironlake_irq_reset(dev);
 }
 
 static void i8xx_irq_preinstall(struct drm_device * dev)
@@ -3626,16 +3640,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                        break;
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if ((I915_HAS_HOTPLUG(dev)) &&
-                   (iir & I915_DISPLAY_PORT_INTERRUPT)) {
-                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-                       u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
-
-                       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-
-                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-                       POSTING_READ(PORT_HOTPLUG_STAT);
-               }
+               if (I915_HAS_HOTPLUG(dev) &&
+                   iir & I915_DISPLAY_PORT_INTERRUPT)
+                       i9xx_hpd_irq_handler(dev);
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -3869,22 +3876,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                ret = IRQ_HANDLED;
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if (iir & I915_DISPLAY_PORT_INTERRUPT) {
-                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-                       u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
-                                                                 HOTPLUG_INT_STATUS_G4X :
-                                                                 HOTPLUG_INT_STATUS_I915);
-
-                       intel_hpd_irq_handler(dev, hotplug_trigger,
-                                             IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
-
-                       if (IS_G4X(dev) &&
-                           (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X))
-                               dp_aux_irq_handler(dev);
-
-                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-                       I915_READ(PORT_HOTPLUG_STAT);
-               }
+               if (iir & I915_DISPLAY_PORT_INTERRUPT)
+                       i9xx_hpd_irq_handler(dev);
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -4111,57 +4104,20 @@ void intel_hpd_init(struct drm_device *dev)
 }
 
 /* Disable interrupts so we can allow runtime PM. */
-void hsw_runtime_pm_disable_interrupts(struct drm_device *dev)
+void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
-       dev_priv->pm.regsave.deimr = I915_READ(DEIMR);
-       dev_priv->pm.regsave.sdeimr = I915_READ(SDEIMR);
-       dev_priv->pm.regsave.gtimr = I915_READ(GTIMR);
-       dev_priv->pm.regsave.gtier = I915_READ(GTIER);
-       dev_priv->pm.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
-
-       ironlake_disable_display_irq(dev_priv, 0xffffffff);
-       ibx_disable_display_interrupt(dev_priv, 0xffffffff);
-       ilk_disable_gt_irq(dev_priv, 0xffffffff);
-       snb_disable_pm_irq(dev_priv, 0xffffffff);
 
+       dev->driver->irq_uninstall(dev);
        dev_priv->pm.irqs_disabled = true;
-
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
 /* Restore interrupts so we can recover from runtime PM. */
-void hsw_runtime_pm_restore_interrupts(struct drm_device *dev)
+void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
-       uint32_t val;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
-       val = I915_READ(DEIMR);
-       WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val);
-
-       val = I915_READ(SDEIMR);
-       WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val);
-
-       val = I915_READ(GTIMR);
-       WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val);
-
-       val = I915_READ(GEN6_PMIMR);
-       WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val);
 
        dev_priv->pm.irqs_disabled = false;
-
-       ironlake_enable_display_irq(dev_priv, ~dev_priv->pm.regsave.deimr);
-       ibx_enable_display_interrupt(dev_priv, ~dev_priv->pm.regsave.sdeimr);
-       ilk_enable_gt_irq(dev_priv, ~dev_priv->pm.regsave.gtimr);
-       snb_enable_pm_irq(dev_priv, ~dev_priv->pm.regsave.gen6_pmimr);
-       I915_WRITE(GTIER, dev_priv->pm.regsave.gtier);
-
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       dev->driver->irq_preinstall(dev);
+       dev->driver->irq_postinstall(dev);
 }
index d1d7980f0e010cc3d48ee86ce4699b3068ce47be..d05a2afa17dc605acc294e0e15ae88ac200b5093 100644 (file)
@@ -46,7 +46,8 @@ struct i915_params i915 __read_mostly = {
        .reset = true,
        .invert_brightness = 0,
        .disable_display = 0,
-       .enable_cmd_parser = 0,
+       .enable_cmd_parser = 1,
+       .disable_vtd_wa = 0,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -149,6 +150,9 @@ MODULE_PARM_DESC(invert_brightness,
 module_param_named(disable_display, i915.disable_display, bool, 0600);
 MODULE_PARM_DESC(disable_display, "Disable display (default: false)");
 
+module_param_named(disable_vtd_wa, i915.disable_vtd_wa, bool, 0600);
+MODULE_PARM_DESC(disable_vtd_wa, "Disable all VT-d workarounds (default: false)");
+
 module_param_named(enable_cmd_parser, i915.enable_cmd_parser, int, 0600);
 MODULE_PARM_DESC(enable_cmd_parser,
-                "Enable command parsing (1=enabled, 0=disabled [default])");
+                "Enable command parsing (1=enabled [default], 0=disabled)");
index 9f5b18d9d8850e886eeb44ca68b0bd17af4c3f30..0eff337a572059e229defa84b911143c7bf90455 100644 (file)
  * Memory interface instructions used by the kernel
  */
 #define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+/* Many MI commands use bit 22 of the header dword for GGTT vs PPGTT */
+#define  MI_GLOBAL_GTT    (1<<22)
 
 #define MI_NOOP                        MI_INSTR(0, 0)
 #define MI_USER_INTERRUPT      MI_INSTR(0x02, 0)
 #define   MI_SEMAPHORE_SYNC_BVE            (0<<16) /* VECS wait for BCS  (VEBSYNC) */
 #define   MI_SEMAPHORE_SYNC_VVE            (1<<16) /* VECS wait for VCS  (VEVSYNC) */
 #define   MI_SEMAPHORE_SYNC_RVE            (2<<16) /* VECS wait for RCS  (VERSYNC) */
-#define   MI_SEMAPHORE_SYNC_INVALID  (3<<16)
+#define   MI_SEMAPHORE_SYNC_INVALID (3<<16)
+#define   MI_SEMAPHORE_SYNC_MASK    (3<<16)
 #define MI_SET_CONTEXT         MI_INSTR(0x18, 0)
 #define   MI_MM_SPACE_GTT              (1<<8)
 #define   MI_MM_SPACE_PHYSICAL         (0<<8)
  * - One can actually load arbitrary many arbitrary registers: Simply issue x
  *   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_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*(x)-1)
+#define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1)
+#define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1)
 #define   MI_SRM_LRM_GLOBAL_GTT                (1<<22)
 #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   MI_FLUSH_DW_OP_STOREDW       (1<<14)
+#define   MI_FLUSH_DW_OP_MASK          (3<<14)
+#define   MI_FLUSH_DW_NOTIFY           (1<<8)
 #define   MI_INVALIDATE_BSD            (1<<7)
 #define   MI_FLUSH_DW_USE_GTT          (1<<2)
 #define   MI_FLUSH_DW_USE_PPGTT                (0<<2)
 #define   DISPLAY_PLANE_B           (1<<20)
 #define GFX_OP_PIPE_CONTROL(len)       ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2))
 #define   PIPE_CONTROL_GLOBAL_GTT_IVB                  (1<<24) /* gen7+ */
+#define   PIPE_CONTROL_MMIO_WRITE                      (1<<23)
+#define   PIPE_CONTROL_STORE_DATA_INDEX                        (1<<21)
 #define   PIPE_CONTROL_CS_STALL                                (1<<20)
 #define   PIPE_CONTROL_TLB_INVALIDATE                  (1<<18)
 #define   PIPE_CONTROL_QW_WRITE                                (1<<14)
+#define   PIPE_CONTROL_POST_SYNC_OP_MASK                (3<<14)
 #define   PIPE_CONTROL_DEPTH_STALL                     (1<<13)
 #define   PIPE_CONTROL_WRITE_FLUSH                     (1<<12)
 #define   PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH       (1<<12) /* gen6+ */
 #define   PIPE_CONTROL_DEPTH_CACHE_FLUSH               (1<<0)
 #define   PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
 
+/*
+ * Commands used only by the command parser
+ */
+#define MI_SET_PREDICATE        MI_INSTR(0x01, 0)
+#define MI_ARB_CHECK            MI_INSTR(0x05, 0)
+#define MI_RS_CONTROL           MI_INSTR(0x06, 0)
+#define MI_URB_ATOMIC_ALLOC     MI_INSTR(0x09, 0)
+#define MI_PREDICATE            MI_INSTR(0x0C, 0)
+#define MI_RS_CONTEXT           MI_INSTR(0x0F, 0)
+#define MI_TOPOLOGY_FILTER      MI_INSTR(0x0D, 0)
+#define MI_LOAD_SCAN_LINES_EXCL MI_INSTR(0x13, 0)
+#define MI_URB_CLEAR            MI_INSTR(0x19, 0)
+#define MI_UPDATE_GTT           MI_INSTR(0x23, 0)
+#define MI_CLFLUSH              MI_INSTR(0x27, 0)
+#define MI_REPORT_PERF_COUNT    MI_INSTR(0x28, 0)
+#define   MI_REPORT_PERF_COUNT_GGTT (1<<0)
+#define MI_LOAD_REGISTER_MEM    MI_INSTR(0x29, 0)
+#define MI_LOAD_REGISTER_REG    MI_INSTR(0x2A, 0)
+#define MI_RS_STORE_DATA_IMM    MI_INSTR(0x2B, 0)
+#define MI_LOAD_URB_MEM         MI_INSTR(0x2C, 0)
+#define MI_STORE_URB_MEM        MI_INSTR(0x2D, 0)
+#define MI_CONDITIONAL_BATCH_BUFFER_END MI_INSTR(0x36, 0)
+
+#define PIPELINE_SELECT                ((0x3<<29)|(0x1<<27)|(0x1<<24)|(0x4<<16))
+#define GFX_OP_3DSTATE_VF_STATISTICS   ((0x3<<29)|(0x1<<27)|(0x0<<24)|(0xB<<16))
+#define MEDIA_VFE_STATE                ((0x3<<29)|(0x2<<27)|(0x0<<24)|(0x0<<16))
+#define  MEDIA_VFE_STATE_MMIO_ACCESS_MASK (0x18)
+#define GPGPU_OBJECT                   ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x4<<16))
+#define GPGPU_WALKER                   ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x5<<16))
+#define GFX_OP_3DSTATE_DX9_CONSTANTF_VS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x39<<16))
+#define GFX_OP_3DSTATE_DX9_CONSTANTF_PS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x3A<<16))
+#define GFX_OP_3DSTATE_SO_DECL_LIST \
+       ((0x3<<29)|(0x3<<27)|(0x1<<24)|(0x17<<16))
+
+#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x43<<16))
+#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x44<<16))
+#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x45<<16))
+#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x46<<16))
+#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS \
+       ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x47<<16))
+
+#define MFX_WAIT  ((0x3<<29)|(0x1<<27)|(0x0<<16))
+
+#define COLOR_BLT     ((0x2<<29)|(0x40<<22))
+#define SRC_COPY_BLT  ((0x2<<29)|(0x43<<22))
+
+/*
+ * Registers used only by the command parser
+ */
+#define BCS_SWCTRL 0x22200
+
+#define HS_INVOCATION_COUNT 0x2300
+#define DS_INVOCATION_COUNT 0x2308
+#define IA_VERTICES_COUNT   0x2310
+#define IA_PRIMITIVES_COUNT 0x2318
+#define VS_INVOCATION_COUNT 0x2320
+#define GS_INVOCATION_COUNT 0x2328
+#define GS_PRIMITIVES_COUNT 0x2330
+#define CL_INVOCATION_COUNT 0x2338
+#define CL_PRIMITIVES_COUNT 0x2340
+#define PS_INVOCATION_COUNT 0x2348
+#define PS_DEPTH_COUNT      0x2350
+
+/* There are the 4 64-bit counter registers, one for each stream output */
+#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8)
+
+#define GEN7_SO_PRIM_STORAGE_NEEDED(n)  (0x5240 + (n) * 8)
+
+#define GEN7_3DPRIM_END_OFFSET          0x2420
+#define GEN7_3DPRIM_START_VERTEX        0x2430
+#define GEN7_3DPRIM_VERTEX_COUNT        0x2434
+#define GEN7_3DPRIM_INSTANCE_COUNT      0x2438
+#define GEN7_3DPRIM_START_INSTANCE      0x243C
+#define GEN7_3DPRIM_BASE_VERTEX         0x2440
+
+#define OACONTROL 0x2360
+
+#define _GEN7_PIPEA_DE_LOAD_SL 0x70068
+#define _GEN7_PIPEB_DE_LOAD_SL 0x71068
+#define GEN7_PIPE_DE_LOAD_SL(pipe) _PIPE(pipe, \
+                                        _GEN7_PIPEA_DE_LOAD_SL, \
+                                        _GEN7_PIPEB_DE_LOAD_SL)
 
 /*
  * Reset registers
@@ -663,6 +760,7 @@ enum punit_power_well {
 #define RENDER_RING_BASE       0x02000
 #define BSD_RING_BASE          0x04000
 #define GEN6_BSD_RING_BASE     0x12000
+#define GEN8_BSD2_RING_BASE    0x1c000
 #define VEBOX_RING_BASE                0x1a000
 #define BLT_RING_BASE          0x22000
 #define RING_TAIL(base)                ((base)+0x30)
@@ -748,6 +846,7 @@ enum punit_power_well {
 #define RING_INSTDONE(base)    ((base)+0x6c)
 #define RING_INSTPS(base)      ((base)+0x70)
 #define RING_DMA_FADD(base)    ((base)+0x78)
+#define RING_DMA_FADD_UDW(base)        ((base)+0x60) /* gen8+ */
 #define RING_INSTPM(base)      ((base)+0xc0)
 #define RING_MI_MODE(base)     ((base)+0x9c)
 #define INSTPS         0x02070 /* 965+ only */
@@ -827,6 +926,7 @@ enum punit_power_well {
 # define MI_FLUSH_ENABLE                               (1 << 12)
 # define ASYNC_FLIP_PERF_DISABLE                       (1 << 14)
 # define MODE_IDLE                                     (1 << 9)
+# define STOP_RING                                     (1 << 8)
 
 #define GEN6_GT_MODE   0x20d0
 #define GEN7_GT_MODE   0x7008
@@ -841,7 +941,7 @@ enum punit_power_well {
 #define GFX_MODE_GEN7  0x0229c
 #define RING_MODE_GEN7(ring)   ((ring)->mmio_base+0x29c)
 #define   GFX_RUN_LIST_ENABLE          (1<<15)
-#define   GFX_TLB_INVALIDATE_ALWAYS    (1<<13)
+#define   GFX_TLB_INVALIDATE_EXPLICIT  (1<<13)
 #define   GFX_SURFACE_FAULT_ENABLE     (1<<12)
 #define   GFX_REPLAY_MODE              (1<<11)
 #define   GFX_PSMI_GRANULARITY         (1<<10)
@@ -972,6 +1072,7 @@ enum punit_power_well {
 #define   ECO_FLIP_DONE                (1<<0)
 
 #define CACHE_MODE_0_GEN7      0x7000 /* IVB+ */
+#define RC_OP_FLUSH_ENABLE (1<<0)
 #define   HIZ_RAW_STALL_OPT_DISABLE (1<<2)
 #define CACHE_MODE_1           0x7004 /* IVB+ */
 #define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE    (1<<6)
@@ -3257,6 +3358,7 @@ enum punit_power_well {
 #define   PIPECONF_INTERLACED_DBL_ILK          (4 << 21) /* ilk/snb only */
 #define   PIPECONF_PFIT_PF_INTERLACED_DBL_ILK  (5 << 21) /* ilk/snb only */
 #define   PIPECONF_INTERLACE_MODE_MASK         (7 << 21)
+#define   PIPECONF_EDP_RR_MODE_SWITCH          (1 << 20)
 #define   PIPECONF_CXSR_DOWNCLOCK      (1<<16)
 #define   PIPECONF_COLOR_RANGE_SELECT  (1 << 13)
 #define   PIPECONF_BPC_MASK    (0x7 << 5)
@@ -3534,9 +3636,9 @@ enum punit_power_well {
 #define   PIPE_PIXEL_MASK         0x00ffffff
 #define   PIPE_PIXEL_SHIFT        0
 /* GM45+ just has to be different */
-#define _PIPEA_FRMCOUNT_GM45   (dev_priv->info.display_mmio_offset + 0x70040)
-#define _PIPEA_FLIPCOUNT_GM45  (dev_priv->info.display_mmio_offset + 0x70044)
-#define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45)
+#define _PIPEA_FRMCOUNT_GM45   0x70040
+#define _PIPEA_FLIPCOUNT_GM45  0x70044
+#define PIPE_FRMCOUNT_GM45(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_GM45)
 
 /* Cursor A & B regs */
 #define _CURACNTR              (dev_priv->info.display_mmio_offset + 0x70080)
@@ -4119,7 +4221,7 @@ enum punit_power_well {
 #define  GEN8_PIPE_SPRITE_FAULT                (1 << 9)
 #define  GEN8_PIPE_PRIMARY_FAULT       (1 << 8)
 #define  GEN8_PIPE_SPRITE_FLIP_DONE    (1 << 5)
-#define  GEN8_PIPE_FLIP_DONE           (1 << 4)
+#define  GEN8_PIPE_PRIMARY_FLIP_DONE   (1 << 4)
 #define  GEN8_PIPE_SCAN_LINE_EVENT     (1 << 2)
 #define  GEN8_PIPE_VSYNC               (1 << 1)
 #define  GEN8_PIPE_VBLANK              (1 << 0)
@@ -4895,9 +4997,15 @@ enum punit_power_well {
 #define  FORCEWAKE_ACK_HSW                     0x130044
 #define  FORCEWAKE_ACK                         0x130090
 #define  VLV_GTLC_WAKE_CTRL                    0x130090
+#define   VLV_GTLC_RENDER_CTX_EXISTS           (1 << 25)
+#define   VLV_GTLC_MEDIA_CTX_EXISTS            (1 << 24)
+#define   VLV_GTLC_ALLOWWAKEREQ                        (1 << 0)
+
 #define  VLV_GTLC_PW_STATUS                    0x130094
-#define VLV_GTLC_PW_RENDER_STATUS_MASK         0x80
-#define VLV_GTLC_PW_MEDIA_STATUS_MASK          0x20
+#define   VLV_GTLC_ALLOWWAKEACK                        (1 << 0)
+#define   VLV_GTLC_ALLOWWAKEERR                        (1 << 1)
+#define   VLV_GTLC_PW_MEDIA_STATUS_MASK                (1 << 5)
+#define   VLV_GTLC_PW_RENDER_STATUS_MASK       (1 << 7)
 #define  FORCEWAKE_MT                          0xa188 /* multi-threaded */
 #define   FORCEWAKE_KERNEL                     0x1
 #define   FORCEWAKE_USER                       0x2
@@ -5029,6 +5137,9 @@ enum punit_power_well {
 #define   VLV_MEDIA_RC6_COUNT_EN               (1<<1)
 #define   VLV_RENDER_RC6_COUNT_EN              (1<<0)
 #define GEN6_GT_GFX_RC6                                0x138108
+#define VLV_GT_RENDER_RC6                      0x138108
+#define VLV_GT_MEDIA_RC6                       0x13810C
+
 #define GEN6_GT_GFX_RC6p                       0x13810C
 #define GEN6_GT_GFX_RC6pp                      0x138110
 
index 9c57029f6f4b4b9ba6b63ce2493eac4942f5eb59..3620997e43f50bd3089f760cc2a50e374a6fd502 100644 (file)
@@ -263,6 +263,8 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
 
        flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
+       intel_runtime_pm_get(dev_priv);
+
        mutex_lock(&dev_priv->rps.hw_lock);
        if (IS_VALLEYVIEW(dev_priv->dev)) {
                u32 freq;
@@ -273,6 +275,8 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 
+       intel_runtime_pm_put(dev_priv);
+
        return snprintf(buf, PAGE_SIZE, "%d\n", ret);
 }
 
index fa486c5fbb0250650b558632c6f63aa0ebf5bd63..2945f57c53ee9a56cb59007c8f5e891e4df52bee 100644 (file)
@@ -49,13 +49,19 @@ find_section(struct bdb_header *bdb, int section_id)
        total = bdb->bdb_size;
 
        /* walk the sections looking for section_id */
-       while (index < total) {
+       while (index + 3 < total) {
                current_id = *(base + index);
                index++;
+
                current_size = *((u16 *)(base + index));
                index += 2;
+
+               if (index + current_size > total)
+                       return NULL;
+
                if (current_id == section_id)
                        return base + index;
+
                index += current_size;
        }
 
@@ -206,7 +212,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        const struct lvds_dvo_timing *panel_dvo_timing;
        const struct lvds_fp_timing *fp_timing;
        struct drm_display_mode *panel_fixed_mode;
-       int i, downclock;
+       int i, downclock, drrs_mode;
 
        lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
        if (!lvds_options)
@@ -218,6 +224,28 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 
        panel_type = lvds_options->panel_type;
 
+       drrs_mode = (lvds_options->dps_panel_type_bits
+                               >> (panel_type * 2)) & MODE_MASK;
+       /*
+        * VBT has static DRRS = 0 and seamless DRRS = 2.
+        * The below piece of code is required to adjust vbt.drrs_type
+        * to match the enum drrs_support_type.
+        */
+       switch (drrs_mode) {
+       case 0:
+               dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT;
+               DRM_DEBUG_KMS("DRRS supported mode is static\n");
+               break;
+       case 2:
+               dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT;
+               DRM_DEBUG_KMS("DRRS supported mode is seamless\n");
+               break;
+       default:
+               dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED;
+               DRM_DEBUG_KMS("DRRS not supported (VBT input)\n");
+               break;
+       }
+
        lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
        if (!lvds_lfp_data)
                return;
@@ -526,6 +554,16 @@ parse_driver_features(struct drm_i915_private *dev_priv,
 
        if (driver->dual_frequency)
                dev_priv->render_reclock_avail = true;
+
+       DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled);
+       /*
+        * If DRRS is not supported, drrs_type has to be set to 0.
+        * This is because, VBT is configured in such a way that
+        * static DRRS is 0 and DRRS not supported is represented by
+        * driver->drrs_enabled=false
+        */
+       if (!driver->drrs_enabled)
+               dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED;
 }
 
 static void
@@ -604,19 +642,217 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
        }
 }
 
+static u8 *goto_next_sequence(u8 *data, int *size)
+{
+       u16 len;
+       int tmp = *size;
+
+       if (--tmp < 0)
+               return NULL;
+
+       /* goto first element */
+       data++;
+       while (1) {
+               switch (*data) {
+               case MIPI_SEQ_ELEM_SEND_PKT:
+                       /*
+                        * skip by this element payload size
+                        * skip elem id, command flag and data type
+                        */
+                       tmp -= 5;
+                       if (tmp < 0)
+                               return NULL;
+
+                       data += 3;
+                       len = *((u16 *)data);
+
+                       tmp -= len;
+                       if (tmp < 0)
+                               return NULL;
+
+                       /* skip by len */
+                       data = data + 2 + len;
+                       break;
+               case MIPI_SEQ_ELEM_DELAY:
+                       /* skip by elem id, and delay is 4 bytes */
+                       tmp -= 5;
+                       if (tmp < 0)
+                               return NULL;
+
+                       data += 5;
+                       break;
+               case MIPI_SEQ_ELEM_GPIO:
+                       tmp -= 3;
+                       if (tmp < 0)
+                               return NULL;
+
+                       data += 3;
+                       break;
+               default:
+                       DRM_ERROR("Unknown element\n");
+                       return NULL;
+               }
+
+               /* end of sequence ? */
+               if (*data == 0)
+                       break;
+       }
+
+       /* goto next sequence or end of block byte */
+       if (--tmp < 0)
+               return NULL;
+
+       data++;
+
+       /* update amount of data left for the sequence block to be parsed */
+       *size = tmp;
+       return data;
+}
+
 static void
 parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 {
-       struct bdb_mipi *mipi;
+       struct bdb_mipi_config *start;
+       struct bdb_mipi_sequence *sequence;
+       struct mipi_config *config;
+       struct mipi_pps_data *pps;
+       u8 *data, *seq_data;
+       int i, panel_id, seq_size;
+       u16 block_size;
+
+       /* Initialize this to undefined indicating no generic MIPI support */
+       dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID;
+
+       /* Block #40 is already parsed and panel_fixed_mode is
+        * stored in dev_priv->lfp_lvds_vbt_mode
+        * resuse this when needed
+        */
 
-       mipi = find_section(bdb, BDB_MIPI_CONFIG);
-       if (!mipi) {
-               DRM_DEBUG_KMS("No MIPI BDB found");
+       /* Parse #52 for panel index used from panel_type already
+        * parsed
+        */
+       start = find_section(bdb, BDB_MIPI_CONFIG);
+       if (!start) {
+               DRM_DEBUG_KMS("No MIPI config BDB found");
                return;
        }
 
-       /* XXX: add more info */
+       DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n",
+                                                               panel_type);
+
+       /*
+        * get hold of the correct configuration block and pps data as per
+        * the panel_type as index
+        */
+       config = &start->config[panel_type];
+       pps = &start->pps[panel_type];
+
+       /* store as of now full data. Trim when we realise all is not needed */
+       dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL);
+       if (!dev_priv->vbt.dsi.config)
+               return;
+
+       dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL);
+       if (!dev_priv->vbt.dsi.pps) {
+               kfree(dev_priv->vbt.dsi.config);
+               return;
+       }
+
+       /* We have mandatory mipi config blocks. Initialize as generic panel */
        dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
+
+       /* Check if we have sequence block as well */
+       sequence = find_section(bdb, BDB_MIPI_SEQUENCE);
+       if (!sequence) {
+               DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n");
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("Found MIPI sequence block\n");
+
+       block_size = get_blocksize(sequence);
+
+       /*
+        * parse the sequence block for individual sequences
+        */
+       dev_priv->vbt.dsi.seq_version = sequence->version;
+
+       seq_data = &sequence->data[0];
+
+       /*
+        * sequence block is variable length and hence we need to parse and
+        * get the sequence data for specific panel id
+        */
+       for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) {
+               panel_id = *seq_data;
+               seq_size = *((u16 *) (seq_data + 1));
+               if (panel_id == panel_type)
+                       break;
+
+               /* skip the sequence including seq header of 3 bytes */
+               seq_data = seq_data + 3 + seq_size;
+               if ((seq_data - &sequence->data[0]) > block_size) {
+                       DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n");
+                       return;
+               }
+       }
+
+       if (i == MAX_MIPI_CONFIGURATIONS) {
+               DRM_ERROR("Sequence block detected but no valid configuration\n");
+               return;
+       }
+
+       /* check if found sequence is completely within the sequence block
+        * just being paranoid */
+       if (seq_size > block_size) {
+               DRM_ERROR("Corrupted sequence/size, bailing out\n");
+               return;
+       }
+
+       /* skip the panel id(1 byte) and seq size(2 bytes) */
+       dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL);
+       if (!dev_priv->vbt.dsi.data)
+               return;
+
+       /*
+        * loop into the sequence data and split into multiple sequneces
+        * There are only 5 types of sequences as of now
+        */
+       data = dev_priv->vbt.dsi.data;
+       dev_priv->vbt.dsi.size = seq_size;
+
+       /* two consecutive 0x00 indicate end of all sequences */
+       while (1) {
+               int seq_id = *data;
+               if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) {
+                       dev_priv->vbt.dsi.sequence[seq_id] = data;
+                       DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id);
+               } else {
+                       DRM_ERROR("undefined sequence\n");
+                       goto err;
+               }
+
+               /* partial parsing to skip elements */
+               data = goto_next_sequence(data, &seq_size);
+
+               if (data == NULL) {
+                       DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n");
+                       goto err;
+               }
+
+               if (*data == 0)
+                       break; /* end of sequence reached */
+       }
+
+       DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n");
+       return;
+err:
+       kfree(dev_priv->vbt.dsi.data);
+       dev_priv->vbt.dsi.data = NULL;
+
+       /* error during parsing so set all pointers to null
+        * because of partial parsing */
+       memset(dev_priv->vbt.dsi.sequence, 0, MIPI_SEQ_MAX);
 }
 
 static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
@@ -869,6 +1105,46 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = {
        { }
 };
 
+static struct bdb_header *validate_vbt(char *base, size_t size,
+                                      struct vbt_header *vbt,
+                                      const char *source)
+{
+       size_t offset;
+       struct bdb_header *bdb;
+
+       if (vbt == NULL) {
+               DRM_DEBUG_DRIVER("VBT signature missing\n");
+               return NULL;
+       }
+
+       offset = (char *)vbt - base;
+       if (offset + sizeof(struct vbt_header) > size) {
+               DRM_DEBUG_DRIVER("VBT header incomplete\n");
+               return NULL;
+       }
+
+       if (memcmp(vbt->signature, "$VBT", 4)) {
+               DRM_DEBUG_DRIVER("VBT invalid signature\n");
+               return NULL;
+       }
+
+       offset += vbt->bdb_offset;
+       if (offset + sizeof(struct bdb_header) > size) {
+               DRM_DEBUG_DRIVER("BDB header incomplete\n");
+               return NULL;
+       }
+
+       bdb = (struct bdb_header *)(base + offset);
+       if (offset + bdb->bdb_size > size) {
+               DRM_DEBUG_DRIVER("BDB incomplete\n");
+               return NULL;
+       }
+
+       DRM_DEBUG_KMS("Using VBT from %s: %20s\n",
+                     source, vbt->signature);
+       return bdb;
+}
+
 /**
  * intel_parse_bios - find VBT and initialize settings from the BIOS
  * @dev: DRM device
@@ -892,20 +1168,13 @@ intel_parse_bios(struct drm_device *dev)
        init_vbt_defaults(dev_priv);
 
        /* XXX Should this validation be moved to intel_opregion.c? */
-       if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) {
-               struct vbt_header *vbt = dev_priv->opregion.vbt;
-               if (memcmp(vbt->signature, "$VBT", 4) == 0) {
-                       DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
-                                        vbt->signature);
-                       bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
-               } else
-                       dev_priv->opregion.vbt = NULL;
-       }
+       if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt)
+               bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE,
+                                  (struct vbt_header *)dev_priv->opregion.vbt,
+                                  "OpRegion");
 
        if (bdb == NULL) {
-               struct vbt_header *vbt = NULL;
-               size_t size;
-               int i;
+               size_t i, size;
 
                bios = pci_map_rom(pdev, &size);
                if (!bios)
@@ -913,19 +1182,18 @@ intel_parse_bios(struct drm_device *dev)
 
                /* Scour memory looking for the VBT signature */
                for (i = 0; i + 4 < size; i++) {
-                       if (!memcmp(bios + i, "$VBT", 4)) {
-                               vbt = (struct vbt_header *)(bios + i);
+                       if (memcmp(bios + i, "$VBT", 4) == 0) {
+                               bdb = validate_vbt(bios, size,
+                                                  (struct vbt_header *)(bios + i),
+                                                  "PCI ROM");
                                break;
                        }
                }
 
-               if (!vbt) {
-                       DRM_DEBUG_DRIVER("VBT signature missing\n");
+               if (!bdb) {
                        pci_unmap_rom(pdev, bios);
                        return -1;
                }
-
-               bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
        }
 
        /* Grab useful general definitions */
index f27f7b282465aa76a77690ebe8239775c923f06e..6009debebaaf648c8f1c10ecb13de33bf2427058 100644 (file)
@@ -282,6 +282,9 @@ struct bdb_general_definitions {
        union child_device_config devices[0];
 } __packed;
 
+/* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */
+#define MODE_MASK              0x3
+
 struct bdb_lvds_options {
        u8 panel_type;
        u8 rsvd1;
@@ -294,6 +297,18 @@ struct bdb_lvds_options {
        u8 lvds_edid:1;
        u8 rsvd2:1;
        u8 rsvd4;
+       /* LVDS Panel channel bits stored here */
+       u32 lvds_panel_channel_bits;
+       /* LVDS SSC (Spread Spectrum Clock) bits stored here. */
+       u16 ssc_bits;
+       u16 ssc_freq;
+       u16 ssc_ddt;
+       /* Panel color depth defined here */
+       u16 panel_color_depth;
+       /* LVDS panel type bits stored here */
+       u32 dps_panel_type_bits;
+       /* LVDS backlight control type bits stored here */
+       u32 blt_control_type_bits;
 } __packed;
 
 /* LFP pointer table contains entries to the struct below */
@@ -482,6 +497,20 @@ struct bdb_driver_features {
 
        u8 hdmi_termination;
        u8 custom_vbt_version;
+       /* Driver features data block */
+       u16 rmpm_enabled:1;
+       u16 s2ddt_enabled:1;
+       u16 dpst_enabled:1;
+       u16 bltclt_enabled:1;
+       u16 adb_enabled:1;
+       u16 drrs_enabled:1;
+       u16 grs_enabled:1;
+       u16 gpmt_enabled:1;
+       u16 tbt_enabled:1;
+       u16 psr_enabled:1;
+       u16 ips_enabled:1;
+       u16 reserved3:4;
+       u16 pc_feature_valid:1;
 } __packed;
 
 #define EDP_18BPP      0
@@ -870,4 +899,35 @@ struct bdb_mipi_sequence {
        u8 data[0];
 };
 
+/* MIPI Sequnece Block definitions */
+enum mipi_seq {
+       MIPI_SEQ_UNDEFINED = 0,
+       MIPI_SEQ_ASSERT_RESET,
+       MIPI_SEQ_INIT_OTP,
+       MIPI_SEQ_DISPLAY_ON,
+       MIPI_SEQ_DISPLAY_OFF,
+       MIPI_SEQ_DEASSERT_RESET,
+       MIPI_SEQ_MAX
+};
+
+enum mipi_seq_element {
+       MIPI_SEQ_ELEM_UNDEFINED = 0,
+       MIPI_SEQ_ELEM_SEND_PKT,
+       MIPI_SEQ_ELEM_DELAY,
+       MIPI_SEQ_ELEM_GPIO,
+       MIPI_SEQ_ELEM_STATUS,
+       MIPI_SEQ_ELEM_MAX
+};
+
+enum mipi_gpio_pin_index {
+       MIPI_GPIO_UNDEFINED = 0,
+       MIPI_GPIO_PANEL_ENABLE,
+       MIPI_GPIO_BL_ENABLE,
+       MIPI_GPIO_PWM_ENABLE,
+       MIPI_GPIO_RESET_N,
+       MIPI_GPIO_PWR_DOWN_R,
+       MIPI_GPIO_STDBY_RST_N,
+       MIPI_GPIO_MAX
+};
+
 #endif /* _I830_BIOS_H_ */
index aa5a3dc43342a1d484a5419d5fa8388049348636..22d8347f7838eb67955b6fc3efd52b368975f867 100644 (file)
@@ -144,28 +144,49 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       u32 temp;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+       u32 adpa;
+
+       if (INTEL_INFO(dev)->gen >= 5)
+               adpa = ADPA_HOTPLUG_BITS;
+       else
+               adpa = 0;
 
-       temp = I915_READ(crt->adpa_reg);
-       temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
-       temp &= ~ADPA_DAC_ENABLE;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               adpa |= ADPA_HSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               adpa |= ADPA_VSYNC_ACTIVE_HIGH;
+
+       /* For CPT allow 3 pipe config, for others just use A or B */
+       if (HAS_PCH_LPT(dev))
+               ; /* Those bits don't exist here */
+       else if (HAS_PCH_CPT(dev))
+               adpa |= PORT_TRANS_SEL_CPT(crtc->pipe);
+       else if (crtc->pipe == 0)
+               adpa |= ADPA_PIPE_A_SELECT;
+       else
+               adpa |= ADPA_PIPE_B_SELECT;
+
+       if (!HAS_PCH_SPLIT(dev))
+               I915_WRITE(BCLRPAT(crtc->pipe), 0);
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
-               temp |= ADPA_DAC_ENABLE;
+               adpa |= ADPA_DAC_ENABLE;
                break;
        case DRM_MODE_DPMS_STANDBY:
-               temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
+               adpa |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
                break;
        case DRM_MODE_DPMS_SUSPEND:
-               temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
+               adpa |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
                break;
        case DRM_MODE_DPMS_OFF:
-               temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
+               adpa |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
                break;
        }
 
-       I915_WRITE(crt->adpa_reg, temp);
+       I915_WRITE(crt->adpa_reg, adpa);
 }
 
 static void intel_disable_crt(struct intel_encoder *encoder)
@@ -274,42 +295,6 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_crt_mode_set(struct intel_encoder *encoder)
-{
-
-       struct drm_device *dev = encoder->base.dev;
-       struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
-       u32 adpa;
-
-       if (INTEL_INFO(dev)->gen >= 5)
-               adpa = ADPA_HOTPLUG_BITS;
-       else
-               adpa = 0;
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-               adpa |= ADPA_HSYNC_ACTIVE_HIGH;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-               adpa |= ADPA_VSYNC_ACTIVE_HIGH;
-
-       /* For CPT allow 3 pipe config, for others just use A or B */
-       if (HAS_PCH_LPT(dev))
-               ; /* Those bits don't exist here */
-       else if (HAS_PCH_CPT(dev))
-               adpa |= PORT_TRANS_SEL_CPT(crtc->pipe);
-       else if (crtc->pipe == 0)
-               adpa |= ADPA_PIPE_A_SELECT;
-       else
-               adpa |= ADPA_PIPE_B_SELECT;
-
-       if (!HAS_PCH_SPLIT(dev))
-               I915_WRITE(BCLRPAT(crtc->pipe), 0);
-
-       I915_WRITE(crt->adpa_reg, adpa);
-}
-
 static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
@@ -867,7 +852,6 @@ void intel_crt_init(struct drm_device *dev)
                crt->adpa_reg = ADPA;
 
        crt->base.compute_config = intel_crt_compute_config;
-       crt->base.mode_set = intel_crt_mode_set;
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
        if (I915_HAS_HOTPLUG(dev))
index dae976f51d83357a51637fca61bd830bb9753010..d3e72639a44980fa6a3a68a21b874c0d7c99e173 100644 (file)
@@ -765,7 +765,7 @@ static void g4x_wait_for_vblank(struct drm_device *dev, int pipe)
        frame = I915_READ(frame_reg);
 
        if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50))
-               DRM_DEBUG_KMS("vblank wait timed out\n");
+               WARN(1, "vblank wait timed out\n");
 }
 
 /**
@@ -1804,16 +1804,6 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
 
        I915_WRITE(reg, val | PIPECONF_ENABLE);
        POSTING_READ(reg);
-
-       /*
-        * There's no guarantee the pipe will really start running now. It
-        * depends on the Gen, the output type and the relative order between
-        * pipe and plane enabling. Avoid waiting on HSW+ since it's not
-        * necessary.
-        * TODO: audit the previous gens.
-        */
-       if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
-               intel_wait_for_vblank(dev_priv->dev, pipe);
 }
 
 /**
@@ -1890,7 +1880,8 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
        /* If the pipe isn't enabled, we can't pump pixels and may hang */
        assert_pipe_enabled(dev_priv, pipe);
 
-       WARN(intel_crtc->primary_enabled, "Primary plane already enabled\n");
+       if (intel_crtc->primary_enabled)
+               return;
 
        intel_crtc->primary_enabled = true;
 
@@ -1920,7 +1911,8 @@ static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
        int reg;
        u32 val;
 
-       WARN(!intel_crtc->primary_enabled, "Primary plane already disabled\n");
+       if (!intel_crtc->primary_enabled)
+               return;
 
        intel_crtc->primary_enabled = false;
 
@@ -2166,15 +2158,6 @@ static int i9xx_update_primary_plane(struct drm_crtc *crtc,
        u32 dspcntr;
        u32 reg;
 
-       switch (plane) {
-       case 0:
-       case 1:
-               break;
-       default:
-               DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane));
-               return -EINVAL;
-       }
-
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
@@ -2267,16 +2250,6 @@ static int ironlake_update_primary_plane(struct drm_crtc *crtc,
        u32 dspcntr;
        u32 reg;
 
-       switch (plane) {
-       case 0:
-       case 1:
-       case 2:
-               break;
-       default:
-               DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane));
-               return -EINVAL;
-       }
-
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
@@ -2628,12 +2601,10 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
        u32 reg, temp, tries;
 
-       /* FDI needs bits from pipe & plane first */
+       /* FDI needs bits from pipe first */
        assert_pipe_enabled(dev_priv, pipe);
-       assert_plane_enabled(dev_priv, plane);
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
@@ -3602,10 +3573,13 @@ void hsw_disable_ips(struct intel_crtc *crtc)
                return;
 
        assert_plane_enabled(dev_priv, crtc->plane);
-       if (IS_BROADWELL(crtc->base.dev)) {
+       if (IS_BROADWELL(dev)) {
                mutex_lock(&dev_priv->rps.hw_lock);
                WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
                mutex_unlock(&dev_priv->rps.hw_lock);
+               /* wait for pcode to finish disabling IPS, which may take up to 42ms */
+               if (wait_for((I915_READ(IPS_CTL) & IPS_ENABLE) == 0, 42))
+                       DRM_ERROR("Timed out waiting for IPS disable\n");
        } else {
                I915_WRITE(IPS_CTL, 0);
                POSTING_READ(IPS_CTL);
@@ -3662,6 +3636,46 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
                hsw_enable_ips(intel_crtc);
 }
 
+static void ilk_crtc_enable_planes(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+
+       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
+       intel_enable_planes(crtc);
+       intel_crtc_update_cursor(crtc, true);
+
+       hsw_enable_ips(intel_crtc);
+
+       mutex_lock(&dev->struct_mutex);
+       intel_update_fbc(dev);
+       mutex_unlock(&dev->struct_mutex);
+}
+
+static void ilk_crtc_disable_planes(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+
+       intel_crtc_wait_for_pending_flips(crtc);
+       drm_vblank_off(dev, pipe);
+
+       if (dev_priv->fbc.plane == plane)
+               intel_disable_fbc(dev);
+
+       hsw_disable_ips(intel_crtc);
+
+       intel_crtc_update_cursor(crtc, false);
+       intel_disable_planes(crtc);
+       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -3669,7 +3683,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
 
        WARN_ON(!crtc->enabled);
 
@@ -3705,23 +3718,18 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
-       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
-       intel_enable_planes(crtc);
-       intel_crtc_update_cursor(crtc, true);
 
        if (intel_crtc->config.has_pch_encoder)
                ironlake_pch_enable(crtc);
 
-       mutex_lock(&dev->struct_mutex);
-       intel_update_fbc(dev);
-       mutex_unlock(&dev->struct_mutex);
-
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->enable(encoder);
 
        if (HAS_PCH_CPT(dev))
                cpt_verify_modeset(dev, intel_crtc->pipe);
 
+       ilk_crtc_enable_planes(crtc);
+
        /*
         * There seems to be a race in PCH platform hw (at least on some
         * outputs) where an enabled pipe still completes any pageflip right
@@ -3739,47 +3747,6 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
        return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A;
 }
 
-static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-
-       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
-       intel_enable_planes(crtc);
-       intel_crtc_update_cursor(crtc, true);
-
-       hsw_enable_ips(intel_crtc);
-
-       mutex_lock(&dev->struct_mutex);
-       intel_update_fbc(dev);
-       mutex_unlock(&dev->struct_mutex);
-}
-
-static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-
-       intel_crtc_wait_for_pending_flips(crtc);
-       drm_vblank_off(dev, pipe);
-
-       /* FBC must be disabled before disabling the plane on HSW. */
-       if (dev_priv->fbc.plane == plane)
-               intel_disable_fbc(dev);
-
-       hsw_disable_ips(intel_crtc);
-
-       intel_crtc_update_cursor(crtc, false);
-       intel_disable_planes(crtc);
-       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
-}
-
 /*
  * This implements the workaround described in the "notes" section of the mode
  * set sequence documentation. When going from no pipes or single pipe to
@@ -3862,7 +3829,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        /* If we change the relative order between pipe/planes enabling, we need
         * to change the workaround. */
        haswell_mode_set_planes_workaround(intel_crtc);
-       haswell_crtc_enable_planes(crtc);
+       ilk_crtc_enable_planes(crtc);
 }
 
 static void ironlake_pfit_disable(struct intel_crtc *crtc)
@@ -3887,26 +3854,16 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
        u32 reg, temp;
 
-
        if (!intel_crtc->active)
                return;
 
+       ilk_crtc_disable_planes(crtc);
+
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->disable(encoder);
 
-       intel_crtc_wait_for_pending_flips(crtc);
-       drm_vblank_off(dev, pipe);
-
-       if (dev_priv->fbc.plane == plane)
-               intel_disable_fbc(dev);
-
-       intel_crtc_update_cursor(crtc, false);
-       intel_disable_planes(crtc);
-       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
-
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
 
@@ -3965,7 +3922,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        if (!intel_crtc->active)
                return;
 
-       haswell_crtc_disable_planes(crtc);
+       ilk_crtc_disable_planes(crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                intel_opregion_notify_encoder(encoder, false);
@@ -4207,6 +4164,9 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val, cmd;
 
+       WARN_ON(valleyview_cur_cdclk(dev_priv) != dev_priv->vlv_cdclk_freq);
+       dev_priv->vlv_cdclk_freq = cdclk;
+
        if (cdclk >= 320) /* jump to highest voltage for 400MHz too */
                cmd = 2;
        else if (cdclk == 266)
@@ -4261,7 +4221,7 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
        intel_i2c_reset(dev);
 }
 
-static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv)
+int valleyview_cur_cdclk(struct drm_i915_private *dev_priv)
 {
        int cur_cdclk, vco;
        int divider;
@@ -4282,10 +4242,6 @@ static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv)
 static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
                                 int max_pixclk)
 {
-       int cur_cdclk;
-
-       cur_cdclk = valleyview_cur_cdclk(dev_priv);
-
        /*
         * Really only a few cases to deal with, as only 4 CDclks are supported:
         *   200MHz
@@ -4327,9 +4283,9 @@ static void valleyview_modeset_global_pipes(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc;
        int max_pixclk = intel_mode_max_pixclk(dev_priv);
-       int cur_cdclk = valleyview_cur_cdclk(dev_priv);
 
-       if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk)
+       if (valleyview_calc_cdclk(dev_priv, max_pixclk) ==
+           dev_priv->vlv_cdclk_freq)
                return;
 
        /* disable/enable all currently active pipes while we change cdclk */
@@ -4343,10 +4299,9 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_pixclk = intel_mode_max_pixclk(dev_priv);
-       int cur_cdclk = valleyview_cur_cdclk(dev_priv);
        int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
 
-       if (req_cdclk != cur_cdclk)
+       if (req_cdclk != dev_priv->vlv_cdclk_freq)
                valleyview_set_cdclk(dev, req_cdclk);
        modeset_update_crtc_power_domains(dev);
 }
@@ -4387,7 +4342,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
        intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
+       intel_wait_for_vblank(dev_priv->dev, pipe);
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+
        intel_enable_primary_hw_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
@@ -4426,7 +4383,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
        intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
+       intel_wait_for_vblank(dev_priv->dev, pipe);
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+
        intel_enable_primary_hw_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        /* The fixup needs to happen before cursor is enabled */
@@ -5245,9 +5204,6 @@ static void vlv_update_pll(struct intel_crtc *crtc)
                << DPLL_MD_UDI_MULTIPLIER_SHIFT;
        crtc->config.dpll_hw_state.dpll_md = dpll_md;
 
-       if (crtc->config.has_dp_encoder)
-               intel_dp_set_m_n(crtc);
-
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
@@ -5325,9 +5281,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
                        << DPLL_MD_UDI_MULTIPLIER_SHIFT;
                crtc->config.dpll_hw_state.dpll_md = dpll_md;
        }
-
-       if (crtc->config.has_dp_encoder)
-               intel_dp_set_m_n(crtc);
 }
 
 static void i8xx_update_pll(struct intel_crtc *crtc,
@@ -5656,6 +5609,9 @@ skip_dpll:
                        dspcntr |= DISPPLANE_SEL_PIPE_B;
        }
 
+       if (intel_crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(intel_crtc);
+
        intel_set_pipe_timings(intel_crtc);
 
        /* pipesrc and dspsize control the size that is scaled from,
@@ -6880,8 +6836,6 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
        struct drm_device *dev = dev_priv->dev;
        struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
        struct intel_crtc *crtc;
-       unsigned long irqflags;
-       uint32_t val;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
                WARN(crtc->active, "CRTC for pipe %c enabled\n",
@@ -6902,14 +6856,29 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
             "Utility pin enabled\n");
        WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       val = I915_READ(DEIMR);
-       WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff,
-            "Unexpected DEIMR bits enabled: 0x%x\n", val);
-       val = I915_READ(SDEIMR);
-       WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff,
-            "Unexpected SDEIMR bits enabled: 0x%x\n", val);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       /*
+        * In theory we can still leave IRQs enabled, as long as only the HPD
+        * interrupts remain enabled. We used to check for that, but since it's
+        * gen-specific and since we only disable LCPLL after we fully disable
+        * the interrupts, the check below should be enough.
+        */
+       WARN(!dev_priv->pm.irqs_disabled, "IRQs enabled\n");
+}
+
+static void hsw_write_dcomp(struct drm_i915_private *dev_priv, uint32_t val)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       if (IS_HASWELL(dev)) {
+               mutex_lock(&dev_priv->rps.hw_lock);
+               if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP,
+                                           val))
+                       DRM_ERROR("Failed to disable D_COMP\n");
+               mutex_unlock(&dev_priv->rps.hw_lock);
+       } else {
+               I915_WRITE(D_COMP, val);
+       }
+       POSTING_READ(D_COMP);
 }
 
 /*
@@ -6949,11 +6918,7 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
 
        val = I915_READ(D_COMP);
        val |= D_COMP_COMP_DISABLE;
-       mutex_lock(&dev_priv->rps.hw_lock);
-       if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val))
-               DRM_ERROR("Failed to disable D_COMP\n");
-       mutex_unlock(&dev_priv->rps.hw_lock);
-       POSTING_READ(D_COMP);
+       hsw_write_dcomp(dev_priv, val);
        ndelay(100);
 
        if (wait_for((I915_READ(D_COMP) & D_COMP_RCOMP_IN_PROGRESS) == 0, 1))
@@ -7008,11 +6973,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
        val = I915_READ(D_COMP);
        val |= D_COMP_COMP_FORCE;
        val &= ~D_COMP_COMP_DISABLE;
-       mutex_lock(&dev_priv->rps.hw_lock);
-       if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val))
-               DRM_ERROR("Failed to enable D_COMP\n");
-       mutex_unlock(&dev_priv->rps.hw_lock);
-       POSTING_READ(D_COMP);
+       hsw_write_dcomp(dev_priv, val);
 
        val = I915_READ(LCPLL_CTL);
        val &= ~LCPLL_PLL_DISABLE;
@@ -7066,8 +7027,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv)
        struct drm_device *dev = dev_priv->dev;
        uint32_t val;
 
-       WARN_ON(!HAS_PC8(dev));
-
        DRM_DEBUG_KMS("Enabling package C8+\n");
 
        if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
@@ -7077,7 +7036,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv)
        }
 
        lpt_disable_clkout_dp(dev);
-       hsw_runtime_pm_disable_interrupts(dev);
        hsw_disable_lcpll(dev_priv, true, true);
 }
 
@@ -7086,12 +7044,9 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
        struct drm_device *dev = dev_priv->dev;
        uint32_t val;
 
-       WARN_ON(!HAS_PC8(dev));
-
        DRM_DEBUG_KMS("Disabling package C8+\n");
 
        hsw_restore_lcpll(dev_priv);
-       hsw_runtime_pm_restore_interrupts(dev);
        lpt_init_pch_refclk(dev);
 
        if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
@@ -7101,10 +7056,11 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
        }
 
        intel_prepare_ddi(dev);
-       i915_gem_init_swizzling(dev);
-       mutex_lock(&dev_priv->rps.hw_lock);
-       gen6_update_ring_freq(dev);
-       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void snb_modeset_global_resources(struct drm_device *dev)
+{
+       modeset_update_crtc_power_domains(dev);
 }
 
 static void haswell_modeset_global_resources(struct drm_device *dev)
@@ -7254,7 +7210,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        encoder->base.base.id,
                        drm_get_encoder_name(&encoder->base),
                        mode->base.id, mode->name);
-               encoder->mode_set(encoder);
+
+               if (encoder->mode_set)
+                       encoder->mode_set(encoder);
        }
 
        return 0;
@@ -7374,7 +7332,6 @@ static void haswell_write_eld(struct drm_connector *connector,
 {
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        uint8_t *eld = connector->eld;
-       struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t eldv;
        uint32_t i;
@@ -7387,17 +7344,14 @@ static void haswell_write_eld(struct drm_connector *connector,
        int aud_config = HSW_AUD_CFG(pipe);
        int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD;
 
-
-       DRM_DEBUG_DRIVER("HDMI: Haswell Audio initialize....\n");
-
        /* Audio output enable */
        DRM_DEBUG_DRIVER("HDMI audio: enable codec\n");
        tmp = I915_READ(aud_cntrl_st2);
        tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4));
        I915_WRITE(aud_cntrl_st2, tmp);
+       POSTING_READ(aud_cntrl_st2);
 
-       /* Wait for 1 vertical blank */
-       intel_wait_for_vblank(dev, pipe);
+       assert_pipe_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
 
        /* Set ELD valid state */
        tmp = I915_READ(aud_cntrl_st2);
@@ -8836,8 +8790,16 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
        }
 
        len = 4;
-       if (ring->id == RCS)
+       if (ring->id == RCS) {
                len += 6;
+               /*
+                * On Gen 8, SRM is now taking an extra dword to accommodate
+                * 48bits addresses, and we need a NOOP for the batch size to
+                * stay even.
+                */
+               if (IS_GEN8(dev))
+                       len += 2;
+       }
 
        /*
         * BSpec MI_DISPLAY_FLIP for IVB:
@@ -8872,10 +8834,18 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
                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) |
-                               MI_SRM_LRM_GLOBAL_GTT);
+               if (IS_GEN8(dev))
+                       intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8(1) |
+                                             MI_SRM_LRM_GLOBAL_GTT);
+               else
+                       intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) |
+                                             MI_SRM_LRM_GLOBAL_GTT);
                intel_ring_emit(ring, DERRMR);
                intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
+               if (IS_GEN8(dev)) {
+                       intel_ring_emit(ring, 0);
+                       intel_ring_emit(ring, MI_NOOP);
+               }
        }
 
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
@@ -9654,11 +9624,22 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_I(pipe_src_w);
        PIPE_CONF_CHECK_I(pipe_src_h);
 
-       PIPE_CONF_CHECK_I(gmch_pfit.control);
-       /* pfit ratios are autocomputed by the hw on gen4+ */
-       if (INTEL_INFO(dev)->gen < 4)
-               PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
-       PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
+       /*
+        * FIXME: BIOS likes to set up a cloned config with lvds+external
+        * screen. Since we don't yet re-compute the pipe config when moving
+        * just the lvds port away to another pipe the sw tracking won't match.
+        *
+        * Proper atomic modesets with recomputed global state will fix this.
+        * Until then just don't check gmch state for inherited modes.
+        */
+       if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_INHERITED_MODE)) {
+               PIPE_CONF_CHECK_I(gmch_pfit.control);
+               /* pfit ratios are autocomputed by the hw on gen4+ */
+               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.enabled);
        if (current_config->pch_pfit.enabled) {
                PIPE_CONF_CHECK_I(pch_pfit.pos);
@@ -10567,16 +10548,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
-       if (IS_GEN2(dev)) {
-               intel_crtc->max_cursor_width = GEN2_CURSOR_WIDTH;
-               intel_crtc->max_cursor_height = GEN2_CURSOR_HEIGHT;
-       } else {
-               intel_crtc->max_cursor_width = CURSOR_WIDTH;
-               intel_crtc->max_cursor_height = CURSOR_HEIGHT;
-       }
-       dev->mode_config.cursor_width = intel_crtc->max_cursor_width;
-       dev->mode_config.cursor_height = intel_crtc->max_cursor_height;
-
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
@@ -11077,6 +11048,8 @@ static void intel_init_display(struct drm_device *dev)
                } else if (IS_GEN6(dev)) {
                        dev_priv->display.fdi_link_train = gen6_fdi_link_train;
                        dev_priv->display.write_eld = ironlake_write_eld;
+                       dev_priv->display.modeset_global_resources =
+                               snb_modeset_global_resources;
                } else if (IS_IVYBRIDGE(dev)) {
                        /* FIXME: detect B0+ stepping and use auto training */
                        dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
@@ -11281,9 +11254,7 @@ void intel_modeset_init_hw(struct drm_device *dev)
 
        intel_reset_dpio(dev);
 
-       mutex_lock(&dev->struct_mutex);
        intel_enable_gt_powersave(dev);
-       mutex_unlock(&dev->struct_mutex);
 }
 
 void intel_modeset_suspend_hw(struct drm_device *dev)
@@ -11327,6 +11298,15 @@ void intel_modeset_init(struct drm_device *dev)
                dev->mode_config.max_width = 8192;
                dev->mode_config.max_height = 8192;
        }
+
+       if (IS_GEN2(dev)) {
+               dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH;
+               dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT;
+       } else {
+               dev->mode_config.cursor_width = MAX_CURSOR_WIDTH;
+               dev->mode_config.cursor_height = MAX_CURSOR_HEIGHT;
+       }
+
        dev->mode_config.fb_base = dev_priv->gtt.mappable_base;
 
        DRM_DEBUG_KMS("%d display pipe%s available.\n",
@@ -11603,6 +11583,16 @@ void i915_redisable_vga(struct drm_device *dev)
        i915_redisable_vga_power_on(dev);
 }
 
+static bool primary_get_hw_state(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+       if (!crtc->active)
+               return false;
+
+       return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE;
+}
+
 static void intel_modeset_readout_hw_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11616,11 +11606,13 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                            base.head) {
                memset(&crtc->config, 0, sizeof(crtc->config));
 
+               crtc->config.quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
+
                crtc->active = dev_priv->display.get_pipe_config(crtc,
                                                                 &crtc->config);
 
                crtc->base.enabled = crtc->active;
-               crtc->primary_enabled = crtc->active;
+               crtc->primary_enabled = primary_get_hw_state(crtc);
 
                DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
                              crtc->base.base.id,
@@ -11923,6 +11915,7 @@ struct intel_display_error_state {
        struct intel_pipe_error_state {
                bool power_domain_on;
                u32 source;
+               u32 stat;
        } pipe[I915_MAX_PIPES];
 
        struct intel_plane_error_state {
@@ -12004,6 +11997,9 @@ intel_display_capture_error_state(struct drm_device *dev)
                }
 
                error->pipe[i].source = I915_READ(PIPESRC(i));
+
+               if (!HAS_PCH_SPLIT(dev))
+                       error->pipe[i].stat = I915_READ(PIPESTAT(i));
        }
 
        error->num_transcoders = INTEL_INFO(dev)->num_pipes;
@@ -12054,6 +12050,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                err_printf(m, "  Power: %s\n",
                           error->pipe[i].power_domain_on ? "on" : "off");
                err_printf(m, "  SRC: %08x\n", error->pipe[i].source);
+               err_printf(m, "  STAT: %08x\n", error->pipe[i].stat);
 
                err_printf(m, "Plane [%d]:\n", i);
                err_printf(m, "  CNTR: %08x\n", error->plane[i].control);
index d2a55884ad523b8a54546bfbbe0565889e73261e..34ed143ab479317568ccdbc0c46fe943f85e030b 100644 (file)
@@ -313,8 +313,12 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       enum intel_display_power_domain power_domain;
 
-       return !dev_priv->pm.suspended &&
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       return intel_display_power_enabled(dev_priv, power_domain) &&
               (I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD) != 0;
 }
 
@@ -738,6 +742,20 @@ intel_dp_set_clock(struct intel_encoder *encoder,
        }
 }
 
+static void
+intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder transcoder = crtc->config.cpu_transcoder;
+
+       I915_WRITE(PIPE_DATA_M2(transcoder),
+               TU_SIZE(m_n->tu) | m_n->gmch_m);
+       I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n);
+       I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m);
+       I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n);
+}
+
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_config *pipe_config)
@@ -842,6 +860,14 @@ found:
                               pipe_config->port_clock,
                               &pipe_config->dp_m_n);
 
+       if (intel_connector->panel.downclock_mode != NULL &&
+               intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
+                       intel_link_compute_m_n(bpp, lane_count,
+                               intel_connector->panel.downclock_mode->clock,
+                               pipe_config->port_clock,
+                               &pipe_config->dp_m2_n2);
+       }
+
        intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw);
 
        return true;
@@ -1044,7 +1070,10 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
 static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
        u32 pp;
        u32 pp_stat_reg, pp_ctrl_reg;
        bool need_to_disable = !intel_dp->want_panel_vdd;
@@ -1057,7 +1086,8 @@ static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
        if (edp_have_panel_vdd(intel_dp))
                return need_to_disable;
 
-       intel_runtime_pm_get(dev_priv);
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
 
        DRM_DEBUG_KMS("Turning eDP VDD on\n");
 
@@ -1104,6 +1134,11 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
        if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
+               struct intel_digital_port *intel_dig_port =
+                                               dp_to_dig_port(intel_dp);
+               struct intel_encoder *intel_encoder = &intel_dig_port->base;
+               enum intel_display_power_domain power_domain;
+
                DRM_DEBUG_KMS("Turning eDP VDD off\n");
 
                pp = ironlake_get_pp_control(intel_dp);
@@ -1122,7 +1157,8 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
                if ((pp & POWER_TARGET_ON) == 0)
                        intel_dp->last_power_cycle = jiffies;
 
-               intel_runtime_pm_put(dev_priv);
+               power_domain = intel_display_port_power_domain(intel_encoder);
+               intel_display_power_put(dev_priv, power_domain);
        }
 }
 
@@ -1206,8 +1242,11 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
 
 void intel_edp_panel_off(struct intel_dp *intel_dp)
 {
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
        u32 pp;
        u32 pp_ctrl_reg;
 
@@ -1237,7 +1276,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
        wait_panel_off(intel_dp);
 
        /* We got a reference when we enabled the VDD. */
-       intel_runtime_pm_put(dev_priv);
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_put(dev_priv, power_domain);
 }
 
 void intel_edp_backlight_on(struct intel_dp *intel_dp)
@@ -1778,17 +1818,23 @@ static void intel_disable_dp(struct intel_encoder *encoder)
                intel_dp_link_down(intel_dp);
 }
 
-static void intel_post_disable_dp(struct intel_encoder *encoder)
+static void g4x_post_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
-       struct drm_device *dev = encoder->base.dev;
 
-       if (port == PORT_A || IS_VALLEYVIEW(dev)) {
-               intel_dp_link_down(intel_dp);
-               if (!IS_VALLEYVIEW(dev))
-                       ironlake_edp_pll_off(intel_dp);
-       }
+       if (port != PORT_A)
+               return;
+
+       intel_dp_link_down(intel_dp);
+       ironlake_edp_pll_off(intel_dp);
+}
+
+static void vlv_post_disable_dp(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+       intel_dp_link_down(intel_dp);
 }
 
 static void intel_enable_dp(struct intel_encoder *encoder)
@@ -2737,9 +2783,6 @@ intel_dp_link_down(struct intel_dp *intel_dp)
        }
        POSTING_READ(intel_dp->output_reg);
 
-       /* We don't really know why we're doing this */
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
-
        if (HAS_PCH_IBX(dev) &&
            I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
                struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
@@ -3613,22 +3656,158 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                      I915_READ(pp_div_reg));
 }
 
+void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *encoder;
+       struct intel_dp *intel_dp = NULL;
+       struct intel_crtc_config *config = NULL;
+       struct intel_crtc *intel_crtc = NULL;
+       struct intel_connector *intel_connector = dev_priv->drrs.connector;
+       u32 reg, val;
+       enum edp_drrs_refresh_rate_type index = DRRS_HIGH_RR;
+
+       if (refresh_rate <= 0) {
+               DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
+               return;
+       }
+
+       if (intel_connector == NULL) {
+               DRM_DEBUG_KMS("DRRS supported for eDP only.\n");
+               return;
+       }
+
+       if (INTEL_INFO(dev)->gen < 8 && intel_edp_is_psr_enabled(dev)) {
+               DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
+               return;
+       }
+
+       encoder = intel_attached_encoder(&intel_connector->base);
+       intel_dp = enc_to_intel_dp(&encoder->base);
+       intel_crtc = encoder->new_crtc;
+
+       if (!intel_crtc) {
+               DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
+               return;
+       }
+
+       config = &intel_crtc->config;
+
+       if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) {
+               DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
+               return;
+       }
+
+       if (intel_connector->panel.downclock_mode->vrefresh == refresh_rate)
+               index = DRRS_LOW_RR;
+
+       if (index == intel_dp->drrs_state.refresh_rate_type) {
+               DRM_DEBUG_KMS(
+                       "DRRS requested for previously set RR...ignoring\n");
+               return;
+       }
+
+       if (!intel_crtc->active) {
+               DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
+               return;
+       }
+
+       if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) {
+               reg = PIPECONF(intel_crtc->config.cpu_transcoder);
+               val = I915_READ(reg);
+               if (index > DRRS_HIGH_RR) {
+                       val |= PIPECONF_EDP_RR_MODE_SWITCH;
+                       intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2);
+               } else {
+                       val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+               }
+               I915_WRITE(reg, val);
+       }
+
+       /*
+        * mutex taken to ensure that there is no race between differnt
+        * drrs calls trying to update refresh rate. This scenario may occur
+        * in future when idleness detection based DRRS in kernel and
+        * possible calls from user space to set differnt RR are made.
+        */
+
+       mutex_lock(&intel_dp->drrs_state.mutex);
+
+       intel_dp->drrs_state.refresh_rate_type = index;
+
+       mutex_unlock(&intel_dp->drrs_state.mutex);
+
+       DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+}
+
+static struct drm_display_mode *
+intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
+                       struct intel_connector *intel_connector,
+                       struct drm_display_mode *fixed_mode)
+{
+       struct drm_connector *connector = &intel_connector->base;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_display_mode *downclock_mode = NULL;
+
+       if (INTEL_INFO(dev)->gen <= 6) {
+               DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n");
+               return NULL;
+       }
+
+       if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
+               DRM_INFO("VBT doesn't support DRRS\n");
+               return NULL;
+       }
+
+       downclock_mode = intel_find_panel_downclock
+                                       (dev, fixed_mode, connector);
+
+       if (!downclock_mode) {
+               DRM_INFO("DRRS not supported\n");
+               return NULL;
+       }
+
+       dev_priv->drrs.connector = intel_connector;
+
+       mutex_init(&intel_dp->drrs_state.mutex);
+
+       intel_dp->drrs_state.type = dev_priv->vbt.drrs_type;
+
+       intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR;
+       DRM_INFO("seamless DRRS supported for eDP panel.\n");
+       return downclock_mode;
+}
+
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                                     struct intel_connector *intel_connector,
                                     struct edp_power_seq *power_seq)
 {
        struct drm_connector *connector = &intel_connector->base;
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *fixed_mode = NULL;
+       struct drm_display_mode *downclock_mode = NULL;
        bool has_dpcd;
        struct drm_display_mode *scan;
        struct edid *edid;
 
+       intel_dp->drrs_state.type = DRRS_NOT_SUPPORTED;
+
        if (!is_edp(intel_dp))
                return true;
 
+       /* The VDD bit needs a power domain reference, so if the bit is already
+        * enabled when we boot, grab this reference. */
+       if (edp_have_panel_vdd(intel_dp)) {
+               enum intel_display_power_domain power_domain;
+               power_domain = intel_display_port_power_domain(intel_encoder);
+               intel_display_power_get(dev_priv, power_domain);
+       }
+
        /* Cache DPCD and EDID for edp. */
        intel_edp_panel_vdd_on(intel_dp);
        has_dpcd = intel_dp_get_dpcd(intel_dp);
@@ -3668,6 +3847,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        list_for_each_entry(scan, &connector->probed_modes, head) {
                if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
                        fixed_mode = drm_mode_duplicate(dev, scan);
+                       downclock_mode = intel_dp_drrs_init(
+                                               intel_dig_port,
+                                               intel_connector, fixed_mode);
                        break;
                }
        }
@@ -3681,7 +3863,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
        mutex_unlock(&dev->mode_config.mutex);
 
-       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
+       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
        intel_panel_setup_backlight(connector);
 
        return true;
@@ -3832,16 +4014,17 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        intel_encoder->compute_config = intel_dp_compute_config;
        intel_encoder->mode_set = intel_dp_mode_set;
        intel_encoder->disable = intel_disable_dp;
-       intel_encoder->post_disable = intel_post_disable_dp;
        intel_encoder->get_hw_state = intel_dp_get_hw_state;
        intel_encoder->get_config = intel_dp_get_config;
        if (IS_VALLEYVIEW(dev)) {
                intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable;
                intel_encoder->pre_enable = vlv_pre_enable_dp;
                intel_encoder->enable = vlv_enable_dp;
+               intel_encoder->post_disable = vlv_post_disable_dp;
        } else {
                intel_encoder->pre_enable = g4x_pre_enable_dp;
                intel_encoder->enable = g4x_enable_dp;
+               intel_encoder->post_disable = g4x_post_disable_dp;
        }
 
        intel_dig_port->port = port;
index 0542de98226018a9427519d0eb6996714f3c0582..96ae78d0e9752f2b4718792bc2e9b65c2f6ed680 100644 (file)
@@ -81,8 +81,8 @@
 /* Maximum cursor sizes */
 #define GEN2_CURSOR_WIDTH 64
 #define GEN2_CURSOR_HEIGHT 64
-#define CURSOR_WIDTH 256
-#define CURSOR_HEIGHT 256
+#define MAX_CURSOR_WIDTH 256
+#define MAX_CURSOR_HEIGHT 256
 
 #define INTEL_I2C_BUS_DVO 1
 #define INTEL_I2C_BUS_SDVO 2
@@ -236,7 +236,8 @@ struct intel_crtc_config {
         * tracked with quirk flags so that fastboot and state checker can act
         * accordingly.
         */
-#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
+#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS      (1<<0) /* unreliable sync mode.flags */
+#define PIPE_CONFIG_QUIRK_INHERITED_MODE       (1<<1) /* mode inherited from firmware */
        unsigned long quirks;
 
        /* User requested mode, only valid as a starting point to
@@ -305,6 +306,9 @@ struct intel_crtc_config {
        int pipe_bpp;
        struct intel_link_m_n dp_m_n;
 
+       /* m2_n2 for eDP downclock */
+       struct intel_link_m_n dp_m2_n2;
+
        /*
         * Frequence the dpll for the port should run at. Differs from the
         * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also
@@ -342,6 +346,9 @@ struct intel_pipe_wm {
        struct intel_wm_level wm[5];
        uint32_t linetime;
        bool fbc_wm_enabled;
+       bool pipe_enabled;
+       bool sprites_enabled;
+       bool sprites_scaled;
 };
 
 struct intel_crtc {
@@ -373,7 +380,6 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_x, cursor_y;
        int16_t cursor_width, cursor_height;
-       int16_t max_cursor_width, max_cursor_height;
        bool cursor_visible;
 
        struct intel_plane_config plane_config;
@@ -483,6 +489,17 @@ struct intel_hdmi {
 
 #define DP_MAX_DOWNSTREAM_PORTS                0x10
 
+/**
+ * HIGH_RR is the highest eDP panel refresh rate read from EDID
+ * LOW_RR is the lowest eDP panel refresh rate found from EDID
+ * parsing for same resolution.
+ */
+enum edp_drrs_refresh_rate_type {
+       DRRS_HIGH_RR,
+       DRRS_LOW_RR,
+       DRRS_MAX_RR, /* RR count */
+};
+
 struct intel_dp {
        uint32_t output_reg;
        uint32_t aux_ch_ctl_reg;
@@ -521,6 +538,12 @@ struct intel_dp {
                                     bool has_aux_irq,
                                     int send_bytes,
                                     uint32_t aux_clock_divider);
+       struct {
+               enum drrs_support_type type;
+               enum edp_drrs_refresh_rate_type refresh_rate_type;
+               struct mutex mutex;
+       } drrs_state;
+
 };
 
 struct intel_digital_port {
@@ -628,8 +651,9 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
-void hsw_runtime_pm_disable_interrupts(struct drm_device *dev);
-void hsw_runtime_pm_restore_interrupts(struct drm_device *dev);
+void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
+void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
+int intel_get_crtc_scanline(struct intel_crtc *crtc);
 
 
 /* intel_crt.c */
@@ -665,6 +689,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 const char *intel_output_name(int output);
 bool intel_has_pending_fb_unpin(struct drm_device *dev);
 int intel_pch_rawclk(struct drm_device *dev);
+int valleyview_cur_cdclk(struct drm_i915_private *dev_priv);
 void intel_mark_busy(struct drm_device *dev);
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
                        struct intel_ring_buffer *ring);
@@ -773,7 +798,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
-
+void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
 
 /* intel_dsi.c */
 bool intel_dsi_init(struct drm_device *dev);
@@ -901,6 +926,7 @@ void intel_init_gt_powersave(struct drm_device *dev);
 void intel_cleanup_gt_powersave(struct drm_device *dev);
 void intel_enable_gt_powersave(struct drm_device *dev);
 void intel_disable_gt_powersave(struct drm_device *dev);
+void intel_reset_gt_powersave(struct drm_device *dev);
 void ironlake_teardown_rc6(struct drm_device *dev);
 void gen6_update_ring_freq(struct drm_device *dev);
 void gen6_rps_idle(struct drm_i915_private *dev_priv);
@@ -908,6 +934,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv);
 void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
 void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
+void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
 void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
 void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
index 33656647f8bcf566ea8fba54f898ec6fc71b2b5b..4e271c768fd0c58c65b60e9e16d5725c9f82653a 100644 (file)
@@ -110,6 +110,15 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
 
        DRM_DEBUG_KMS("\n");
 
+       mutex_lock(&dev_priv->dpio_lock);
+       /* program rcomp for compliance, reduce from 50 ohms to 45 ohms
+        * needed everytime after power gate */
+       vlv_flisdsi_write(dev_priv, 0x04, 0x0004);
+       mutex_unlock(&dev_priv->dpio_lock);
+
+       /* bandgap reset is needed after everytime we do power gate */
+       band_gap_reset(dev_priv);
+
        val = I915_READ(MIPI_PORT_CTRL(pipe));
        I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD);
        usleep_range(1000, 1500);
@@ -122,21 +131,6 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
        I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY);
        usleep_range(2000, 2500);
 }
-static void intel_dsi_pre_enable(struct intel_encoder *encoder)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       DRM_DEBUG_KMS("\n");
-
-       if (intel_dsi->dev.dev_ops->panel_reset)
-               intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev);
-
-       /* put device in ready state */
-       intel_dsi_device_ready(encoder);
-
-       if (intel_dsi->dev.dev_ops->send_otp_cmds)
-               intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev);
-}
 
 static void intel_dsi_enable(struct intel_encoder *encoder)
 {
@@ -153,18 +147,63 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
                I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4);
        else {
                msleep(20); /* XXX */
-               dpi_send_cmd(intel_dsi, TURN_ON);
+               dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN);
                msleep(100);
 
+               if (intel_dsi->dev.dev_ops->enable)
+                       intel_dsi->dev.dev_ops->enable(&intel_dsi->dev);
+
                /* assert ip_tg_enable signal */
                temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK;
                temp = temp | intel_dsi->port_bits;
                I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE);
                POSTING_READ(MIPI_PORT_CTRL(pipe));
        }
+}
+
+static void intel_dsi_pre_enable(struct intel_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       enum pipe pipe = intel_crtc->pipe;
+       u32 tmp;
+
+       DRM_DEBUG_KMS("\n");
 
-       if (intel_dsi->dev.dev_ops->enable)
-               intel_dsi->dev.dev_ops->enable(&intel_dsi->dev);
+       /* Disable DPOunit clock gating, can stall pipe
+        * and we need DPLL REFA always enabled */
+       tmp = I915_READ(DPLL(pipe));
+       tmp |= DPLL_REFA_CLK_ENABLE_VLV;
+       I915_WRITE(DPLL(pipe), tmp);
+
+       tmp = I915_READ(DSPCLK_GATE_D);
+       tmp |= DPOUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, tmp);
+
+       /* put device in ready state */
+       intel_dsi_device_ready(encoder);
+
+       if (intel_dsi->dev.dev_ops->panel_reset)
+               intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev);
+
+       if (intel_dsi->dev.dev_ops->send_otp_cmds)
+               intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev);
+
+       /* Enable port in pre-enable phase itself because as per hw team
+        * recommendation, port should be enabled befor plane & pipe */
+       intel_dsi_enable(encoder);
+}
+
+static void intel_dsi_enable_nop(struct intel_encoder *encoder)
+{
+       DRM_DEBUG_KMS("\n");
+
+       /* for DSI port enable has to be done before pipe
+        * and plane enable, so port enable is done in
+        * pre_enable phase itself unlike other encoders
+        */
 }
 
 static void intel_dsi_disable(struct intel_encoder *encoder)
@@ -179,7 +218,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
        DRM_DEBUG_KMS("\n");
 
        if (is_vid_mode(intel_dsi)) {
-               dpi_send_cmd(intel_dsi, SHUTDOWN);
+               /* Send Shutdown command to the panel in LP mode */
+               dpi_send_cmd(intel_dsi, SHUTDOWN, DPI_LP_MODE_EN);
                msleep(10);
 
                /* de-assert ip_tg_enable signal */
@@ -190,6 +230,23 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
                msleep(2);
        }
 
+       /* Panel commands can be sent when clock is in LP11 */
+       I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0);
+
+       temp = I915_READ(MIPI_CTRL(pipe));
+       temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+       I915_WRITE(MIPI_CTRL(pipe), temp |
+                       intel_dsi->escape_clk_div <<
+                       ESCAPE_CLOCK_DIVIDER_SHIFT);
+
+       I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP);
+
+       temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe));
+       temp &= ~VID_MODE_FORMAT_MASK;
+       I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp);
+
+       I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1);
+
        /* if disable packets are sent before sending shutdown packet then in
         * some next enable sequence send turn on packet error is observed */
        if (intel_dsi->dev.dev_ops->disable)
@@ -227,14 +284,21 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
 
        vlv_disable_dsi_pll(encoder);
 }
+
 static void intel_dsi_post_disable(struct intel_encoder *encoder)
 {
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 val;
 
        DRM_DEBUG_KMS("\n");
 
        intel_dsi_clear_device_ready(encoder);
 
+       val = I915_READ(DSPCLK_GATE_D);
+       val &= ~DPOUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, val);
+
        if (intel_dsi->dev.dev_ops->disable_panel_power)
                intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev);
 }
@@ -379,9 +443,6 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
 
        DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
 
-       /* XXX: Location of the call */
-       band_gap_reset(dev_priv);
-
        /* escape clock divider, 20MHz, shared for A and C. device ready must be
         * off when doing this! txclkesc? */
        tmp = I915_READ(MIPI_CTRL(0));
@@ -452,10 +513,17 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
        /* dphy stuff */
 
        /* in terms of low power clock */
-       I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(ESCAPE_CLOCK_DIVIDER_1, 100));
+       I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(intel_dsi->escape_clk_div, 100));
+
+       val = 0;
+       if (intel_dsi->eotp_pkt == 0)
+               val |= EOT_DISABLE;
+
+       if (intel_dsi->clock_stop)
+               val |= CLOCKSTOP;
 
        /* recovery disables */
-       I915_WRITE(MIPI_EOT_DISABLE(pipe), intel_dsi->eot_disable);
+       I915_WRITE(MIPI_EOT_DISABLE(pipe), val);
 
        /* in terms of txbyteclkhs. actual high to low switch +
         * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
@@ -484,9 +552,14 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
                   intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
 
        if (is_vid_mode(intel_dsi))
+               /* Some panels might have resolution which is not a multiple of
+                * 64 like 1366 x 768. Enable RANDOM resolution support for such
+                * panels by default */
                I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
                                intel_dsi->video_frmt_cfg_bits |
-                               intel_dsi->video_mode_format);
+                               intel_dsi->video_mode_format |
+                               IP_TG_CONFIG |
+                               RANDOM_DPI_DISPLAY_RESOLUTION);
 }
 
 static enum drm_connector_status
@@ -594,7 +667,7 @@ bool intel_dsi_init(struct drm_device *dev)
        intel_encoder->compute_config = intel_dsi_compute_config;
        intel_encoder->pre_pll_enable = intel_dsi_pre_pll_enable;
        intel_encoder->pre_enable = intel_dsi_pre_enable;
-       intel_encoder->enable = intel_dsi_enable;
+       intel_encoder->enable = intel_dsi_enable_nop;
        intel_encoder->mode_set = intel_dsi_mode_set;
        intel_encoder->disable = intel_dsi_disable;
        intel_encoder->post_disable = intel_dsi_post_disable;
index b4a27cec882f76d7cab17400d8adf438532b4c9d..550714c7860e8ad57a90153e7838830217a92798 100644 (file)
@@ -95,8 +95,10 @@ struct intel_dsi {
        u32 video_mode_format;
 
        /* eot for MIPI_EOT_DISABLE register */
-       u32 eot_disable;
+       u8 eotp_pkt;
+       u8 clock_stop;
 
+       u8 escape_clk_div;
        u32 port_bits;
        u32 bw_timer;
        u32 dphy_reg;
index 7c40f981d2c75d236a33faf843c03a1c100bf5e7..3eeb21b9fddface4d1122a6be9389f5ca1598f0f 100644 (file)
@@ -389,7 +389,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
  *
  * XXX: commands with data in MIPI_DPI_DATA?
  */
-int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd)
+int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs)
 {
        struct drm_encoder *encoder = &intel_dsi->base.base;
        struct drm_device *dev = encoder->dev;
@@ -399,7 +399,7 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd)
        u32 mask;
 
        /* XXX: pipe, hs */
-       if (intel_dsi->hs)
+       if (hs)
                cmd &= ~DPI_LP_MODE;
        else
                cmd |= DPI_LP_MODE;
index 54c8a234a2e0fc53d7c5f3e5a01ec02351ceff9a..9a18cbfa546010320826013c956f53c8c9eb0d02 100644 (file)
@@ -33,6 +33,9 @@
 #include "intel_drv.h"
 #include "intel_dsi.h"
 
+#define DPI_LP_MODE_EN false
+#define DPI_HS_MODE_EN true
+
 void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable);
 
 int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
@@ -47,7 +50,7 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
 int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
                        u8 *reqdata, int reqlen, u8 *buf, int buflen);
 
-int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd);
+int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs);
 
 /* XXX: questionable write helpers */
 static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi,
index 7fe3feedfe039cda453851f1338fd56b100945cb..1604235d58e6f508446785677198ddbaf9a1be8b 100644 (file)
@@ -285,7 +285,7 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_dvo_mode_set(struct intel_encoder *encoder)
+static void intel_dvo_pre_enable(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -475,7 +475,7 @@ void intel_dvo_init(struct drm_device *dev)
        intel_encoder->get_hw_state = intel_dvo_get_hw_state;
        intel_encoder->get_config = intel_dvo_get_config;
        intel_encoder->compute_config = intel_dvo_compute_config;
-       intel_encoder->mode_set = intel_dvo_mode_set;
+       intel_encoder->pre_enable = intel_dvo_pre_enable;
        intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
        intel_connector->unregister = intel_connector_unregister;
 
index b4d44e62f0c769746a538f70afdf9916c95f6bd8..fce4a0d93c0b19b7d51f4d2578331b13aef51399 100644 (file)
@@ -132,6 +132,16 @@ static int intelfb_create(struct drm_fb_helper *helper,
 
        mutex_lock(&dev->struct_mutex);
 
+       if (intel_fb &&
+           (sizes->fb_width > intel_fb->base.width ||
+            sizes->fb_height > intel_fb->base.height)) {
+               DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d),"
+                             " releasing it\n",
+                             intel_fb->base.width, intel_fb->base.height,
+                             sizes->fb_width, sizes->fb_height);
+               drm_framebuffer_unreference(&intel_fb->base);
+               intel_fb = ifbdev->fb = NULL;
+       }
        if (!intel_fb || WARN_ON(!intel_fb->obj)) {
                DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
                ret = intelfb_alloc(helper, sizes);
index b0413e190625b26c0552e8a737479f52b3dd5c9d..b606162cc17c755a3ef890dca23c7af8c997c56d 100644 (file)
@@ -557,10 +557,12 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
                               struct drm_display_mode *adjusted_mode)
 {
        struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
        u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
+       u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
 
        assert_hdmi_port_disabled(intel_hdmi);
 
@@ -576,9 +578,19 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
                return;
        }
 
+       if (port != (val & VIDEO_DIP_PORT_MASK)) {
+               if (val & VIDEO_DIP_ENABLE) {
+                       val &= ~VIDEO_DIP_ENABLE;
+                       I915_WRITE(reg, val);
+                       POSTING_READ(reg);
+               }
+               val &= ~VIDEO_DIP_PORT_MASK;
+               val |= port;
+       }
+
        val |= VIDEO_DIP_ENABLE;
-       val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
-                VIDEO_DIP_ENABLE_GCP);
+       val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR |
+                VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP);
 
        I915_WRITE(reg, val);
        POSTING_READ(reg);
@@ -638,8 +650,8 @@ static void intel_hdmi_mode_set(struct intel_encoder *encoder)
        else
                hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
 
-       /* Required on CPT */
-       if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
+       if (intel_hdmi->has_hdmi_sink &&
+           (HAS_PCH_CPT(dev) || IS_VALLEYVIEW(dev)))
                hdmi_val |= HDMI_MODE_SELECT_HDMI;
 
        if (intel_hdmi->has_audio) {
@@ -657,8 +669,6 @@ static void intel_hdmi_mode_set(struct intel_encoder *encoder)
 
        I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
        POSTING_READ(intel_hdmi->hdmi_reg);
-
-       intel_hdmi->set_infoframes(&encoder->base, adjusted_mode);
 }
 
 static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
@@ -821,11 +831,11 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
        }
 }
 
-static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
+static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
 {
        struct drm_device *dev = intel_hdmi_to_dev(hdmi);
 
-       if (!hdmi->has_hdmi_sink || IS_G4X(dev))
+       if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev))
                return 165000;
        else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
                return 300000;
@@ -837,7 +847,8 @@ static enum drm_mode_status
 intel_hdmi_mode_valid(struct drm_connector *connector,
                      struct drm_display_mode *mode)
 {
-       if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector)))
+       if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector),
+                                              true))
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
                return MODE_CLOCK_LOW;
@@ -879,7 +890,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        struct drm_device *dev = encoder->base.dev;
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2;
-       int portclock_limit = hdmi_portclock_limit(intel_hdmi);
+       int portclock_limit = hdmi_portclock_limit(intel_hdmi, false);
        int desired_bpp;
 
        if (intel_hdmi->color_range_auto) {
@@ -1103,13 +1114,26 @@ done:
        return 0;
 }
 
+static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       struct drm_display_mode *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
+
+       intel_hdmi->set_infoframes(&encoder->base, adjusted_mode);
+}
+
 static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
 {
        struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+       struct intel_hdmi *intel_hdmi = &dport->hdmi;
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(encoder->base.crtc);
+       struct drm_display_mode *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
        enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
        u32 val;
@@ -1143,6 +1167,8 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
        vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888);
        mutex_unlock(&dev_priv->dpio_lock);
 
+       intel_hdmi->set_infoframes(&encoder->base, adjusted_mode);
+
        intel_enable_hdmi(encoder);
 
        vlv_wait_port_ready(dev_priv, dport);
@@ -1338,6 +1364,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
                intel_encoder->enable = vlv_enable_hdmi;
                intel_encoder->post_disable = vlv_hdmi_post_disable;
        } else {
+               intel_encoder->pre_enable = intel_hdmi_pre_enable;
                intel_encoder->enable = intel_enable_hdmi;
        }
 
index f1ecf916474a93e3a18dd604991a8915309d83cb..1b1541dfb4400addfd5288a5e989a8943216abcc 100644 (file)
@@ -111,13 +111,6 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
 
        pipe_config->adjusted_mode.flags |= flags;
 
-       /* gen2/3 store dither state in pfit control, needs to match */
-       if (INTEL_INFO(dev)->gen < 4) {
-               tmp = I915_READ(PFIT_CONTROL);
-
-               pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
-       }
-
        dotclock = pipe_config->port_clock;
 
        if (HAS_PCH_SPLIT(dev_priv->dev))
index 0eead16aeda7404053de8c9885992b0904c1049c..44ad415e37067be162682d68368f95fc9083638b 100644 (file)
@@ -308,16 +308,16 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
                pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
                                 PFIT_FILTER_FUZZY);
 
+       /* Make sure pre-965 set dither correctly for 18bpp panels. */
+       if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
+               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+
 out:
        if ((pfit_control & PFIT_ENABLE) == 0) {
                pfit_control = 0;
                pfit_pgm_ratios = 0;
        }
 
-       /* Make sure pre-965 set dither correctly for 18bpp panels. */
-       if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
-               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-
        pipe_config->gmch_pfit.control = pfit_control;
        pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
        pipe_config->gmch_pfit.lvds_border_bits = border;
index 19e94c3edc1957d96b928fb23d696b393216fc42..eae82c70dcc13f5778e3afa926bda9f2f92a2a71 100644 (file)
@@ -1831,6 +1831,40 @@ static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
                return 512;
 }
 
+static unsigned int ilk_plane_wm_reg_max(const struct drm_device *dev,
+                                        int level, bool is_sprite)
+{
+       if (INTEL_INFO(dev)->gen >= 8)
+               /* BDW primary/sprite plane watermarks */
+               return level == 0 ? 255 : 2047;
+       else if (INTEL_INFO(dev)->gen >= 7)
+               /* IVB/HSW primary/sprite plane watermarks */
+               return level == 0 ? 127 : 1023;
+       else if (!is_sprite)
+               /* ILK/SNB primary plane watermarks */
+               return level == 0 ? 127 : 511;
+       else
+               /* ILK/SNB sprite plane watermarks */
+               return level == 0 ? 63 : 255;
+}
+
+static unsigned int ilk_cursor_wm_reg_max(const struct drm_device *dev,
+                                         int level)
+{
+       if (INTEL_INFO(dev)->gen >= 7)
+               return level == 0 ? 63 : 255;
+       else
+               return level == 0 ? 31 : 63;
+}
+
+static unsigned int ilk_fbc_wm_reg_max(const struct drm_device *dev)
+{
+       if (INTEL_INFO(dev)->gen >= 8)
+               return 31;
+       else
+               return 15;
+}
+
 /* Calculate the maximum primary/sprite plane watermark */
 static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
                                     int level,
@@ -1839,7 +1873,6 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
                                     bool is_sprite)
 {
        unsigned int fifo_size = ilk_display_fifo_size(dev);
-       unsigned int max;
 
        /* if sprites aren't enabled, sprites get nothing */
        if (is_sprite && !config->sprites_enabled)
@@ -1870,19 +1903,7 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
        }
 
        /* clamp to max that the registers can hold */
-       if (INTEL_INFO(dev)->gen >= 8)
-               max = level == 0 ? 255 : 2047;
-       else if (INTEL_INFO(dev)->gen >= 7)
-               /* IVB/HSW primary/sprite plane watermarks */
-               max = level == 0 ? 127 : 1023;
-       else if (!is_sprite)
-               /* ILK/SNB primary plane watermarks */
-               max = level == 0 ? 127 : 511;
-       else
-               /* ILK/SNB sprite plane watermarks */
-               max = level == 0 ? 63 : 255;
-
-       return min(fifo_size, max);
+       return min(fifo_size, ilk_plane_wm_reg_max(dev, level, is_sprite));
 }
 
 /* Calculate the maximum cursor plane watermark */
@@ -1895,20 +1916,7 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev,
                return 64;
 
        /* otherwise just report max that registers can hold */
-       if (INTEL_INFO(dev)->gen >= 7)
-               return level == 0 ? 63 : 255;
-       else
-               return level == 0 ? 31 : 63;
-}
-
-/* Calculate the maximum FBC watermark */
-static unsigned int ilk_fbc_wm_max(const struct drm_device *dev)
-{
-       /* max that registers can hold */
-       if (INTEL_INFO(dev)->gen >= 8)
-               return 31;
-       else
-               return 15;
+       return ilk_cursor_wm_reg_max(dev, level);
 }
 
 static void ilk_compute_wm_maximums(const struct drm_device *dev,
@@ -1920,7 +1928,7 @@ static void ilk_compute_wm_maximums(const struct drm_device *dev,
        max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false);
        max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true);
        max->cur = ilk_cursor_wm_max(dev, level, config);
-       max->fbc = ilk_fbc_wm_max(dev);
+       max->fbc = ilk_fbc_wm_reg_max(dev);
 }
 
 static bool ilk_validate_wm_level(int level,
@@ -2115,38 +2123,52 @@ static void ilk_setup_wm_latency(struct drm_device *dev)
 }
 
 static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
-                                     struct ilk_pipe_wm_parameters *p,
-                                     struct intel_wm_config *config)
+                                     struct ilk_pipe_wm_parameters *p)
 {
        struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
        struct drm_plane *plane;
 
-       p->active = intel_crtc_active(crtc);
-       if (p->active) {
-               p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
-               p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
-               p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
-               p->cur.bytes_per_pixel = 4;
-               p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
-               p->cur.horiz_pixels = intel_crtc->cursor_width;
-               /* TODO: for now, assume primary and cursor planes are always enabled. */
-               p->pri.enabled = true;
-               p->cur.enabled = true;
-       }
+       if (!intel_crtc_active(crtc))
+               return;
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-               config->num_pipes_active += intel_crtc_active(crtc);
+       p->active = true;
+       p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
+       p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
+       p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
+       p->cur.bytes_per_pixel = 4;
+       p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
+       p->cur.horiz_pixels = intel_crtc->cursor_width;
+       /* TODO: for now, assume primary and cursor planes are always enabled. */
+       p->pri.enabled = true;
+       p->cur.enabled = true;
 
        drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                struct intel_plane *intel_plane = to_intel_plane(plane);
 
-               if (intel_plane->pipe == pipe)
+               if (intel_plane->pipe == pipe) {
                        p->spr = intel_plane->wm;
+                       break;
+               }
+       }
+}
+
+static void ilk_compute_wm_config(struct drm_device *dev,
+                                 struct intel_wm_config *config)
+{
+       struct intel_crtc *intel_crtc;
+
+       /* Compute the currently _active_ config */
+       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
+               const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
+
+               if (!wm->pipe_enabled)
+                       continue;
 
-               config->sprites_enabled |= intel_plane->wm.enabled;
-               config->sprites_scaled |= intel_plane->wm.scaled;
+               config->sprites_enabled |= wm->sprites_enabled;
+               config->sprites_scaled |= wm->sprites_scaled;
+               config->num_pipes_active++;
        }
 }
 
@@ -2169,6 +2191,10 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
        /* LP0 watermarks always use 1/2 DDB partitioning */
        ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
 
+       pipe_wm->pipe_enabled = params->active;
+       pipe_wm->sprites_enabled = params->spr.enabled;
+       pipe_wm->sprites_scaled = params->spr.scaled;
+
        /* ILK/SNB: LP2+ watermarks only w/o sprites */
        if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled)
                max_level = 1;
@@ -2198,8 +2224,11 @@ static void ilk_merge_wm_level(struct drm_device *dev,
        const struct intel_crtc *intel_crtc;
 
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
-               const struct intel_wm_level *wm =
-                       &intel_crtc->wm.active.wm[level];
+               const struct intel_pipe_wm *active = &intel_crtc->wm.active;
+               const struct intel_wm_level *wm = &active->wm[level];
+
+               if (!active->pipe_enabled)
+                       continue;
 
                if (!wm->enable)
                        return;
@@ -2558,7 +2587,7 @@ static void ilk_update_wm(struct drm_crtc *crtc)
        struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
        struct intel_wm_config config = {};
 
-       ilk_compute_wm_parameters(crtc, &params, &config);
+       ilk_compute_wm_parameters(crtc, &params);
 
        intel_compute_pipe_wm(crtc, &params, &pipe_wm);
 
@@ -2567,6 +2596,8 @@ static void ilk_update_wm(struct drm_crtc *crtc)
 
        intel_crtc->wm.active = pipe_wm;
 
+       ilk_compute_wm_config(dev, &config);
+
        ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max);
        ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
 
@@ -2633,7 +2664,9 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
 
-       if (intel_crtc_active(crtc)) {
+       active->pipe_enabled = intel_crtc_active(crtc);
+
+       if (active->pipe_enabled) {
                u32 tmp = hw->wm_pipe[pipe];
 
                /*
@@ -2674,8 +2707,10 @@ void ilk_wm_get_hw_state(struct drm_device *dev)
        hw->wm_lp[2] = I915_READ(WM3_LP_ILK);
 
        hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
-       hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
-       hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
+       if (INTEL_INFO(dev)->gen >= 7) {
+               hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
+               hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
+       }
 
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
@@ -3051,7 +3086,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
        if (val != dev_priv->rps.cur_freq) {
                gen6_set_rps_thresholds(dev_priv, val);
 
-               if (IS_HASWELL(dev))
+               if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                        I915_WRITE(GEN6_RPNSWREQ,
                                   HSW_FREQUENCY(val));
                else
@@ -3094,16 +3129,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
        /* Mask turbo interrupt so that they will not come in between */
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
 
-       /* Bring up the Gfx clock */
-       I915_WRITE(VLV_GTLC_SURVIVABILITY_REG,
-               I915_READ(VLV_GTLC_SURVIVABILITY_REG) |
-                               VLV_GFX_CLK_FORCE_ON_BIT);
-
-       if (wait_for(((VLV_GFX_CLK_STATUS_BIT &
-               I915_READ(VLV_GTLC_SURVIVABILITY_REG)) != 0), 5)) {
-                       DRM_ERROR("GFX_CLK_ON request timed out\n");
-               return;
-       }
+       vlv_force_gfx_clock(dev_priv, true);
 
        dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
 
@@ -3114,10 +3140,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
                                & GENFREQSTATUS) == 0, 5))
                DRM_ERROR("timed out waiting for Punit\n");
 
-       /* Release the Gfx clock */
-       I915_WRITE(VLV_GTLC_SURVIVABILITY_REG,
-               I915_READ(VLV_GTLC_SURVIVABILITY_REG) &
-                               ~VLV_GFX_CLK_FORCE_ON_BIT);
+       vlv_force_gfx_clock(dev_priv, false);
 
        I915_WRITE(GEN6_PMINTRMSK,
                   gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
@@ -3215,21 +3238,48 @@ static void valleyview_disable_rps(struct drm_device *dev)
 
 static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
 {
+       if (IS_VALLEYVIEW(dev)) {
+               if (mode & (GEN7_RC_CTL_TO_MODE | GEN6_RC_CTL_EI_MODE(1)))
+                       mode = GEN6_RC_CTL_RC6_ENABLE;
+               else
+                       mode = 0;
+       }
        DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
                 (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off",
                 (mode & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off",
                 (mode & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off");
 }
 
-int intel_enable_rc6(const struct drm_device *dev)
+static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6)
 {
        /* No RC6 before Ironlake */
        if (INTEL_INFO(dev)->gen < 5)
                return 0;
 
+       /* RC6 is only on Ironlake mobile not on desktop */
+       if (INTEL_INFO(dev)->gen == 5 && !IS_IRONLAKE_M(dev))
+               return 0;
+
+       /* Disable RC6 on Broadwell for now */
+       if (IS_BROADWELL(dev))
+               return 0;
+
        /* Respect the kernel parameter if it is set */
-       if (i915.enable_rc6 >= 0)
-               return i915.enable_rc6;
+       if (enable_rc6 >= 0) {
+               int mask;
+
+               if (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
+                       mask = INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE |
+                              INTEL_RC6pp_ENABLE;
+               else
+                       mask = INTEL_RC6_ENABLE;
+
+               if ((enable_rc6 & mask) != enable_rc6)
+                       DRM_INFO("Adjusting RC6 mask to %d (requested %d, valid %d)\n",
+                                enable_rc6, enable_rc6 & mask, mask);
+
+               return enable_rc6 & mask;
+       }
 
        /* Disable RC6 on Ironlake */
        if (INTEL_INFO(dev)->gen == 5)
@@ -3241,6 +3291,11 @@ int intel_enable_rc6(const struct drm_device *dev)
        return INTEL_RC6_ENABLE;
 }
 
+int intel_enable_rc6(const struct drm_device *dev)
+{
+       return i915.enable_rc6;
+}
+
 static void gen6_enable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3252,6 +3307,27 @@ static void gen6_enable_rps_interrupts(struct drm_device *dev)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
+static void parse_rp_state_cap(struct drm_i915_private *dev_priv, u32 rp_state_cap)
+{
+       /* All of these values are in units of 50MHz */
+       dev_priv->rps.cur_freq          = 0;
+       /* static values from HW: RP0 < RPe < RP1 < RPn (min_freq) */
+       dev_priv->rps.rp1_freq          = (rp_state_cap >>  8) & 0xff;
+       dev_priv->rps.rp0_freq          = (rp_state_cap >>  0) & 0xff;
+       dev_priv->rps.min_freq          = (rp_state_cap >> 16) & 0xff;
+       /* XXX: only BYT has a special efficient freq */
+       dev_priv->rps.efficient_freq    = dev_priv->rps.rp1_freq;
+       /* hw_max = RP0 until we check for overclocking */
+       dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
+
+       /* Preserve min/max settings in case of re-init */
+       if (dev_priv->rps.max_freq_softlimit == 0)
+               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
+
+       if (dev_priv->rps.min_freq_softlimit == 0)
+               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
+}
+
 static void gen8_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3270,6 +3346,7 @@ static void gen8_enable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RC_CONTROL, 0);
 
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+       parse_rp_state_cap(dev_priv, rp_state_cap);
 
        /* 2b: Program RC6 thresholds.*/
        I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
@@ -3289,8 +3366,10 @@ static void gen8_enable_rps(struct drm_device *dev)
                                    rc6_mask);
 
        /* 4 Program defaults and thresholds for RPS*/
-       I915_WRITE(GEN6_RPNSWREQ, HSW_FREQUENCY(10)); /* Request 500 MHz */
-       I915_WRITE(GEN6_RC_VIDEO_FREQ, HSW_FREQUENCY(12)); /* Request 600 MHz */
+       I915_WRITE(GEN6_RPNSWREQ,
+                  HSW_FREQUENCY(dev_priv->rps.rp1_freq));
+       I915_WRITE(GEN6_RC_VIDEO_FREQ,
+                  HSW_FREQUENCY(dev_priv->rps.rp1_freq));
        /* NB: Docs say 1s, and 1000000 - which aren't equivalent */
        I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 100000000 / 128); /* 1 second timeout */
 
@@ -3356,23 +3435,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
        gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 
-       /* All of these values are in units of 50MHz */
-       dev_priv->rps.cur_freq          = 0;
-       /* static values from HW: RP0 < RPe < RP1 < RPn (min_freq) */
-       dev_priv->rps.rp1_freq          = (rp_state_cap >>  8) & 0xff;
-       dev_priv->rps.rp0_freq          = (rp_state_cap >>  0) & 0xff;
-       dev_priv->rps.min_freq          = (rp_state_cap >> 16) & 0xff;
-       /* XXX: only BYT has a special efficient freq */
-       dev_priv->rps.efficient_freq    = dev_priv->rps.rp1_freq;
-       /* hw_max = RP0 until we check for overclocking */
-       dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
-
-       /* Preserve min/max settings in case of re-init */
-       if (dev_priv->rps.max_freq_softlimit == 0)
-               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
-
-       if (dev_priv->rps.min_freq_softlimit == 0)
-               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
+       parse_rp_state_cap(dev_priv, rp_state_cap);
 
        /* disable the counters and set deterministic thresholds */
        I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -3454,7 +3517,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
-void gen6_update_ring_freq(struct drm_device *dev)
+static void __gen6_update_ring_freq(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int min_freq = 15;
@@ -3524,6 +3587,18 @@ void gen6_update_ring_freq(struct drm_device *dev)
        }
 }
 
+void gen6_update_ring_freq(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (INTEL_INFO(dev)->gen < 6 || IS_VALLEYVIEW(dev))
+               return;
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+       __gen6_update_ring_freq(dev);
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
 int valleyview_rps_max_freq(struct drm_i915_private *dev_priv)
 {
        u32 val, rp0;
@@ -3618,6 +3693,45 @@ static void valleyview_cleanup_pctx(struct drm_device *dev)
        dev_priv->vlv_pctx = NULL;
 }
 
+static void valleyview_init_gt_powersave(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       valleyview_setup_pctx(dev);
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+       dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
+       dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
+       DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
+                        dev_priv->rps.max_freq);
+
+       dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
+       DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+                        dev_priv->rps.efficient_freq);
+
+       dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
+       DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
+                        dev_priv->rps.min_freq);
+
+       /* Preserve min/max settings in case of re-init */
+       if (dev_priv->rps.max_freq_softlimit == 0)
+               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
+
+       if (dev_priv->rps.min_freq_softlimit == 0)
+               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
+
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void valleyview_cleanup_gt_powersave(struct drm_device *dev)
+{
+       valleyview_cleanup_pctx(dev);
+}
+
 static void valleyview_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3684,29 +3798,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
                         vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
                         dev_priv->rps.cur_freq);
 
-       dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
-       dev_priv->rps.rp0_freq  = dev_priv->rps.max_freq;
-       DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
-                        dev_priv->rps.max_freq);
-
-       dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
-       DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
-                        dev_priv->rps.efficient_freq);
-
-       dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
-       DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
-                        dev_priv->rps.min_freq);
-
-       /* Preserve min/max settings in case of re-init */
-       if (dev_priv->rps.max_freq_softlimit == 0)
-               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
-
-       if (dev_priv->rps.min_freq_softlimit == 0)
-               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
-
        DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
                         vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
                         dev_priv->rps.efficient_freq);
@@ -3833,7 +3924,7 @@ static void ironlake_enable_rc6(struct drm_device *dev)
        I915_WRITE(PWRCTXA, i915_gem_obj_ggtt_offset(dev_priv->ips.pwrctx) | PWRCTX_EN);
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
 
-       intel_print_rc6_info(dev, INTEL_RC6_ENABLE);
+       intel_print_rc6_info(dev, GEN6_RC_CTL_RC6_ENABLE);
 }
 
 static unsigned long intel_pxfreq(u32 vidfreq)
@@ -4447,14 +4538,16 @@ static void intel_init_emon(struct drm_device *dev)
 
 void intel_init_gt_powersave(struct drm_device *dev)
 {
+       i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6);
+
        if (IS_VALLEYVIEW(dev))
-               valleyview_setup_pctx(dev);
+               valleyview_init_gt_powersave(dev);
 }
 
 void intel_cleanup_gt_powersave(struct drm_device *dev)
 {
        if (IS_VALLEYVIEW(dev))
-               valleyview_cleanup_pctx(dev);
+               valleyview_cleanup_gt_powersave(dev);
 }
 
 void intel_disable_gt_powersave(struct drm_device *dev)
@@ -4467,7 +4560,7 @@ void intel_disable_gt_powersave(struct drm_device *dev)
        if (IS_IRONLAKE_M(dev)) {
                ironlake_disable_drps(dev);
                ironlake_disable_rc6(dev);
-       } else if (INTEL_INFO(dev)->gen >= 6) {
+       } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
                cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
                cancel_work_sync(&dev_priv->rps.work);
                mutex_lock(&dev_priv->rps.hw_lock);
@@ -4493,13 +4586,15 @@ static void intel_gen6_powersave_work(struct work_struct *work)
                valleyview_enable_rps(dev);
        } else if (IS_BROADWELL(dev)) {
                gen8_enable_rps(dev);
-               gen6_update_ring_freq(dev);
+               __gen6_update_ring_freq(dev);
        } else {
                gen6_enable_rps(dev);
-               gen6_update_ring_freq(dev);
+               __gen6_update_ring_freq(dev);
        }
        dev_priv->rps.enabled = true;
        mutex_unlock(&dev_priv->rps.hw_lock);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
 void intel_enable_gt_powersave(struct drm_device *dev)
@@ -4507,20 +4602,38 @@ void intel_enable_gt_powersave(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (IS_IRONLAKE_M(dev)) {
+               mutex_lock(&dev->struct_mutex);
                ironlake_enable_drps(dev);
                ironlake_enable_rc6(dev);
                intel_init_emon(dev);
+               mutex_unlock(&dev->struct_mutex);
        } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
                /*
                 * PCU communication is slow and this doesn't need to be
                 * done at any specific time, so do this out of our fast path
                 * to make resume and init faster.
+                *
+                * We depend on the HW RC6 power context save/restore
+                * mechanism when entering D3 through runtime PM suspend. So
+                * disable RPM until RPS/RC6 is properly setup. We can only
+                * get here via the driver load/system resume/runtime resume
+                * paths, so the _noresume version is enough (and in case of
+                * runtime resume it's necessary).
                 */
-               schedule_delayed_work(&dev_priv->rps.delayed_resume_work,
-                                     round_jiffies_up_relative(HZ));
+               if (schedule_delayed_work(&dev_priv->rps.delayed_resume_work,
+                                          round_jiffies_up_relative(HZ)))
+                       intel_runtime_pm_get_noresume(dev_priv);
        }
 }
 
+void intel_reset_gt_powersave(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->rps.enabled = false;
+       intel_enable_gt_powersave(dev);
+}
+
 static void ibx_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4626,6 +4739,9 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
        I915_WRITE(CACHE_MODE_0,
                   _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE));
 
+       /* WaDisable_RenderCache_OperationalFlush:ilk */
+       I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
+
        g4x_disable_trickle_feed(dev);
 
        ibx_init_clock_gating(dev);
@@ -4701,6 +4817,9 @@ static void gen6_init_clock_gating(struct drm_device *dev)
                I915_WRITE(GEN6_GT_MODE,
                           _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE));
 
+       /* WaDisable_RenderCache_OperationalFlush:snb */
+       I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
+
        /*
         * BSpec recoomends 8x4 when MSAA is used,
         * however in practice 16x4 seems fastest.
@@ -4869,6 +4988,10 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
                   _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
 
+       /* WaDisableDopClockGating:bdw May not be needed for production */
+       I915_WRITE(GEN7_ROW_CHICKEN2,
+                  _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
+
        /* WaSwitchSolVfFArbitrationPriority:bdw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
@@ -4940,6 +5063,9 @@ static void haswell_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_FF_THREAD_MODE,
                   I915_READ(GEN7_FF_THREAD_MODE) & ~GEN7_FF_VS_REF_CNT_FFME);
 
+       /* WaDisable_RenderCache_OperationalFlush:hsw */
+       I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
+
        /* enable HiZ Raw Stall Optimization */
        I915_WRITE(CACHE_MODE_0_GEN7,
                   _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE));
@@ -4992,6 +5118,9 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
                I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
                           _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 
+       /* WaDisable_RenderCache_OperationalFlush:ivb */
+       I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
+
        /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */
        I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
                   GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
@@ -5086,6 +5215,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
        }
        DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
 
+       dev_priv->vlv_cdclk_freq = valleyview_cur_cdclk(dev_priv);
+       DRM_DEBUG_DRIVER("Current CD clock rate: %d MHz",
+                        dev_priv->vlv_cdclk_freq);
+
        I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
 
        /* WaDisableEarlyCull:vlv */
@@ -5103,6 +5236,9 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
                   _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP |
                                      GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 
+       /* WaDisable_RenderCache_OperationalFlush:vlv */
+       I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
+
        /* WaForceL3Serialization:vlv */
        I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
                   ~L3SQ_URB_READ_CAM_MATCH_DISABLE);
@@ -5172,6 +5308,9 @@ static void g4x_init_clock_gating(struct drm_device *dev)
        I915_WRITE(CACHE_MODE_0,
                   _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE));
 
+       /* WaDisable_RenderCache_OperationalFlush:g4x */
+       I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
+
        g4x_disable_trickle_feed(dev);
 }
 
@@ -5186,6 +5325,9 @@ static void crestline_init_clock_gating(struct drm_device *dev)
        I915_WRITE16(DEUC, 0);
        I915_WRITE(MI_ARB_STATE,
                   _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
+
+       /* WaDisable_RenderCache_OperationalFlush:gen4 */
+       I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
 }
 
 static void broadwater_init_clock_gating(struct drm_device *dev)
@@ -5200,6 +5342,9 @@ static void broadwater_init_clock_gating(struct drm_device *dev)
        I915_WRITE(RENCLK_GATE_D2, 0);
        I915_WRITE(MI_ARB_STATE,
                   _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
+
+       /* WaDisable_RenderCache_OperationalFlush:gen4 */
+       I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
 }
 
 static void gen3_init_clock_gating(struct drm_device *dev)
@@ -5551,11 +5696,13 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
        spin_unlock_irq(&dev_priv->irq_lock);
 
        /*
-        * During driver initialization we need to defer enabling hotplug
-        * processing until fbdev is set up.
+        * During driver initialization/resume we can avoid restoring the
+        * part of the HW/SW state that will be inited anyway explicitly.
         */
-       if (dev_priv->enable_hotplug_processing)
-               intel_hpd_init(dev_priv->dev);
+       if (dev_priv->power_domains.initializing)
+               return;
+
+       intel_hpd_init(dev_priv->dev);
 
        i915_redisable_vga_power_on(dev_priv->dev);
 }
@@ -5919,9 +6066,13 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
 
 void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
 {
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+       power_domains->initializing = true;
        /* For now, we need the power well to be always enabled. */
        intel_display_set_init_power(dev_priv, true);
        intel_power_domains_resume(dev_priv);
+       power_domains->initializing = false;
 }
 
 void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
@@ -5946,6 +6097,18 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
        WARN(dev_priv->pm.suspended, "Device still suspended.\n");
 }
 
+void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct device *device = &dev->pdev->dev;
+
+       if (!HAS_RUNTIME_PM(dev))
+               return;
+
+       WARN(dev_priv->pm.suspended, "Getting nosync-ref while suspended.\n");
+       pm_runtime_get_noresume(device);
+}
+
 void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
@@ -5968,6 +6131,15 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
 
        pm_runtime_set_active(device);
 
+       /*
+        * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
+        * requirement.
+        */
+       if (!intel_enable_rc6(dev)) {
+               DRM_INFO("RC6 disabled, disabling runtime PM support\n");
+               return;
+       }
+
        pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
        pm_runtime_mark_last_busy(device);
        pm_runtime_use_autosuspend(device);
@@ -5983,6 +6155,9 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
        if (!HAS_RUNTIME_PM(dev))
                return;
 
+       if (!intel_enable_rc6(dev))
+               return;
+
        /* Make sure we're not suspended first. */
        pm_runtime_get_sync(device);
        pm_runtime_disable(device);
index 6bc68bdcf433cf06a68d52d95b063f9a42795194..40a7aa4db589b2293dc89fdb280872e5c710a4a1 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
+ * but keeps the logic simple. Indeed, the whole purpose of this macro is just
+ * to give some inclination as to some of the magic values used in the various
+ * workarounds!
+ */
+#define CACHELINE_BYTES 64
+
 static inline int ring_space(struct intel_ring_buffer *ring)
 {
        int space = (ring->head & HEAD_ADDR) - (ring->tail + I915_RING_FREE_SPACE);
@@ -41,12 +48,16 @@ static inline int ring_space(struct intel_ring_buffer *ring)
        return space;
 }
 
-void __intel_ring_advance(struct intel_ring_buffer *ring)
+static bool intel_ring_stopped(struct intel_ring_buffer *ring)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring);
+}
 
+void __intel_ring_advance(struct intel_ring_buffer *ring)
+{
        ring->tail &= ring->size - 1;
-       if (dev_priv->gpu_error.stop_rings & intel_ring_flag(ring))
+       if (intel_ring_stopped(ring))
                return;
        ring->write_tail(ring, ring->tail);
 }
@@ -175,7 +186,7 @@ gen4_render_ring_flush(struct intel_ring_buffer *ring,
 static int
 intel_emit_post_sync_nonzero_flush(struct intel_ring_buffer *ring)
 {
-       u32 scratch_addr = ring->scratch.gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
 
@@ -212,7 +223,7 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
                          u32 invalidate_domains, u32 flush_domains)
 {
        u32 flags = 0;
-       u32 scratch_addr = ring->scratch.gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        /* Force SNB workarounds for PIPE_CONTROL flushes */
@@ -306,7 +317,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
                       u32 invalidate_domains, u32 flush_domains)
 {
        u32 flags = 0;
-       u32 scratch_addr = ring->scratch.gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        /*
@@ -367,7 +378,7 @@ gen8_render_ring_flush(struct intel_ring_buffer *ring,
                       u32 invalidate_domains, u32 flush_domains)
 {
        u32 flags = 0;
-       u32 scratch_addr = ring->scratch.gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        flags |= PIPE_CONTROL_CS_STALL;
@@ -437,32 +448,41 @@ static void ring_setup_phys_status_page(struct intel_ring_buffer *ring)
        I915_WRITE(HWS_PGA, addr);
 }
 
-static int init_ring_common(struct intel_ring_buffer *ring)
+static bool stop_ring(struct intel_ring_buffer *ring)
 {
-       struct drm_device *dev = ring->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj = ring->obj;
-       int ret = 0;
-       u32 head;
+       struct drm_i915_private *dev_priv = to_i915(ring->dev);
 
-       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+       if (!IS_GEN2(ring->dev)) {
+               I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
+               if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
+                       DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
+                       return false;
+               }
+       }
 
-       /* Stop the ring if it's running. */
        I915_WRITE_CTL(ring, 0);
        I915_WRITE_HEAD(ring, 0);
        ring->write_tail(ring, 0);
-       if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000))
-               DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
 
-       if (I915_NEED_GFX_HWS(dev))
-               intel_ring_setup_status_page(ring);
-       else
-               ring_setup_phys_status_page(ring);
+       if (!IS_GEN2(ring->dev)) {
+               (void)I915_READ_CTL(ring);
+               I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
+       }
+
+       return (I915_READ_HEAD(ring) & HEAD_ADDR) == 0;
+}
+
+static int init_ring_common(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj = ring->obj;
+       int ret = 0;
 
-       head = I915_READ_HEAD(ring) & HEAD_ADDR;
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
-       /* G45 ring initialization fails to reset head to zero */
-       if (head != 0) {
+       if (!stop_ring(ring)) {
+               /* G45 ring initialization often fails to reset head to zero */
                DRM_DEBUG_KMS("%s head not reset to zero "
                              "ctl %08x head %08x tail %08x start %08x\n",
                              ring->name,
@@ -471,9 +491,7 @@ static int init_ring_common(struct intel_ring_buffer *ring)
                              I915_READ_TAIL(ring),
                              I915_READ_START(ring));
 
-               I915_WRITE_HEAD(ring, 0);
-
-               if (I915_READ_HEAD(ring) & HEAD_ADDR) {
+               if (!stop_ring(ring)) {
                        DRM_ERROR("failed to set %s head to zero "
                                  "ctl %08x head %08x tail %08x start %08x\n",
                                  ring->name,
@@ -481,9 +499,16 @@ static int init_ring_common(struct intel_ring_buffer *ring)
                                  I915_READ_HEAD(ring),
                                  I915_READ_TAIL(ring),
                                  I915_READ_START(ring));
+                       ret = -EIO;
+                       goto out;
                }
        }
 
+       if (I915_NEED_GFX_HWS(dev))
+               intel_ring_setup_status_page(ring);
+       else
+               ring_setup_phys_status_page(ring);
+
        /* Initialize the ring. This must happen _after_ we've cleared the ring
         * registers with the above sequence (the readback of the HEAD registers
         * also enforces ordering), otherwise the hw might lose the new ring
@@ -498,12 +523,11 @@ static int init_ring_common(struct intel_ring_buffer *ring)
                     I915_READ_START(ring) == i915_gem_obj_ggtt_offset(obj) &&
                     (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) {
                DRM_ERROR("%s initialization failed "
-                               "ctl %08x head %08x tail %08x start %08x\n",
-                               ring->name,
-                               I915_READ_CTL(ring),
-                               I915_READ_HEAD(ring),
-                               I915_READ_TAIL(ring),
-                               I915_READ_START(ring));
+                         "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08lx]\n",
+                         ring->name,
+                         I915_READ_CTL(ring), I915_READ_CTL(ring) & RING_VALID,
+                         I915_READ_HEAD(ring), I915_READ_TAIL(ring),
+                         I915_READ_START(ring), (unsigned long)i915_gem_obj_ggtt_offset(obj));
                ret = -EIO;
                goto out;
        }
@@ -587,13 +611,15 @@ static int init_render_ring(struct intel_ring_buffer *ring)
                I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
 
        /* Required for the hardware to program scanline values for waiting */
+       /* WaEnableFlushTlbInvalidationMode:snb */
        if (INTEL_INFO(dev)->gen == 6)
                I915_WRITE(GFX_MODE,
-                          _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_ALWAYS));
+                          _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT));
 
+       /* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */
        if (IS_GEN7(dev))
                I915_WRITE(GFX_MODE_GEN7,
-                          _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
+                          _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
                           _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
        if (INTEL_INFO(dev)->gen >= 5) {
@@ -610,13 +636,6 @@ static int init_render_ring(struct intel_ring_buffer *ring)
                 */
                I915_WRITE(CACHE_MODE_0,
                           _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
-
-               /* This is not explicitly set for GEN6, so read the register.
-                * see intel_ring_mi_set_context() for why we care.
-                * TODO: consider explicitly setting the bit for GEN5
-                */
-               ring->itlb_before_ctx_switch =
-                       !!(I915_READ(GFX_MODE) & GFX_TLB_INVALIDATE_ALWAYS);
        }
 
        if (INTEL_INFO(dev)->gen >= 6)
@@ -644,20 +663,44 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring)
        ring->scratch.obj = NULL;
 }
 
-static void
-update_mboxes(struct intel_ring_buffer *ring,
-             u32 mmio_offset)
+static int gen6_signal(struct intel_ring_buffer *signaller,
+                      unsigned int num_dwords)
 {
-/* NB: In order to be able to do semaphore MBOX updates for varying number
- * of rings, it's easiest if we round up each individual update to a
- * multiple of 2 (since ring updates must always be a multiple of 2)
- * even though the actual update only requires 3 dwords.
- */
+       struct drm_device *dev = signaller->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *useless;
+       int i, ret;
+
+       /* NB: In order to be able to do semaphore MBOX updates for varying
+        * number of rings, it's easiest if we round up each individual update
+        * to a multiple of 2 (since ring updates must always be a multiple of
+        * 2) even though the actual update only requires 3 dwords.
+        */
 #define MBOX_UPDATE_DWORDS 4
-       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-       intel_ring_emit(ring, mmio_offset);
-       intel_ring_emit(ring, ring->outstanding_lazy_seqno);
-       intel_ring_emit(ring, MI_NOOP);
+       if (i915_semaphore_is_enabled(dev))
+               num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS);
+
+       ret = intel_ring_begin(signaller, num_dwords);
+       if (ret)
+               return ret;
+#undef MBOX_UPDATE_DWORDS
+
+       for_each_ring(useless, dev_priv, i) {
+               u32 mbox_reg = signaller->semaphore.mbox.signal[i];
+               if (mbox_reg != GEN6_NOSYNC) {
+                       intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
+                       intel_ring_emit(signaller, mbox_reg);
+                       intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+                       intel_ring_emit(signaller, MI_NOOP);
+               } else {
+                       intel_ring_emit(signaller, MI_NOOP);
+                       intel_ring_emit(signaller, MI_NOOP);
+                       intel_ring_emit(signaller, MI_NOOP);
+                       intel_ring_emit(signaller, MI_NOOP);
+               }
+       }
+
+       return 0;
 }
 
 /**
@@ -672,27 +715,12 @@ update_mboxes(struct intel_ring_buffer *ring,
 static int
 gen6_add_request(struct intel_ring_buffer *ring)
 {
-       struct drm_device *dev = ring->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *useless;
-       int i, ret, num_dwords = 4;
-
-       if (i915_semaphore_is_enabled(dev))
-               num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS);
-#undef MBOX_UPDATE_DWORDS
+       int ret;
 
-       ret = intel_ring_begin(ring, num_dwords);
+       ret = ring->semaphore.signal(ring, 4);
        if (ret)
                return ret;
 
-       if (i915_semaphore_is_enabled(dev)) {
-               for_each_ring(useless, dev_priv, i) {
-                       u32 mbox_reg = ring->signal_mbox[i];
-                       if (mbox_reg != GEN6_NOSYNC)
-                               update_mboxes(ring, mbox_reg);
-               }
-       }
-
        intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
        intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
        intel_ring_emit(ring, ring->outstanding_lazy_seqno);
@@ -721,10 +749,11 @@ gen6_ring_sync(struct intel_ring_buffer *waiter,
               struct intel_ring_buffer *signaller,
               u32 seqno)
 {
-       int ret;
        u32 dw1 = MI_SEMAPHORE_MBOX |
                  MI_SEMAPHORE_COMPARE |
                  MI_SEMAPHORE_REGISTER;
+       u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id];
+       int ret;
 
        /* Throughout all of the GEM code, seqno passed implies our current
         * seqno is >= the last seqno executed. However for hardware the
@@ -732,8 +761,7 @@ gen6_ring_sync(struct intel_ring_buffer *waiter,
         */
        seqno -= 1;
 
-       WARN_ON(signaller->semaphore_register[waiter->id] ==
-               MI_SEMAPHORE_SYNC_INVALID);
+       WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
 
        ret = intel_ring_begin(waiter, 4);
        if (ret)
@@ -741,9 +769,7 @@ gen6_ring_sync(struct intel_ring_buffer *waiter,
 
        /* If seqno wrap happened, omit the wait with no-ops */
        if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) {
-               intel_ring_emit(waiter,
-                               dw1 |
-                               signaller->semaphore_register[waiter->id]);
+               intel_ring_emit(waiter, dw1 | wait_mbox);
                intel_ring_emit(waiter, seqno);
                intel_ring_emit(waiter, 0);
                intel_ring_emit(waiter, MI_NOOP);
@@ -770,7 +796,7 @@ do {                                                                        \
 static int
 pc_render_add_request(struct intel_ring_buffer *ring)
 {
-       u32 scratch_addr = ring->scratch.gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        /* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently
@@ -792,15 +818,15 @@ pc_render_add_request(struct intel_ring_buffer *ring)
        intel_ring_emit(ring, ring->outstanding_lazy_seqno);
        intel_ring_emit(ring, 0);
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
-       scratch_addr += 128; /* write to separate cachelines */
+       scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
-       scratch_addr += 128;
+       scratch_addr += 2 * CACHELINE_BYTES;
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
-       scratch_addr += 128;
+       scratch_addr += 2 * CACHELINE_BYTES;
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
-       scratch_addr += 128;
+       scratch_addr += 2 * CACHELINE_BYTES;
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
-       scratch_addr += 128;
+       scratch_addr += 2 * CACHELINE_BYTES;
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
 
        intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
@@ -975,6 +1001,11 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
                case BCS:
                        mmio = BLT_HWS_PGA_GEN7;
                        break;
+               /*
+                * VCS2 actually doesn't exist on Gen7. Only shut up
+                * gcc switch check warning
+                */
+               case VCS2:
                case VCS:
                        mmio = BSD_HWS_PGA_GEN7;
                        break;
@@ -1179,7 +1210,7 @@ gen8_ring_put_irq(struct intel_ring_buffer *ring)
 
 static int
 i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
-                        u32 offset, u32 length,
+                        u64 offset, u32 length,
                         unsigned flags)
 {
        int ret;
@@ -1202,7 +1233,7 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
 #define I830_BATCH_LIMIT (256*1024)
 static int
 i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
-                               u32 offset, u32 len,
+                               u64 offset, u32 len,
                                unsigned flags)
 {
        int ret;
@@ -1253,7 +1284,7 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
 
 static int
 i915_dispatch_execbuffer(struct intel_ring_buffer *ring,
-                        u32 offset, u32 len,
+                        u64 offset, u32 len,
                         unsigned flags)
 {
        int ret;
@@ -1285,45 +1316,39 @@ static void cleanup_status_page(struct intel_ring_buffer *ring)
 
 static int init_status_page(struct intel_ring_buffer *ring)
 {
-       struct drm_device *dev = ring->dev;
        struct drm_i915_gem_object *obj;
-       int ret;
 
-       obj = i915_gem_alloc_object(dev, 4096);
-       if (obj == NULL) {
-               DRM_ERROR("Failed to allocate status page\n");
-               ret = -ENOMEM;
-               goto err;
-       }
+       if ((obj = ring->status_page.obj) == NULL) {
+               int ret;
 
-       ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
-       if (ret)
-               goto err_unref;
+               obj = i915_gem_alloc_object(ring->dev, 4096);
+               if (obj == NULL) {
+                       DRM_ERROR("Failed to allocate status page\n");
+                       return -ENOMEM;
+               }
 
-       ret = i915_gem_obj_ggtt_pin(obj, 4096, 0);
-       if (ret)
-               goto err_unref;
+               ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
+               if (ret)
+                       goto err_unref;
+
+               ret = i915_gem_obj_ggtt_pin(obj, 4096, 0);
+               if (ret) {
+err_unref:
+                       drm_gem_object_unreference(&obj->base);
+                       return ret;
+               }
+
+               ring->status_page.obj = obj;
+       }
 
        ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
        ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
-       if (ring->status_page.page_addr == NULL) {
-               ret = -ENOMEM;
-               goto err_unpin;
-       }
-       ring->status_page.obj = obj;
        memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
        DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
                        ring->name, ring->status_page.gfx_addr);
 
        return 0;
-
-err_unpin:
-       i915_gem_object_ggtt_unpin(obj);
-err_unref:
-       drm_gem_object_unreference(&obj->base);
-err:
-       return ret;
 }
 
 static int init_phys_status_page(struct intel_ring_buffer *ring)
@@ -1343,44 +1368,23 @@ static int init_phys_status_page(struct intel_ring_buffer *ring)
        return 0;
 }
 
-static int intel_init_ring_buffer(struct drm_device *dev,
-                                 struct intel_ring_buffer *ring)
+static int allocate_ring_buffer(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       ring->dev = dev;
-       INIT_LIST_HEAD(&ring->active_list);
-       INIT_LIST_HEAD(&ring->request_list);
-       ring->size = 32 * PAGE_SIZE;
-       memset(ring->sync_seqno, 0, sizeof(ring->sync_seqno));
-
-       init_waitqueue_head(&ring->irq_queue);
-
-       if (I915_NEED_GFX_HWS(dev)) {
-               ret = init_status_page(ring);
-               if (ret)
-                       return ret;
-       } else {
-               BUG_ON(ring->id != RCS);
-               ret = init_phys_status_page(ring);
-               if (ret)
-                       return ret;
-       }
+       if (ring->obj)
+               return 0;
 
        obj = NULL;
        if (!HAS_LLC(dev))
                obj = i915_gem_object_create_stolen(dev, ring->size);
        if (obj == NULL)
                obj = i915_gem_alloc_object(dev, ring->size);
-       if (obj == NULL) {
-               DRM_ERROR("Failed to allocate ringbuffer\n");
-               ret = -ENOMEM;
-               goto err_hws;
-       }
-
-       ring->obj = obj;
+       if (obj == NULL)
+               return -ENOMEM;
 
        ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
        if (ret)
@@ -1394,55 +1398,72 @@ static int intel_init_ring_buffer(struct drm_device *dev,
                ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
                           ring->size);
        if (ring->virtual_start == NULL) {
-               DRM_ERROR("Failed to map ringbuffer.\n");
                ret = -EINVAL;
                goto err_unpin;
        }
 
-       ret = ring->init(ring);
-       if (ret)
-               goto err_unmap;
+       ring->obj = obj;
+       return 0;
+
+err_unpin:
+       i915_gem_object_ggtt_unpin(obj);
+err_unref:
+       drm_gem_object_unreference(&obj->base);
+       return ret;
+}
+
+static int intel_init_ring_buffer(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring)
+{
+       int ret;
+
+       ring->dev = dev;
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
+       ring->size = 32 * PAGE_SIZE;
+       memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
+
+       init_waitqueue_head(&ring->irq_queue);
+
+       if (I915_NEED_GFX_HWS(dev)) {
+               ret = init_status_page(ring);
+               if (ret)
+                       return ret;
+       } else {
+               BUG_ON(ring->id != RCS);
+               ret = init_phys_status_page(ring);
+               if (ret)
+                       return ret;
+       }
+
+       ret = allocate_ring_buffer(ring);
+       if (ret) {
+               DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", ring->name, ret);
+               return ret;
+       }
 
        /* Workaround an erratum on the i830 which causes a hang if
         * the TAIL pointer points to within the last 2 cachelines
         * of the buffer.
         */
        ring->effective_size = ring->size;
-       if (IS_I830(ring->dev) || IS_845G(ring->dev))
-               ring->effective_size -= 128;
+       if (IS_I830(dev) || IS_845G(dev))
+               ring->effective_size -= 2 * CACHELINE_BYTES;
 
        i915_cmd_parser_init_ring(ring);
 
-       return 0;
-
-err_unmap:
-       iounmap(ring->virtual_start);
-err_unpin:
-       i915_gem_object_ggtt_unpin(obj);
-err_unref:
-       drm_gem_object_unreference(&obj->base);
-       ring->obj = NULL;
-err_hws:
-       cleanup_status_page(ring);
-       return ret;
+       return ring->init(ring);
 }
 
 void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 {
-       struct drm_i915_private *dev_priv;
-       int ret;
+       struct drm_i915_private *dev_priv = to_i915(ring->dev);
 
        if (ring->obj == NULL)
                return;
 
-       /* Disable the ring buffer. The ring must be idle at this point */
-       dev_priv = ring->dev->dev_private;
-       ret = intel_ring_idle(ring);
-       if (ret && !i915_reset_in_progress(&dev_priv->gpu_error))
-               DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
-                         ring->name, ret);
-
-       I915_WRITE_CTL(ring, 0);
+       intel_stop_ring_buffer(ring);
+       WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
 
        iounmap(ring->virtual_start);
 
@@ -1670,12 +1691,13 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
 /* Align the ring tail to a cacheline boundary */
 int intel_ring_cacheline_align(struct intel_ring_buffer *ring)
 {
-       int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t);
+       int num_dwords = (ring->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
        int ret;
 
        if (num_dwords == 0)
                return 0;
 
+       num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords;
        ret = intel_ring_begin(ring, num_dwords);
        if (ret)
                return ret;
@@ -1775,7 +1797,7 @@ static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring,
 
 static int
 gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
-                             u32 offset, u32 len,
+                             u64 offset, u32 len,
                              unsigned flags)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
@@ -1789,8 +1811,8 @@ gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
 
        /* FIXME(BDW): Address space and security selectors. */
        intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));
-       intel_ring_emit(ring, offset);
-       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, lower_32_bits(offset));
+       intel_ring_emit(ring, upper_32_bits(offset));
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
 
@@ -1799,7 +1821,7 @@ gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
 
 static int
 hsw_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
-                             u32 offset, u32 len,
+                             u64 offset, u32 len,
                              unsigned flags)
 {
        int ret;
@@ -1820,7 +1842,7 @@ hsw_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
 
 static int
 gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
-                             u32 offset, u32 len,
+                             u64 offset, u32 len,
                              unsigned flags)
 {
        int ret;
@@ -1906,15 +1928,24 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
                ring->get_seqno = gen6_ring_get_seqno;
                ring->set_seqno = ring_set_seqno;
-               ring->sync_to = gen6_ring_sync;
-               ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID;
-               ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV;
-               ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB;
-               ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_RVE;
-               ring->signal_mbox[RCS] = GEN6_NOSYNC;
-               ring->signal_mbox[VCS] = GEN6_VRSYNC;
-               ring->signal_mbox[BCS] = GEN6_BRSYNC;
-               ring->signal_mbox[VECS] = GEN6_VERSYNC;
+               ring->semaphore.sync_to = gen6_ring_sync;
+               ring->semaphore.signal = gen6_signal;
+               /*
+                * The current semaphore is only applied on pre-gen8 platform.
+                * And there is no VCS2 ring on the pre-gen8 platform. So the
+                * semaphore between RCS and VCS2 is initialized as INVALID.
+                * Gen8 will initialize the sema between VCS2 and RCS later.
+                */
+               ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_INVALID;
+               ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_RV;
+               ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_RB;
+               ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_RVE;
+               ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
+               ring->semaphore.mbox.signal[RCS] = GEN6_NOSYNC;
+               ring->semaphore.mbox.signal[VCS] = GEN6_VRSYNC;
+               ring->semaphore.mbox.signal[BCS] = GEN6_BRSYNC;
+               ring->semaphore.mbox.signal[VECS] = GEN6_VERSYNC;
+               ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
        } else if (IS_GEN5(dev)) {
                ring->add_request = pc_render_add_request;
                ring->flush = gen4_render_ring_flush;
@@ -2032,7 +2063,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
        ring->size = size;
        ring->effective_size = ring->size;
        if (IS_I830(ring->dev) || IS_845G(ring->dev))
-               ring->effective_size -= 128;
+               ring->effective_size -= 2 * CACHELINE_BYTES;
 
        ring->virtual_start = ioremap_wc(start, size);
        if (ring->virtual_start == NULL) {
@@ -2082,15 +2113,24 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
                        ring->dispatch_execbuffer =
                                gen6_ring_dispatch_execbuffer;
                }
-               ring->sync_to = gen6_ring_sync;
-               ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR;
-               ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID;
-               ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB;
-               ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_VVE;
-               ring->signal_mbox[RCS] = GEN6_RVSYNC;
-               ring->signal_mbox[VCS] = GEN6_NOSYNC;
-               ring->signal_mbox[BCS] = GEN6_BVSYNC;
-               ring->signal_mbox[VECS] = GEN6_VEVSYNC;
+               ring->semaphore.sync_to = gen6_ring_sync;
+               ring->semaphore.signal = gen6_signal;
+               /*
+                * The current semaphore is only applied on pre-gen8 platform.
+                * And there is no VCS2 ring on the pre-gen8 platform. So the
+                * semaphore between VCS and VCS2 is initialized as INVALID.
+                * Gen8 will initialize the sema between VCS2 and VCS later.
+                */
+               ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VR;
+               ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_INVALID;
+               ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VB;
+               ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_VVE;
+               ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
+               ring->semaphore.mbox.signal[RCS] = GEN6_RVSYNC;
+               ring->semaphore.mbox.signal[VCS] = GEN6_NOSYNC;
+               ring->semaphore.mbox.signal[BCS] = GEN6_BVSYNC;
+               ring->semaphore.mbox.signal[VECS] = GEN6_VEVSYNC;
+               ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
        } else {
                ring->mmio_base = BSD_RING_BASE;
                ring->flush = bsd_ring_flush;
@@ -2113,6 +2153,58 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
        return intel_init_ring_buffer(dev, ring);
 }
 
+/**
+ * Initialize the second BSD ring for Broadwell GT3.
+ * It is noted that this only exists on Broadwell GT3.
+ */
+int intel_init_bsd2_ring_buffer(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = &dev_priv->ring[VCS2];
+
+       if ((INTEL_INFO(dev)->gen != 8)) {
+               DRM_ERROR("No dual-BSD ring on non-BDW machine\n");
+               return -EINVAL;
+       }
+
+       ring->name = "bds2_ring";
+       ring->id = VCS2;
+
+       ring->write_tail = ring_write_tail;
+       ring->mmio_base = GEN8_BSD2_RING_BASE;
+       ring->flush = gen6_bsd_ring_flush;
+       ring->add_request = gen6_add_request;
+       ring->get_seqno = gen6_ring_get_seqno;
+       ring->set_seqno = ring_set_seqno;
+       ring->irq_enable_mask =
+                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+       ring->irq_get = gen8_ring_get_irq;
+       ring->irq_put = gen8_ring_put_irq;
+       ring->dispatch_execbuffer =
+                       gen8_ring_dispatch_execbuffer;
+       ring->semaphore.sync_to = gen6_ring_sync;
+       /*
+        * The current semaphore is only applied on the pre-gen8. And there
+        * is no bsd2 ring on the pre-gen8. So now the semaphore_register
+        * between VCS2 and other ring is initialized as invalid.
+        * Gen8 will initialize the sema between VCS2 and other ring later.
+        */
+       ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.signal[RCS] = GEN6_NOSYNC;
+       ring->semaphore.mbox.signal[VCS] = GEN6_NOSYNC;
+       ring->semaphore.mbox.signal[BCS] = GEN6_NOSYNC;
+       ring->semaphore.mbox.signal[VECS] = GEN6_NOSYNC;
+       ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
+
+       ring->init = init_ring_common;
+
+       return intel_init_ring_buffer(dev, ring);
+}
+
 int intel_init_blt_ring_buffer(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2139,15 +2231,24 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
                ring->irq_put = gen6_ring_put_irq;
                ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
        }
-       ring->sync_to = gen6_ring_sync;
-       ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR;
-       ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV;
-       ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID;
-       ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_BVE;
-       ring->signal_mbox[RCS] = GEN6_RBSYNC;
-       ring->signal_mbox[VCS] = GEN6_VBSYNC;
-       ring->signal_mbox[BCS] = GEN6_NOSYNC;
-       ring->signal_mbox[VECS] = GEN6_VEBSYNC;
+       ring->semaphore.sync_to = gen6_ring_sync;
+       ring->semaphore.signal = gen6_signal;
+       /*
+        * The current semaphore is only applied on pre-gen8 platform. And
+        * there is no VCS2 ring on the pre-gen8 platform. So the semaphore
+        * between BCS and VCS2 is initialized as INVALID.
+        * Gen8 will initialize the sema between BCS and VCS2 later.
+        */
+       ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_BR;
+       ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_BV;
+       ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_BVE;
+       ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.signal[RCS] = GEN6_RBSYNC;
+       ring->semaphore.mbox.signal[VCS] = GEN6_VBSYNC;
+       ring->semaphore.mbox.signal[BCS] = GEN6_NOSYNC;
+       ring->semaphore.mbox.signal[VECS] = GEN6_VEBSYNC;
+       ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
        ring->init = init_ring_common;
 
        return intel_init_ring_buffer(dev, ring);
@@ -2180,15 +2281,18 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
                ring->irq_put = hsw_vebox_put_irq;
                ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
        }
-       ring->sync_to = gen6_ring_sync;
-       ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER;
-       ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;
-       ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VEB;
-       ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_INVALID;
-       ring->signal_mbox[RCS] = GEN6_RVESYNC;
-       ring->signal_mbox[VCS] = GEN6_VVESYNC;
-       ring->signal_mbox[BCS] = GEN6_BVESYNC;
-       ring->signal_mbox[VECS] = GEN6_NOSYNC;
+       ring->semaphore.sync_to = gen6_ring_sync;
+       ring->semaphore.signal = gen6_signal;
+       ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VER;
+       ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_VEV;
+       ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VEB;
+       ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore.mbox.signal[RCS] = GEN6_RVESYNC;
+       ring->semaphore.mbox.signal[VCS] = GEN6_VVESYNC;
+       ring->semaphore.mbox.signal[BCS] = GEN6_BVESYNC;
+       ring->semaphore.mbox.signal[VECS] = GEN6_NOSYNC;
+       ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
        ring->init = init_ring_common;
 
        return intel_init_ring_buffer(dev, ring);
@@ -2231,3 +2335,19 @@ intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring)
        ring->gpu_caches_dirty = false;
        return 0;
 }
+
+void
+intel_stop_ring_buffer(struct intel_ring_buffer *ring)
+{
+       int ret;
+
+       if (!intel_ring_initialized(ring))
+               return;
+
+       ret = intel_ring_idle(ring);
+       if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error))
+               DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
+                         ring->name, ret);
+
+       stop_ring(ring);
+}
index 270a6a9734387b6079e9348e17773214a293ad0a..72c3c15f62405b0b3939590558cceef74ec4fbc0 100644 (file)
@@ -34,6 +34,7 @@ struct  intel_hw_status_page {
 #define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
 
 #define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base))
+#define I915_WRITE_MODE(ring, val) I915_WRITE(RING_MI_MODE((ring)->mmio_base), val)
 
 enum intel_ring_hangcheck_action {
        HANGCHECK_IDLE = 0,
@@ -60,8 +61,10 @@ struct  intel_ring_buffer {
                VCS,
                BCS,
                VECS,
+               VCS2
        } id;
-#define I915_NUM_RINGS 4
+#define I915_NUM_RINGS 5
+#define LAST_USER_RING (VECS + 1)
        u32             mmio_base;
        void            __iomem *virtual_start;
        struct          drm_device *dev;
@@ -87,7 +90,6 @@ struct  intel_ring_buffer {
        unsigned irq_refcount; /* protected by dev_priv->irq_lock */
        u32             irq_enable_mask;        /* bitmask to enable ring interrupt */
        u32             trace_irq_seqno;
-       u32             sync_seqno[I915_NUM_RINGS-1];
        bool __must_check (*irq_get)(struct intel_ring_buffer *ring);
        void            (*irq_put)(struct intel_ring_buffer *ring);
 
@@ -110,19 +112,30 @@ struct  intel_ring_buffer {
        void            (*set_seqno)(struct intel_ring_buffer *ring,
                                     u32 seqno);
        int             (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
-                                              u32 offset, u32 length,
+                                              u64 offset, u32 length,
                                               unsigned flags);
 #define I915_DISPATCH_SECURE 0x1
 #define I915_DISPATCH_PINNED 0x2
        void            (*cleanup)(struct intel_ring_buffer *ring);
-       int             (*sync_to)(struct intel_ring_buffer *ring,
+
+       struct {
+               u32     sync_seqno[I915_NUM_RINGS-1];
+
+               struct {
+                       /* our mbox written by others */
+                       u32             wait[I915_NUM_RINGS];
+                       /* mboxes this ring signals to */
+                       u32             signal[I915_NUM_RINGS];
+               } mbox;
+
+               /* AKA wait() */
+               int     (*sync_to)(struct intel_ring_buffer *ring,
                                   struct intel_ring_buffer *to,
                                   u32 seqno);
-
-       /* our mbox written by others */
-       u32             semaphore_register[I915_NUM_RINGS];
-       /* mboxes this ring signals to */
-       u32             signal_mbox[I915_NUM_RINGS];
+               int     (*signal)(struct intel_ring_buffer *signaller,
+                                 /* num_dwords needed by caller */
+                                 unsigned int num_dwords);
+       } semaphore;
 
        /**
         * List of objects currently involved in rendering from the
@@ -152,10 +165,6 @@ struct  intel_ring_buffer {
 
        wait_queue_head_t irq_queue;
 
-       /**
-        * Do an explicit TLB flush before MI_SET_CONTEXT
-        */
-       bool itlb_before_ctx_switch;
        struct i915_hw_context *default_context;
        struct i915_hw_context *last_context;
 
@@ -266,6 +275,7 @@ intel_write_status_page(struct intel_ring_buffer *ring,
 #define I915_GEM_HWS_SCRATCH_INDEX     0x30
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
 
+void intel_stop_ring_buffer(struct intel_ring_buffer *ring);
 void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
 
 int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
@@ -289,6 +299,7 @@ int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring);
 
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
+int intel_init_bsd2_ring_buffer(struct drm_device *dev);
 int intel_init_blt_ring_buffer(struct drm_device *dev);
 int intel_init_vebox_ring_buffer(struct drm_device *dev);
 
index d27155adf5db2b039dee51b9aa0de25e60c8967e..2bf09e8eb5ed439259728b7b5a4f249aa14f0fa6 100644 (file)
@@ -1174,7 +1174,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
+static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
 {
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2424,8 +2424,8 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
        if (ret < 0)
                goto err1;
 
-       ret = sysfs_create_link(&encoder->ddc.dev.kobj,
-                               &drm_connector->kdev->kobj,
+       ret = sysfs_create_link(&drm_connector->kdev->kobj,
+                               &encoder->ddc.dev.kobj,
                                encoder->ddc.dev.kobj.name);
        if (ret < 0)
                goto err2;
@@ -2999,7 +2999,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
 
        intel_encoder->compute_config = intel_sdvo_compute_config;
        intel_encoder->disable = intel_disable_sdvo;
-       intel_encoder->mode_set = intel_sdvo_mode_set;
+       intel_encoder->pre_enable = intel_sdvo_pre_enable;
        intel_encoder->enable = intel_enable_sdvo;
        intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
        intel_encoder->get_config = intel_sdvo_get_config;
index 0954f132726ea0ae15593364ef976168fc2c909f..b1a5514e695a71d95b3a6b76522a1a119a41a4bd 100644 (file)
@@ -182,6 +182,14 @@ u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg)
 
        vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)),
                        DPIO_OPCODE_REG_READ, reg, &val);
+
+       /*
+        * FIXME: There might be some registers where all 1's is a valid value,
+        * so ideally we should check the register offset instead...
+        */
+       WARN(val == 0xffffffff, "DPIO read pipe %c reg 0x%x == 0x%x\n",
+            pipe_name(pipe), reg, val);
+
        return val;
 }
 
index bafe92e317d5d24c103bc83ea93a846cfadf19d0..e0193e8020b853a07cea4fe393416218f1cd6de3 100644 (file)
@@ -934,7 +934,86 @@ intel_tv_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_tv_mode_set(struct intel_encoder *encoder)
+static void
+set_tv_mode_timings(struct drm_i915_private *dev_priv,
+                   const struct tv_mode *tv_mode,
+                   bool burst_ena)
+{
+       u32 hctl1, hctl2, hctl3;
+       u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
+
+       hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
+               (tv_mode->htotal << TV_HTOTAL_SHIFT);
+
+       hctl2 = (tv_mode->hburst_start << 16) |
+               (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
+
+       if (burst_ena)
+               hctl2 |= TV_BURST_ENA;
+
+       hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
+               (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
+
+       vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
+               (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
+               (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
+
+       vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
+               (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
+               (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
+
+       vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
+               (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
+               (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
+
+       if (tv_mode->veq_ena)
+               vctl3 |= TV_EQUAL_ENA;
+
+       vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
+               (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
+
+       vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
+               (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
+
+       vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
+               (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
+
+       vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
+               (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
+
+       I915_WRITE(TV_H_CTL_1, hctl1);
+       I915_WRITE(TV_H_CTL_2, hctl2);
+       I915_WRITE(TV_H_CTL_3, hctl3);
+       I915_WRITE(TV_V_CTL_1, vctl1);
+       I915_WRITE(TV_V_CTL_2, vctl2);
+       I915_WRITE(TV_V_CTL_3, vctl3);
+       I915_WRITE(TV_V_CTL_4, vctl4);
+       I915_WRITE(TV_V_CTL_5, vctl5);
+       I915_WRITE(TV_V_CTL_6, vctl6);
+       I915_WRITE(TV_V_CTL_7, vctl7);
+}
+
+static void set_color_conversion(struct drm_i915_private *dev_priv,
+                                const struct color_conversion *color_conversion)
+{
+       if (!color_conversion)
+               return;
+
+       I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
+                  color_conversion->gy);
+       I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
+                  color_conversion->ay);
+       I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
+                  color_conversion->gu);
+       I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
+                  color_conversion->au);
+       I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
+                  color_conversion->gv);
+       I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
+                  color_conversion->av);
+}
+
+static void intel_tv_pre_enable(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -942,14 +1021,13 @@ static void intel_tv_mode_set(struct intel_encoder *encoder)
        struct intel_tv *intel_tv = enc_to_tv(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
        u32 tv_ctl;
-       u32 hctl1, hctl2, hctl3;
-       u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
        u32 scctl1, scctl2, scctl3;
        int i, j;
        const struct video_levels *video_levels;
        const struct color_conversion *color_conversion;
        bool burst_ena;
-       int pipe = intel_crtc->pipe;
+       int xpos = 0x0, ypos = 0x0;
+       unsigned int xsize, ysize;
 
        if (!tv_mode)
                return; /* can't happen (mode_prepare prevents this) */
@@ -982,44 +1060,6 @@ static void intel_tv_mode_set(struct intel_encoder *encoder)
                burst_ena = tv_mode->burst_ena;
                break;
        }
-       hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
-               (tv_mode->htotal << TV_HTOTAL_SHIFT);
-
-       hctl2 = (tv_mode->hburst_start << 16) |
-               (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
-
-       if (burst_ena)
-               hctl2 |= TV_BURST_ENA;
-
-       hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
-               (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
-
-       vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
-               (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
-               (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
-
-       vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
-               (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
-               (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
-
-       vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
-               (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
-               (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
-
-       if (tv_mode->veq_ena)
-               vctl3 |= TV_EQUAL_ENA;
-
-       vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
-               (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
-
-       vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
-               (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
-
-       vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
-               (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
-
-       vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
-               (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
 
        if (intel_crtc->pipe == 1)
                tv_ctl |= TV_ENC_PIPEB_SELECT;
@@ -1051,37 +1091,16 @@ static void intel_tv_mode_set(struct intel_encoder *encoder)
                tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
 
        /* Enable two fixes for the chips that need them. */
-       if (dev->pdev->device < 0x2772)
+       if (IS_I915GM(dev))
                tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
 
-       I915_WRITE(TV_H_CTL_1, hctl1);
-       I915_WRITE(TV_H_CTL_2, hctl2);
-       I915_WRITE(TV_H_CTL_3, hctl3);
-       I915_WRITE(TV_V_CTL_1, vctl1);
-       I915_WRITE(TV_V_CTL_2, vctl2);
-       I915_WRITE(TV_V_CTL_3, vctl3);
-       I915_WRITE(TV_V_CTL_4, vctl4);
-       I915_WRITE(TV_V_CTL_5, vctl5);
-       I915_WRITE(TV_V_CTL_6, vctl6);
-       I915_WRITE(TV_V_CTL_7, vctl7);
+       set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
+
        I915_WRITE(TV_SC_CTL_1, scctl1);
        I915_WRITE(TV_SC_CTL_2, scctl2);
        I915_WRITE(TV_SC_CTL_3, scctl3);
 
-       if (color_conversion) {
-               I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
-                          color_conversion->gy);
-               I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
-                          color_conversion->ay);
-               I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
-                          color_conversion->gu);
-               I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
-                          color_conversion->au);
-               I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
-                          color_conversion->gv);
-               I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
-                          color_conversion->av);
-       }
+       set_color_conversion(dev_priv, color_conversion);
 
        if (INTEL_INFO(dev)->gen >= 4)
                I915_WRITE(TV_CLR_KNOBS, 0x00404000);
@@ -1092,46 +1111,25 @@ static void intel_tv_mode_set(struct intel_encoder *encoder)
                I915_WRITE(TV_CLR_LEVEL,
                           ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
                            (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
-       {
-               int pipeconf_reg = PIPECONF(pipe);
-               int dspcntr_reg = DSPCNTR(intel_crtc->plane);
-               int pipeconf = I915_READ(pipeconf_reg);
-               int dspcntr = I915_READ(dspcntr_reg);
-               int xpos = 0x0, ypos = 0x0;
-               unsigned int xsize, ysize;
-               /* Pipe must be off here */
-               I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
-               intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-               /* Wait for vblank for the disable to take effect */
-               if (IS_GEN2(dev))
-                       intel_wait_for_vblank(dev, intel_crtc->pipe);
-
-               I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
-               /* Wait for vblank for the disable to take effect. */
-               intel_wait_for_pipe_off(dev, intel_crtc->pipe);
-
-               /* Filter ctl must be set before TV_WIN_SIZE */
-               I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
-               xsize = tv_mode->hblank_start - tv_mode->hblank_end;
-               if (tv_mode->progressive)
-                       ysize = tv_mode->nbr_end + 1;
-               else
-                       ysize = 2*tv_mode->nbr_end + 1;
-
-               xpos += intel_tv->margin[TV_MARGIN_LEFT];
-               ypos += intel_tv->margin[TV_MARGIN_TOP];
-               xsize -= (intel_tv->margin[TV_MARGIN_LEFT] +
-                         intel_tv->margin[TV_MARGIN_RIGHT]);
-               ysize -= (intel_tv->margin[TV_MARGIN_TOP] +
-                         intel_tv->margin[TV_MARGIN_BOTTOM]);
-               I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
-               I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
-
-               I915_WRITE(pipeconf_reg, pipeconf);
-               I915_WRITE(dspcntr_reg, dspcntr);
-               intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-       }
+
+       assert_pipe_disabled(dev_priv, intel_crtc->pipe);
+
+       /* Filter ctl must be set before TV_WIN_SIZE */
+       I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
+       xsize = tv_mode->hblank_start - tv_mode->hblank_end;
+       if (tv_mode->progressive)
+               ysize = tv_mode->nbr_end + 1;
+       else
+               ysize = 2*tv_mode->nbr_end + 1;
+
+       xpos += intel_tv->margin[TV_MARGIN_LEFT];
+       ypos += intel_tv->margin[TV_MARGIN_TOP];
+       xsize -= (intel_tv->margin[TV_MARGIN_LEFT] +
+                 intel_tv->margin[TV_MARGIN_RIGHT]);
+       ysize -= (intel_tv->margin[TV_MARGIN_TOP] +
+                 intel_tv->margin[TV_MARGIN_BOTTOM]);
+       I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
+       I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
 
        j = 0;
        for (i = 0; i < 60; i++)
@@ -1634,7 +1632,7 @@ intel_tv_init(struct drm_device *dev)
 
        intel_encoder->compute_config = intel_tv_compute_config;
        intel_encoder->get_config = intel_tv_get_config;
-       intel_encoder->mode_set = intel_tv_mode_set;
+       intel_encoder->pre_enable = intel_tv_pre_enable;
        intel_encoder->enable = intel_enable_tv;
        intel_encoder->disable = intel_disable_tv;
        intel_encoder->get_hw_state = intel_tv_get_hw_state;
index f729dc71d5beb031599aca72f82c90ec946e2fe0..76dc185793cebe21fd5c050aeb0cf0a4eaada241 100644 (file)
@@ -253,8 +253,7 @@ static void __vlv_force_wake_put(struct drm_i915_private *dev_priv,
 
 }
 
-void vlv_force_wake_get(struct drm_i915_private *dev_priv,
-                                               int fw_engine)
+static void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
 {
        unsigned long irqflags;
 
@@ -273,8 +272,7 @@ void vlv_force_wake_get(struct drm_i915_private *dev_priv,
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-void vlv_force_wake_put(struct drm_i915_private *dev_priv,
-                                               int fw_engine)
+static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
 {
        unsigned long irqflags;
 
@@ -372,7 +370,7 @@ void intel_uncore_early_sanitize(struct drm_device *dev)
        if (HAS_FPGA_DBG_UNCLAIMED(dev))
                __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
 
-       if (IS_HASWELL(dev) &&
+       if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) &&
            (__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) == 1)) {
                /* The docs do not explain exactly how the calculation can be
                 * made. It is somewhat guessable, but for now, it's always
@@ -486,6 +484,17 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
 #define NEEDS_FORCE_WAKE(dev_priv, reg) \
         ((reg) < 0x40000 && (reg) != FORCEWAKE)
 
+#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \
+       (((reg) >= 0x2000 && (reg) < 0x4000) ||\
+       ((reg) >= 0x5000 && (reg) < 0x8000) ||\
+       ((reg) >= 0xB000 && (reg) < 0x12000) ||\
+       ((reg) >= 0x2E000 && (reg) < 0x30000))
+
+#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\
+       (((reg) >= 0x12000 && (reg) < 0x14000) ||\
+       ((reg) >= 0x22000 && (reg) < 0x24000) ||\
+       ((reg) >= 0x30000 && (reg) < 0x40000))
+
 static void
 ilk_dummy_write(struct drm_i915_private *dev_priv)
 {
@@ -852,12 +861,15 @@ void intel_uncore_fini(struct drm_device *dev)
        intel_uncore_forcewake_reset(dev, false);
 }
 
+#define GEN_RANGE(l, h) GENMASK(h, l)
+
 static const struct register_whitelist {
        uint64_t offset;
        uint32_t size;
-       uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
+       /* supported gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
+       uint32_t gen_bitmask;
 } whitelist[] = {
-       { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0x1F0 },
+       { RING_TIMESTAMP(RENDER_RING_BASE), 8, GEN_RANGE(4, 8) },
 };
 
 int i915_reg_read_ioctl(struct drm_device *dev,
index 314685b7f41fc4acb21a2c9c0cad86ecbd1ccad2..3cb58df5237e687299978476b479da827b3decc7 100644 (file)
@@ -1020,7 +1020,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
 
        switch (param->param) {
        case MGA_PARAM_IRQ_NR:
-               value = drm_dev_to_irq(dev);
+               value = dev->pdev->irq;
                break;
        case MGA_PARAM_CARD_TYPE:
                value = dev_priv->chipset;
index 26868e5c55b076352188d34962b928a87a64d1a9..f6b283b8375ec7071adb32459a1bc2f6427dc2ad 100644 (file)
@@ -322,17 +322,13 @@ static void mgag200_bo_unref(struct mgag200_bo **bo)
 
        tbo = &((*bo)->bo);
        ttm_bo_unref(&tbo);
-       if (tbo == NULL)
-               *bo = NULL;
-
+       *bo = NULL;
 }
 
 void mgag200_gem_free_object(struct drm_gem_object *obj)
 {
        struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj);
 
-       if (!mgag200_bo)
-               return;
        mgag200_bo_unref(&mgag200_bo);
 }
 
index 3e6c0f3ed592a6b746610b9b6dd1986e50e1ace7..ef9957dbac943bdda6a1e6fd9bca142ebb202cef 100644 (file)
@@ -510,9 +510,8 @@ static void update_cursor(struct drm_crtc *crtc)
                                        MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN);
                } else {
                        /* disable cursor: */
-                       mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), 0);
-                       mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma),
-                                       MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB));
+                       mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma),
+                                       mdp4_kms->blank_cursor_iova);
                }
 
                /* and drop the iova ref + obj rev when done scanning out: */
@@ -574,11 +573,9 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
 
        if (old_bo) {
                /* drop our previous reference: */
-               msm_gem_put_iova(old_bo, mdp4_kms->id);
-               drm_gem_object_unreference_unlocked(old_bo);
+               drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo);
        }
 
-       crtc_flush(crtc);
        request_pending(crtc, PENDING_CURSOR);
 
        return 0;
index c740ccd1cc67fb4d1a08ef6a65efc671daec8595..8edd531cb62166ad1291be18ffc26ba033cbc71d 100644 (file)
@@ -70,12 +70,12 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
 
        VERB("status=%08x", status);
 
+       mdp_dispatch_irqs(mdp_kms, status);
+
        for (id = 0; id < priv->num_crtcs; id++)
                if (status & mdp4_crtc_vblank(priv->crtcs[id]))
                        drm_handle_vblank(dev, id);
 
-       mdp_dispatch_irqs(mdp_kms, status);
-
        return IRQ_HANDLED;
 }
 
index 272e707c948704e6ff36cc8df263723fdbbd2a71..0bb4faa17523e0862d7f32df0939976424e82d6a 100644 (file)
@@ -144,6 +144,10 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
 static void mdp4_destroy(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       if (mdp4_kms->blank_cursor_iova)
+               msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id);
+       if (mdp4_kms->blank_cursor_bo)
+               drm_gem_object_unreference(mdp4_kms->blank_cursor_bo);
        kfree(mdp4_kms);
 }
 
@@ -372,6 +376,23 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
                goto fail;
        }
 
+       mutex_lock(&dev->struct_mutex);
+       mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC);
+       mutex_unlock(&dev->struct_mutex);
+       if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
+               ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
+               dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
+               mdp4_kms->blank_cursor_bo = NULL;
+               goto fail;
+       }
+
+       ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id,
+                       &mdp4_kms->blank_cursor_iova);
+       if (ret) {
+               dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
+               goto fail;
+       }
+
        return kms;
 
 fail:
index 66a4d31aec80e010e5f5914705f05f7f346dc68c..715520c54cdec48f93750da0843213878aaabf86 100644 (file)
@@ -44,6 +44,10 @@ struct mdp4_kms {
        struct clk *lut_clk;
 
        struct mdp_irq error_handler;
+
+       /* empty/blank cursor bo to use when cursor is "disabled" */
+       struct drm_gem_object *blank_cursor_bo;
+       uint32_t blank_cursor_iova;
 };
 #define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base)
 
index 353d494a497f22c96e0f51d2049cd765ad595f07..f2b985bc2adf41f8330dd4bfb8dcafdb30b43c53 100644 (file)
@@ -71,11 +71,11 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
 
        VERB("status=%08x", status);
 
+       mdp_dispatch_irqs(mdp_kms, status);
+
        for (id = 0; id < priv->num_crtcs; id++)
                if (status & mdp5_crtc_vblank(priv->crtcs[id]))
                        drm_handle_vblank(dev, id);
-
-       mdp_dispatch_irqs(mdp_kms, status);
 }
 
 irqreturn_t mdp5_irq(struct msm_kms *kms)
index f9de156b9e65c992d51f32d9670c315d240797da..50ec1bed5820e80aaf98946e17b82afa0fb21952 100644 (file)
@@ -288,7 +288,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
        }
 
        pm_runtime_get_sync(dev->dev);
-       ret = drm_irq_install(dev);
+       ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
        pm_runtime_put_sync(dev->dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to install IRQ handler\n");
index 6c6d7d4c9b4e77848994222f9bd5bf2b26b6a043..a752ab83b8104124a232d3e6701846c661fabfa3 100644 (file)
@@ -62,11 +62,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
        dma_addr_t paddr;
        int ret, size;
 
-       /* only doing ARGB32 since this is what is needed to alpha-blend
-        * with video overlays:
-        */
        sizes->surface_bpp = 32;
-       sizes->surface_depth = 32;
+       sizes->surface_depth = 24;
 
        DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
                        sizes->surface_height, sizes->surface_bpp,
index 3da8264d3039017bd358ccaca48197356f932f68..bb8026daebc9426759d2bb31f2a6360dfed606a3 100644 (file)
@@ -118,8 +118,10 @@ static void put_pages(struct drm_gem_object *obj)
 
                if (iommu_present(&platform_bus_type))
                        drm_gem_put_pages(obj, msm_obj->pages, true, false);
-               else
+               else {
                        drm_mm_remove_node(msm_obj->vram_node);
+                       drm_free_large(msm_obj->pages);
+               }
 
                msm_obj->pages = NULL;
        }
index fb84da3cb50d50a31f905052b4b85c2cbaf54143..4f4c3fec6916fc4ea568276851f41f5adaadfbd1 100644 (file)
@@ -64,12 +64,13 @@ static bool
 nouveau_switcheroo_can_switch(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
-       bool can_switch;
 
-       spin_lock(&dev->count_lock);
-       can_switch = (dev->open_count == 0);
-       spin_unlock(&dev->count_lock);
-       return can_switch;
+       /*
+        * FIXME: open_count is protected by drm_global_mutex but that would lead to
+        * locking inversion with the driver load path. And the access here is
+        * completely racy anyway. So don't bother with locking for now.
+        */
+       return dev->open_count == 0;
 }
 
 static const struct vga_switcheroo_client_ops
index 1f1f8371a199c172ed2bb4331864a07cef1ef60b..db1601fdbe2946f581b0ec108057f94f647d1d10 100644 (file)
@@ -27,6 +27,7 @@
 #define MCS_ELVSS_ON           0xb1
 #define MCS_USER_SETTING       0xf0
 #define MCS_DISPCTL            0xf2
+#define MCS_POWER_CTRL         0xf4
 #define MCS_GTCON              0xf7
 #define MCS_PANEL_CONDITION    0xf8
 #define MCS_GAMMA_SET1         0xf9
@@ -182,6 +183,8 @@ static void ld9040_init(struct ld9040 *ctx)
        ld9040_dcs_write_seq_static(ctx, MCS_DISPCTL,
                0x02, 0x08, 0x08, 0x10, 0x10);
        ld9040_dcs_write_seq_static(ctx, MCS_MANPWR, 0x04);
+       ld9040_dcs_write_seq_static(ctx, MCS_POWER_CTRL,
+               0x0a, 0x87, 0x25, 0x6a, 0x44, 0x02, 0x88);
        ld9040_dcs_write_seq_static(ctx, MCS_ELVSS_ON, 0x0d, 0x00, 0x16);
        ld9040_dcs_write_seq_static(ctx, MCS_GTCON, 0x09, 0x00, 0x00);
        ld9040_brightness_set(ctx);
index 35941d2412b82882981709a3c44af8d834c71f38..06e57a26db7a5ed09561442aab1dfe840d770775 100644 (file)
@@ -847,6 +847,7 @@ static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx)
        if (i >= ARRAY_SIZE(s6e8aa0_variants)) {
                dev_err(ctx->dev, "unsupported display version %d\n", id[1]);
                ctx->error = -EINVAL;
+               return;
        }
 
        ctx->variant = &s6e8aa0_variants[i];
index 41bdd174657e6ea34c4ad8a703d3288e721d919f..3ab9072d3623538d54d6295326365024288b6eef 100644 (file)
@@ -841,7 +841,7 @@ static const struct drm_connector_funcs qxl_connector_funcs = {
        .save = qxl_conn_save,
        .restore = qxl_conn_restore,
        .detect = qxl_conn_detect,
-       .fill_modes = drm_helper_probe_single_connector_modes,
+       .fill_modes = drm_helper_probe_single_connector_modes_nomerge,
        .set_property = qxl_conn_set_property,
        .destroy = qxl_conn_destroy,
 };
index fee8748bdca52fda145888018b3d4a89c43de866..6e936634d65c8d36593994aa0af4b59df54ebc5c 100644 (file)
@@ -214,7 +214,6 @@ static struct pci_driver qxl_pci_driver = {
 static struct drm_driver qxl_driver = {
        .driver_features = DRIVER_GEM | DRIVER_MODESET |
                           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
-       .dev_priv_size = 0,
        .load = qxl_driver_load,
        .unload = qxl_driver_unload,
 
index 28f84b4fce32fab576d4bd71d324bceaf93c0682..34d6a85e9023655efd5c67bd6b1e67d20b34b1bc 100644 (file)
@@ -87,7 +87,7 @@ int qxl_irq_init(struct qxl_device *qdev)
        atomic_set(&qdev->irq_received_cursor, 0);
        atomic_set(&qdev->irq_received_io_cmd, 0);
        qdev->irq_received_error = 0;
-       ret = drm_irq_install(qdev->ddev);
+       ret = drm_irq_install(qdev->ddev, qdev->ddev->pdev->irq);
        qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
        if (unlikely(ret != 0)) {
                DRM_ERROR("Failed installing irq: %d\n", ret);
index d52c27527b9a638a09307f75a8bd4b91a56c7aef..71a1baeac14edc4ceabb8ab397d0dfe2c23b335b 100644 (file)
@@ -109,13 +109,11 @@ static const struct vm_operations_struct *ttm_vm_ops;
 static int qxl_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct ttm_buffer_object *bo;
-       struct qxl_device *qdev;
        int r;
 
        bo = (struct ttm_buffer_object *)vma->vm_private_data;
        if (bo == NULL)
                return VM_FAULT_NOPAGE;
-       qdev = qxl_get_qdev(bo->bdev);
        r = ttm_vm_ops->fault(vma, vmf);
        return r;
 }
@@ -162,10 +160,6 @@ static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
 static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                             struct ttm_mem_type_manager *man)
 {
-       struct qxl_device *qdev;
-
-       qdev = qxl_get_qdev(bdev);
-
        switch (type) {
        case TTM_PL_SYSTEM:
                /* System memory */
index e806dacd452f7b9cc8c93d20308db93ea0ef0da6..97064dd434c28f0eb31882aa70ed6ead35176f8c 100644 (file)
@@ -1594,7 +1594,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
 
        switch (param->param) {
        case R128_PARAM_IRQ_NR:
-               value = drm_dev_to_irq(dev);
+               value = dev->pdev->irq;
                break;
        default:
                return -EINVAL;
index 511fe26198e4a3e5a779af5e7f82bf62be570da6..9aa1afd1786e3261d59eb7c52e2a5e1c3d5b9bcb 100644 (file)
@@ -1125,12 +1125,13 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
 static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
-       bool can_switch;
 
-       spin_lock(&dev->count_lock);
-       can_switch = (dev->open_count == 0);
-       spin_unlock(&dev->count_lock);
-       return can_switch;
+       /*
+        * FIXME: open_count is protected by drm_global_mutex but that would lead to
+        * locking inversion with the driver load path. And the access here is
+        * completely racy anyway. So don't bother with locking for now.
+        */
+       return dev->open_count == 0;
 }
 
 static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
index c00a2f58518502df5620e02af532f3dd725fa3cf..15447a4119f4285b66b5de1247350646b5adf954 100644 (file)
@@ -519,7 +519,6 @@ static struct drm_driver kms_driver = {
            DRIVER_USE_AGP |
            DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
            DRIVER_PRIME | DRIVER_RENDER,
-       .dev_priv_size = 0,
        .load = radeon_driver_load_kms,
        .open = radeon_driver_open_kms,
        .preclose = radeon_driver_preclose_kms,
index 089c9ffb0aa95e8e47c964f190b07e0e8fe93c32..16807afab362509f8432bf4a021d3954e747c301 100644 (file)
@@ -287,7 +287,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
 
        rdev->irq.installed = true;
-       r = drm_irq_install(rdev->ddev);
+       r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
        if (r) {
                rdev->irq.installed = false;
                flush_work(&rdev->hotplug_work);
index 956ab7f14e1650607c8dd09f1b9c96daaee3169a..b576549fc7837971caeeeb0cdcbba706fcebd73e 100644 (file)
@@ -3054,7 +3054,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
                        value = 0;
                else
-                       value = drm_dev_to_irq(dev);
+                       value = dev->pdev->irq;
                break;
        case RADEON_PARAM_GART_BASE:
                value = dev_priv->gart_vm_start;
index c839c9c89efbf6f4eb4a37cac2fba654435bd1f9..82c84c7fd4f6e1c93d2872414045bed206899c9a 100644 (file)
@@ -185,7 +185,7 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags)
                goto done;
        }
 
-       ret = drm_irq_install(dev);
+       ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to install IRQ handler\n");
                goto done;
index 71cef5c13dc81d0f01cf7c05acae927ef2ab18de..b3a66d65cb535688ed1ff821b63c098ef5f33042 100644 (file)
@@ -12,9 +12,7 @@ static int drm_host1x_set_busid(struct drm_device *dev,
                                struct drm_master *master)
 {
        const char *device = dev_name(dev->dev);
-       const char *driver = dev->driver->name;
        const char *bus = dev->dev->bus->name;
-       int length;
 
        master->unique_len = strlen(bus) + 1 + strlen(device);
        master->unique_size = master->unique_len;
@@ -25,19 +23,10 @@ static int drm_host1x_set_busid(struct drm_device *dev,
 
        snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device);
 
-       length = strlen(driver) + 1 + master->unique_len;
-
-       dev->devname = kmalloc(length + 1, GFP_KERNEL);
-       if (!dev->devname)
-               return -ENOMEM;
-
-       snprintf(dev->devname, length + 1, "%s@%s", driver, master->unique);
-
        return 0;
 }
 
 static struct drm_bus drm_host1x_bus = {
-       .bus_type = DRIVER_BUS_HOST1X,
        .set_busid = drm_host1x_set_busid,
 };
 
index 36c717af6cf90830324a3538ac05dfd4306f3ccb..859e424e15e51939e8cd6979ce49546f7a8a7a36 100644 (file)
@@ -29,6 +29,254 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
        return container_of(plane, struct tegra_plane, base);
 }
 
+static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
+{
+       /* assume no swapping of fetched data */
+       if (swap)
+               *swap = BYTE_SWAP_NOSWAP;
+
+       switch (format) {
+       case DRM_FORMAT_XBGR8888:
+               return WIN_COLOR_DEPTH_R8G8B8A8;
+
+       case DRM_FORMAT_XRGB8888:
+               return WIN_COLOR_DEPTH_B8G8R8A8;
+
+       case DRM_FORMAT_RGB565:
+               return WIN_COLOR_DEPTH_B5G6R5;
+
+       case DRM_FORMAT_UYVY:
+               return WIN_COLOR_DEPTH_YCbCr422;
+
+       case DRM_FORMAT_YUYV:
+               if (swap)
+                       *swap = BYTE_SWAP_SWAP2;
+
+               return WIN_COLOR_DEPTH_YCbCr422;
+
+       case DRM_FORMAT_YUV420:
+               return WIN_COLOR_DEPTH_YCbCr420P;
+
+       case DRM_FORMAT_YUV422:
+               return WIN_COLOR_DEPTH_YCbCr422P;
+
+       default:
+               break;
+       }
+
+       WARN(1, "unsupported pixel format %u, using default\n", format);
+       return WIN_COLOR_DEPTH_B8G8R8A8;
+}
+
+static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
+{
+       switch (format) {
+       case WIN_COLOR_DEPTH_YCbCr422:
+       case WIN_COLOR_DEPTH_YUV422:
+               if (planar)
+                       *planar = false;
+
+               return true;
+
+       case WIN_COLOR_DEPTH_YCbCr420P:
+       case WIN_COLOR_DEPTH_YUV420P:
+       case WIN_COLOR_DEPTH_YCbCr422P:
+       case WIN_COLOR_DEPTH_YUV422P:
+       case WIN_COLOR_DEPTH_YCbCr422R:
+       case WIN_COLOR_DEPTH_YUV422R:
+       case WIN_COLOR_DEPTH_YCbCr422RA:
+       case WIN_COLOR_DEPTH_YUV422RA:
+               if (planar)
+                       *planar = true;
+
+               return true;
+       }
+
+       return false;
+}
+
+static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,
+                                 unsigned int bpp)
+{
+       fixed20_12 outf = dfixed_init(out);
+       fixed20_12 inf = dfixed_init(in);
+       u32 dda_inc;
+       int max;
+
+       if (v)
+               max = 15;
+       else {
+               switch (bpp) {
+               case 2:
+                       max = 8;
+                       break;
+
+               default:
+                       WARN_ON_ONCE(1);
+                       /* fallthrough */
+               case 4:
+                       max = 4;
+                       break;
+               }
+       }
+
+       outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1));
+       inf.full -= dfixed_const(1);
+
+       dda_inc = dfixed_div(inf, outf);
+       dda_inc = min_t(u32, dda_inc, dfixed_const(max));
+
+       return dda_inc;
+}
+
+static inline u32 compute_initial_dda(unsigned int in)
+{
+       fixed20_12 inf = dfixed_init(in);
+       return dfixed_frac(inf);
+}
+
+static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
+                                const struct tegra_dc_window *window)
+{
+       unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
+       unsigned long value;
+       bool yuv, planar;
+
+       /*
+        * For YUV planar modes, the number of bytes per pixel takes into
+        * account only the luma component and therefore is 1.
+        */
+       yuv = tegra_dc_format_is_yuv(window->format, &planar);
+       if (!yuv)
+               bpp = window->bits_per_pixel / 8;
+       else
+               bpp = planar ? 1 : 2;
+
+       value = WINDOW_A_SELECT << index;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+
+       tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH);
+       tegra_dc_writel(dc, window->swap, DC_WIN_BYTE_SWAP);
+
+       value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);
+       tegra_dc_writel(dc, value, DC_WIN_POSITION);
+
+       value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);
+       tegra_dc_writel(dc, value, DC_WIN_SIZE);
+
+       h_offset = window->src.x * bpp;
+       v_offset = window->src.y;
+       h_size = window->src.w * bpp;
+       v_size = window->src.h;
+
+       value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
+       tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE);
+
+       /*
+        * For DDA computations the number of bytes per pixel for YUV planar
+        * modes needs to take into account all Y, U and V components.
+        */
+       if (yuv && planar)
+               bpp = 2;
+
+       h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
+       v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);
+
+       value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);
+       tegra_dc_writel(dc, value, DC_WIN_DDA_INC);
+
+       h_dda = compute_initial_dda(window->src.x);
+       v_dda = compute_initial_dda(window->src.y);
+
+       tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
+       tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+
+       tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
+       tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
+
+       tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR);
+
+       if (yuv && planar) {
+               tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U);
+               tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V);
+               value = window->stride[1] << 16 | window->stride[0];
+               tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE);
+       } else {
+               tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
+       }
+
+       if (window->bottom_up)
+               v_offset += window->src.h - 1;
+
+       tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
+       tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
+
+       if (window->tiled) {
+               value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
+                       DC_WIN_BUFFER_ADDR_MODE_TILE;
+       } else {
+               value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
+                       DC_WIN_BUFFER_ADDR_MODE_LINEAR;
+       }
+
+       tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
+
+       value = WIN_ENABLE;
+
+       if (yuv) {
+               /* setup default colorspace conversion coefficients */
+               tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
+               tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
+               tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
+               tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
+               tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
+               tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
+               tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
+               tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
+
+               value |= CSC_ENABLE;
+       } else if (window->bits_per_pixel < 24) {
+               value |= COLOR_EXPAND;
+       }
+
+       if (window->bottom_up)
+               value |= V_DIRECTION;
+
+       tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+
+       /*
+        * Disable blending and assume Window A is the bottom-most window,
+        * Window C is the top-most window and Window B is in the middle.
+        */
+       tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY);
+       tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN);
+
+       switch (index) {
+       case 0:
+               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X);
+               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
+               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
+               break;
+
+       case 1:
+               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
+               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
+               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
+               break;
+
+       case 2:
+               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
+               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y);
+               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY);
+               break;
+       }
+
+       tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL);
+
+       return 0;
+}
+
 static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                              struct drm_framebuffer *fb, int crtc_x,
                              int crtc_y, unsigned int crtc_w,
@@ -49,7 +297,7 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        window.dst.y = crtc_y;
        window.dst.w = crtc_w;
        window.dst.h = crtc_h;
-       window.format = tegra_dc_format(fb->pixel_format);
+       window.format = tegra_dc_format(fb->pixel_format, &window.swap);
        window.bits_per_pixel = fb->bits_per_pixel;
        window.bottom_up = tegra_fb_is_bottom_up(fb);
        window.tiled = tegra_fb_is_tiled(fb);
@@ -117,6 +365,7 @@ static const uint32_t plane_formats[] = {
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_RGB565,
        DRM_FORMAT_UYVY,
+       DRM_FORMAT_YUYV,
        DRM_FORMAT_YUV420,
        DRM_FORMAT_YUV422,
 };
@@ -150,9 +399,9 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
 static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
                             struct drm_framebuffer *fb)
 {
-       unsigned int format = tegra_dc_format(fb->pixel_format);
        struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
        unsigned int h_offset = 0, v_offset = 0;
+       unsigned int format, swap;
        unsigned long value;
 
        tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -162,7 +411,10 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
 
        tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
        tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
+
+       format = tegra_dc_format(fb->pixel_format, &swap);
        tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
+       tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
 
        if (tegra_fb_is_tiled(fb)) {
                value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
@@ -177,13 +429,13 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        /* make sure bottom-up buffers are properly displayed */
        if (tegra_fb_is_bottom_up(fb)) {
                value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-               value |= INVERT_V;
+               value |= V_DIRECTION;
                tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
 
                v_offset += fb->height - 1;
        } else {
                value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-               value &= ~INVERT_V;
+               value &= ~V_DIRECTION;
                tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
        }
 
@@ -312,7 +564,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
        struct drm_device *drm = crtc->dev;
        struct drm_plane *plane;
 
-       list_for_each_entry(plane, &drm->mode_config.plane_list, head) {
+       drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
                if (plane->crtc == crtc) {
                        tegra_plane_disable(plane);
                        plane->crtc = NULL;
@@ -334,52 +586,11 @@ static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
-static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,
-                                 unsigned int bpp)
-{
-       fixed20_12 outf = dfixed_init(out);
-       fixed20_12 inf = dfixed_init(in);
-       u32 dda_inc;
-       int max;
-
-       if (v)
-               max = 15;
-       else {
-               switch (bpp) {
-               case 2:
-                       max = 8;
-                       break;
-
-               default:
-                       WARN_ON_ONCE(1);
-                       /* fallthrough */
-               case 4:
-                       max = 4;
-                       break;
-               }
-       }
-
-       outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1));
-       inf.full -= dfixed_const(1);
-
-       dda_inc = dfixed_div(inf, outf);
-       dda_inc = min_t(u32, dda_inc, dfixed_const(max));
-
-       return dda_inc;
-}
-
-static inline u32 compute_initial_dda(unsigned int in)
-{
-       fixed20_12 inf = dfixed_init(in);
-       return dfixed_frac(inf);
-}
-
 static int tegra_dc_set_timings(struct tegra_dc *dc,
                                struct drm_display_mode *mode)
 {
-       /* TODO: For HDMI compliance, h & v ref_to_sync should be set to 1 */
-       unsigned int h_ref_to_sync = 0;
-       unsigned int v_ref_to_sync = 0;
+       unsigned int h_ref_to_sync = 1;
+       unsigned int v_ref_to_sync = 1;
        unsigned long value;
 
        tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
@@ -406,13 +617,14 @@ static int tegra_dc_set_timings(struct tegra_dc *dc,
 }
 
 static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
-                               struct drm_display_mode *mode,
-                               unsigned long *div)
+                               struct drm_display_mode *mode)
 {
-       unsigned long pclk = mode->clock * 1000, rate;
+       unsigned long pclk = mode->clock * 1000;
        struct tegra_dc *dc = to_tegra_dc(crtc);
        struct tegra_output *output = NULL;
        struct drm_encoder *encoder;
+       unsigned int div;
+       u32 value;
        long err;
 
        list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head)
@@ -425,221 +637,23 @@ static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
                return -ENODEV;
 
        /*
-        * This assumes that the display controller will divide its parent
-        * clock by 2 to generate the pixel clock.
+        * This assumes that the parent clock is pll_d_out0 or pll_d2_out
+        * respectively, each of which divides the base pll_d by 2.
         */
-       err = tegra_output_setup_clock(output, dc->clk, pclk * 2);
+       err = tegra_output_setup_clock(output, dc->clk, pclk, &div);
        if (err < 0) {
                dev_err(dc->dev, "failed to setup clock: %ld\n", err);
                return err;
        }
 
-       rate = clk_get_rate(dc->clk);
-       *div = (rate * 2 / pclk) - 2;
-
-       DRM_DEBUG_KMS("rate: %lu, div: %lu\n", rate, *div);
-
-       return 0;
-}
-
-static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
-{
-       switch (format) {
-       case WIN_COLOR_DEPTH_YCbCr422:
-       case WIN_COLOR_DEPTH_YUV422:
-               if (planar)
-                       *planar = false;
-
-               return true;
-
-       case WIN_COLOR_DEPTH_YCbCr420P:
-       case WIN_COLOR_DEPTH_YUV420P:
-       case WIN_COLOR_DEPTH_YCbCr422P:
-       case WIN_COLOR_DEPTH_YUV422P:
-       case WIN_COLOR_DEPTH_YCbCr422R:
-       case WIN_COLOR_DEPTH_YUV422R:
-       case WIN_COLOR_DEPTH_YCbCr422RA:
-       case WIN_COLOR_DEPTH_YUV422RA:
-               if (planar)
-                       *planar = true;
-
-               return true;
-       }
-
-       return false;
-}
-
-int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
-                         const struct tegra_dc_window *window)
-{
-       unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
-       unsigned long value;
-       bool yuv, planar;
-
-       /*
-        * For YUV planar modes, the number of bytes per pixel takes into
-        * account only the luma component and therefore is 1.
-        */
-       yuv = tegra_dc_format_is_yuv(window->format, &planar);
-       if (!yuv)
-               bpp = window->bits_per_pixel / 8;
-       else
-               bpp = planar ? 1 : 2;
-
-       value = WINDOW_A_SELECT << index;
-       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
-
-       tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH);
-       tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
-
-       value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);
-       tegra_dc_writel(dc, value, DC_WIN_POSITION);
-
-       value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);
-       tegra_dc_writel(dc, value, DC_WIN_SIZE);
-
-       h_offset = window->src.x * bpp;
-       v_offset = window->src.y;
-       h_size = window->src.w * bpp;
-       v_size = window->src.h;
-
-       value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
-       tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE);
+       DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
 
-       /*
-        * For DDA computations the number of bytes per pixel for YUV planar
-        * modes needs to take into account all Y, U and V components.
-        */
-       if (yuv && planar)
-               bpp = 2;
-
-       h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
-       v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);
-
-       value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);
-       tegra_dc_writel(dc, value, DC_WIN_DDA_INC);
-
-       h_dda = compute_initial_dda(window->src.x);
-       v_dda = compute_initial_dda(window->src.y);
-
-       tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
-       tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
-
-       tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
-       tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
-
-       tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR);
-
-       if (yuv && planar) {
-               tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U);
-               tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V);
-               value = window->stride[1] << 16 | window->stride[0];
-               tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE);
-       } else {
-               tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
-       }
-
-       if (window->bottom_up)
-               v_offset += window->src.h - 1;
-
-       tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
-       tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
-
-       if (window->tiled) {
-               value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
-                       DC_WIN_BUFFER_ADDR_MODE_TILE;
-       } else {
-               value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
-                       DC_WIN_BUFFER_ADDR_MODE_LINEAR;
-       }
-
-       tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
-
-       value = WIN_ENABLE;
-
-       if (yuv) {
-               /* setup default colorspace conversion coefficients */
-               tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
-               tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
-               tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
-               tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
-               tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
-               tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
-               tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
-               tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
-
-               value |= CSC_ENABLE;
-       } else if (window->bits_per_pixel < 24) {
-               value |= COLOR_EXPAND;
-       }
-
-       if (window->bottom_up)
-               value |= INVERT_V;
-
-       tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
-       /*
-        * Disable blending and assume Window A is the bottom-most window,
-        * Window C is the top-most window and Window B is in the middle.
-        */
-       tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY);
-       tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN);
-
-       switch (index) {
-       case 0:
-               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X);
-               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
-               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
-               break;
-
-       case 1:
-               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
-               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
-               tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
-               break;
-
-       case 2:
-               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
-               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y);
-               tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY);
-               break;
-       }
-
-       tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL);
+       value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
 
        return 0;
 }
 
-unsigned int tegra_dc_format(uint32_t format)
-{
-       switch (format) {
-       case DRM_FORMAT_XBGR8888:
-               return WIN_COLOR_DEPTH_R8G8B8A8;
-
-       case DRM_FORMAT_XRGB8888:
-               return WIN_COLOR_DEPTH_B8G8R8A8;
-
-       case DRM_FORMAT_RGB565:
-               return WIN_COLOR_DEPTH_B5G6R5;
-
-       case DRM_FORMAT_UYVY:
-               return WIN_COLOR_DEPTH_YCbCr422;
-
-       case DRM_FORMAT_YUV420:
-               return WIN_COLOR_DEPTH_YCbCr420P;
-
-       case DRM_FORMAT_YUV422:
-               return WIN_COLOR_DEPTH_YCbCr422P;
-
-       default:
-               break;
-       }
-
-       WARN(1, "unsupported pixel format %u, using default\n", format);
-       return WIN_COLOR_DEPTH_B8G8R8A8;
-}
-
 static int tegra_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted,
@@ -648,12 +662,12 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
        struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
        struct tegra_dc *dc = to_tegra_dc(crtc);
        struct tegra_dc_window window;
-       unsigned long div, value;
+       u32 value;
        int err;
 
        drm_vblank_pre_modeset(crtc->dev, dc->pipe);
 
-       err = tegra_crtc_setup_clk(crtc, mode, &div);
+       err = tegra_crtc_setup_clk(crtc, mode);
        if (err) {
                dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err);
                return err;
@@ -669,9 +683,6 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
                tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
        }
 
-       value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
-       tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
-
        /* setup window parameters */
        memset(&window, 0, sizeof(window));
        window.src.x = 0;
@@ -682,7 +693,8 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
        window.dst.y = 0;
        window.dst.w = mode->hdisplay;
        window.dst.h = mode->vdisplay;
-       window.format = tegra_dc_format(crtc->primary->fb->pixel_format);
+       window.format = tegra_dc_format(crtc->primary->fb->pixel_format,
+                                       &window.swap);
        window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
        window.stride[0] = crtc->primary->fb->pitches[0];
        window.base[0] = bo->paddr;
@@ -728,10 +740,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc)
                WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
        tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
 
-       value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-               PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
-       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
        /* initialize timer */
        value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
                WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
index c94101494826c898e83d43fb86c9df12064a65b0..44e31aefe8999f6826350b91fea2b0d365e93766 100644 (file)
 #define DC_WIN_CSC_KVB                         0x618
 
 #define DC_WIN_WIN_OPTIONS                     0x700
-#define INVERT_V     (1 <<  2)
+#define H_DIRECTION  (1 <<  0)
+#define V_DIRECTION  (1 <<  2)
 #define COLOR_EXPAND (1 <<  6)
 #define CSC_ENABLE   (1 << 18)
 #define WIN_ENABLE   (1 << 30)
index 6f5b6e2f552e3798c6dc30e582ee804f9dffbee4..09ee77923d6769bab76c202adc09de7a38508def 100644 (file)
@@ -666,6 +666,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
        { .compatible = "nvidia,tegra114-gr3d", },
        { .compatible = "nvidia,tegra124-dc", },
        { .compatible = "nvidia,tegra124-sor", },
+       { .compatible = "nvidia,tegra124-hdmi", },
        { /* sentinel */ }
 };
 
index 126332c3ecbb6b82c4f18388ae7a809ae7c6a28c..784fd5c77441b7c476ede7c0c7b214bb169407f7 100644 (file)
@@ -80,13 +80,13 @@ host1x_to_drm_client(struct host1x_client *client)
        return container_of(client, struct tegra_drm_client, base);
 }
 
-extern int tegra_drm_register_client(struct tegra_drm *tegra,
-                                    struct tegra_drm_client *client);
-extern int tegra_drm_unregister_client(struct tegra_drm *tegra,
-                                      struct tegra_drm_client *client);
+int tegra_drm_register_client(struct tegra_drm *tegra,
+                             struct tegra_drm_client *client);
+int tegra_drm_unregister_client(struct tegra_drm *tegra,
+                               struct tegra_drm_client *client);
 
-extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
-extern int tegra_drm_exit(struct tegra_drm *tegra);
+int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
+int tegra_drm_exit(struct tegra_drm *tegra);
 
 struct tegra_dc_soc_info;
 struct tegra_output;
@@ -156,6 +156,7 @@ struct tegra_dc_window {
        } dst;
        unsigned int bits_per_pixel;
        unsigned int format;
+       unsigned int swap;
        unsigned int stride[2];
        unsigned long base[3];
        bool bottom_up;
@@ -163,19 +164,15 @@ struct tegra_dc_window {
 };
 
 /* from dc.c */
-extern unsigned int tegra_dc_format(uint32_t format);
-extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
-                                const struct tegra_dc_window *window);
-extern void tegra_dc_enable_vblank(struct tegra_dc *dc);
-extern void tegra_dc_disable_vblank(struct tegra_dc *dc);
-extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc,
-                                     struct drm_file *file);
+void tegra_dc_enable_vblank(struct tegra_dc *dc);
+void tegra_dc_disable_vblank(struct tegra_dc *dc);
+void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
 
 struct tegra_output_ops {
        int (*enable)(struct tegra_output *output);
        int (*disable)(struct tegra_output *output);
        int (*setup_clock)(struct tegra_output *output, struct clk *clk,
-                          unsigned long pclk);
+                          unsigned long pclk, unsigned int *div);
        int (*check_mode)(struct tegra_output *output,
                          struct drm_display_mode *mode,
                          enum drm_mode_status *status);
@@ -233,10 +230,11 @@ static inline int tegra_output_disable(struct tegra_output *output)
 }
 
 static inline int tegra_output_setup_clock(struct tegra_output *output,
-                                          struct clk *clk, unsigned long pclk)
+                                          struct clk *clk, unsigned long pclk,
+                                          unsigned int *div)
 {
        if (output && output->ops && output->ops->setup_clock)
-               return output->ops->setup_clock(output, clk, pclk);
+               return output->ops->setup_clock(output, clk, pclk, div);
 
        return output ? -ENOSYS : -EINVAL;
 }
@@ -256,22 +254,20 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device);
 void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device);
 
 /* from rgb.c */
-extern int tegra_dc_rgb_probe(struct tegra_dc *dc);
-extern int tegra_dc_rgb_remove(struct tegra_dc *dc);
-extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
-extern int tegra_dc_rgb_exit(struct tegra_dc *dc);
+int tegra_dc_rgb_probe(struct tegra_dc *dc);
+int tegra_dc_rgb_remove(struct tegra_dc *dc);
+int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
+int tegra_dc_rgb_exit(struct tegra_dc *dc);
 
 /* from output.c */
-extern int tegra_output_probe(struct tegra_output *output);
-extern int tegra_output_remove(struct tegra_output *output);
-extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
-extern int tegra_output_exit(struct tegra_output *output);
+int tegra_output_probe(struct tegra_output *output);
+int tegra_output_remove(struct tegra_output *output);
+int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
+int tegra_output_exit(struct tegra_output *output);
 
 /* from dpaux.c */
-
 struct tegra_dpaux;
 struct drm_dp_link;
-struct drm_dp_aux;
 
 struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np);
 enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux);
@@ -288,10 +284,10 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
                                    unsigned int index);
 bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
 bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer);
-extern int tegra_drm_fb_init(struct drm_device *drm);
-extern void tegra_drm_fb_exit(struct drm_device *drm);
+int tegra_drm_fb_init(struct drm_device *drm);
+void tegra_drm_fb_exit(struct drm_device *drm);
 #ifdef CONFIG_DRM_TEGRA_FBDEV
-extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
+void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
 #endif
 
 extern struct platform_driver tegra_dc_driver;
index 0e599f0417c06869e5b1f2bdd296914dd10f0d75..3838575f71c64c6e2a7966adc20f284e773401c4 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 
+#include <linux/regulator/consumer.h>
+
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 
@@ -43,11 +45,15 @@ struct tegra_dsi {
        struct drm_minor *minor;
        struct dentry *debugfs;
 
+       unsigned long flags;
        enum mipi_dsi_pixel_format format;
        unsigned int lanes;
 
        struct tegra_mipi_device *mipi;
        struct mipi_dsi_host host;
+
+       struct regulator *vdd;
+       bool enabled;
 };
 
 static inline struct tegra_dsi *
@@ -244,8 +250,10 @@ static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
 #define PKT_LP         (1 << 30)
 #define NUM_PKT_SEQ    12
 
-/* non-burst mode with sync-end */
-static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = {
+/*
+ * non-burst mode with sync pulses
+ */
+static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
        [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
               PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
               PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
@@ -280,6 +288,36 @@ static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = {
               PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
 };
 
+/*
+ * non-burst mode with sync events
+ */
+static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
+       [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+              PKT_LP,
+       [ 1] = 0,
+       [ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+              PKT_LP,
+       [ 3] = 0,
+       [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+              PKT_LP,
+       [ 5] = 0,
+       [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
+              PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
+       [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
+       [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+              PKT_LP,
+       [ 9] = 0,
+       [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
+              PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
+       [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
+};
+
 static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
 {
        struct mipi_dphy_timing timing;
@@ -361,28 +399,70 @@ static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
        return 0;
 }
 
+static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
+                               enum tegra_dsi_format *fmt)
+{
+       switch (format) {
+       case MIPI_DSI_FMT_RGB888:
+               *fmt = TEGRA_DSI_FORMAT_24P;
+               break;
+
+       case MIPI_DSI_FMT_RGB666:
+               *fmt = TEGRA_DSI_FORMAT_18NP;
+               break;
+
+       case MIPI_DSI_FMT_RGB666_PACKED:
+               *fmt = TEGRA_DSI_FORMAT_18P;
+               break;
+
+       case MIPI_DSI_FMT_RGB565:
+               *fmt = TEGRA_DSI_FORMAT_16P;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int tegra_output_dsi_enable(struct tegra_output *output)
 {
        struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
        struct drm_display_mode *mode = &dc->base.mode;
        unsigned int hact, hsw, hbp, hfp, i, mul, div;
        struct tegra_dsi *dsi = to_dsi(output);
-       /* FIXME: don't hardcode this */
-       const u32 *pkt_seq = pkt_seq_vnb_syne;
+       enum tegra_dsi_format format;
        unsigned long value;
+       const u32 *pkt_seq;
        int err;
 
+       if (dsi->enabled)
+               return 0;
+
+       if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+               DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
+               pkt_seq = pkt_seq_video_non_burst_sync_pulses;
+       } else {
+               DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
+               pkt_seq = pkt_seq_video_non_burst_sync_events;
+       }
+
        err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
        if (err < 0)
                return err;
 
+       err = tegra_dsi_get_format(dsi->format, &format);
+       if (err < 0)
+               return err;
+
        err = clk_enable(dsi->clk);
        if (err < 0)
                return err;
 
        reset_control_deassert(dsi->rst);
 
-       value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(dsi->format) |
+       value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
                DSI_CONTROL_LANES(dsi->lanes - 1) |
                DSI_CONTROL_SOURCE(dc->pipe);
        tegra_dsi_writel(dsi, value, DSI_CONTROL);
@@ -454,6 +534,8 @@ static int tegra_output_dsi_enable(struct tegra_output *output)
        value |= DSI_POWER_CONTROL_ENABLE;
        tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
 
+       dsi->enabled = true;
+
        return 0;
 }
 
@@ -463,9 +545,12 @@ static int tegra_output_dsi_disable(struct tegra_output *output)
        struct tegra_dsi *dsi = to_dsi(output);
        unsigned long value;
 
+       if (!dsi->enabled)
+               return 0;
+
        /* disable DSI controller */
        value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
-       value &= DSI_POWER_CONTROL_ENABLE;
+       value &= ~DSI_POWER_CONTROL_ENABLE;
        tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
 
        /*
@@ -492,30 +577,44 @@ static int tegra_output_dsi_disable(struct tegra_output *output)
 
        clk_disable(dsi->clk);
 
+       dsi->enabled = false;
+
        return 0;
 }
 
 static int tegra_output_dsi_setup_clock(struct tegra_output *output,
-                                       struct clk *clk, unsigned long pclk)
+                                       struct clk *clk, unsigned long pclk,
+                                       unsigned int *divp)
 {
        struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
        struct drm_display_mode *mode = &dc->base.mode;
        unsigned int timeout, mul, div, vrefresh;
        struct tegra_dsi *dsi = to_dsi(output);
        unsigned long bclk, plld, value;
-       struct clk *base;
        int err;
 
        err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
        if (err < 0)
                return err;
 
+       DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, dsi->lanes);
        vrefresh = drm_mode_vrefresh(mode);
+       DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh);
 
-       pclk = mode->htotal * mode->vtotal * vrefresh;
+       /* compute byte clock */
        bclk = (pclk * mul) / (div * dsi->lanes);
-       plld = DIV_ROUND_UP(bclk * 8, 1000000);
-       pclk = (plld * 1000000) / 2;
+
+       /*
+        * Compute bit clock and round up to the next MHz.
+        */
+       plld = DIV_ROUND_UP(bclk * 8, 1000000) * 1000000;
+
+       /*
+        * We divide the frequency by two here, but we make up for that by
+        * setting the shift clock divider (further below) to half of the
+        * correct value.
+        */
+       plld /= 2;
 
        err = clk_set_parent(clk, dsi->clk_parent);
        if (err < 0) {
@@ -523,19 +622,25 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output,
                return err;
        }
 
-       base = clk_get_parent(dsi->clk_parent);
-
-       /*
-        * This assumes that the parent clock is pll_d_out0 or pll_d2_out
-        * respectively, each of which divides the base pll_d by 2.
-        */
-       err = clk_set_rate(base, pclk * 2);
+       err = clk_set_rate(dsi->clk_parent, plld);
        if (err < 0) {
                dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n",
-                       pclk * 2);
+                       plld);
                return err;
        }
 
+       /*
+        * Derive pixel clock from bit clock using the shift clock divider.
+        * Note that this is only half of what we would expect, but we need
+        * that to make up for the fact that we divided the bit clock by a
+        * factor of two above.
+        *
+        * It's not clear exactly why this is necessary, but the display is
+        * not working properly otherwise. Perhaps the PLLs cannot generate
+        * frequencies sufficiently high.
+        */
+       *divp = ((8 * mul) / (div * dsi->lanes)) - 2;
+
        /*
         * XXX: Move the below somewhere else so that we don't need to have
         * access to the vrefresh in this function?
@@ -612,7 +717,6 @@ static int tegra_dsi_init(struct host1x_client *client)
 {
        struct tegra_drm *tegra = dev_get_drvdata(client->parent);
        struct tegra_dsi *dsi = host1x_client_to_dsi(client);
-       unsigned long value, i;
        int err;
 
        dsi->output.type = TEGRA_OUTPUT_DSI;
@@ -631,40 +735,12 @@ static int tegra_dsi_init(struct host1x_client *client)
                        dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
        }
 
-       /*
-        * enable high-speed mode, checksum generation, ECC generation and
-        * disable raw mode
-        */
-       value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
-       value |= DSI_HOST_CONTROL_ECC | DSI_HOST_CONTROL_CS |
-                DSI_HOST_CONTROL_HS;
-       value &= ~DSI_HOST_CONTROL_RAW;
-       tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
-
-       tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY);
-       tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD);
-
-       tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
-
-       for (i = 0; i < 8; i++) {
-               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i);
-               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i);
-       }
-
-       for (i = 0; i < 12; i++)
-               tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i);
-
-       tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS);
-
        err = tegra_dsi_pad_calibrate(dsi);
        if (err < 0) {
                dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
                return err;
        }
 
-       tegra_dsi_writel(dsi, DSI_POWER_CONTROL_ENABLE, DSI_POWER_CONTROL);
-       usleep_range(300, 1000);
-
        return 0;
 }
 
@@ -715,66 +791,13 @@ static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
        return 0;
 }
 
-static void tegra_dsi_initialize(struct tegra_dsi *dsi)
-{
-       unsigned int i;
-
-       tegra_dsi_writel(dsi, 0, DSI_POWER_CONTROL);
-
-       tegra_dsi_writel(dsi, 0, DSI_INT_ENABLE);
-       tegra_dsi_writel(dsi, 0, DSI_INT_STATUS);
-       tegra_dsi_writel(dsi, 0, DSI_INT_MASK);
-
-       tegra_dsi_writel(dsi, 0, DSI_HOST_CONTROL);
-       tegra_dsi_writel(dsi, 0, DSI_CONTROL);
-
-       tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY);
-       tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD);
-
-       tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
-
-       for (i = 0; i < 8; i++) {
-               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i);
-               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i);
-       }
-
-       for (i = 0; i < 12; i++)
-               tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i);
-
-       tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS);
-
-       for (i = 0; i < 4; i++)
-               tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1 + i);
-
-       tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_0);
-       tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_1);
-       tegra_dsi_writel(dsi, 0x000000ff, DSI_PHY_TIMING_2);
-       tegra_dsi_writel(dsi, 0x00000000, DSI_BTA_TIMING);
-
-       tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_0);
-       tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_1);
-       tegra_dsi_writel(dsi, 0, DSI_TO_TALLY);
-
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_CD);
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CD_STATUS);
-       tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL);
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
-       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
-
-       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
-       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
-       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
-}
-
 static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
                                 struct mipi_dsi_device *device)
 {
        struct tegra_dsi *dsi = host_to_tegra(host);
        struct tegra_output *output = &dsi->output;
 
+       dsi->flags = device->mode_flags;
        dsi->format = device->format;
        dsi->lanes = device->lanes;
 
@@ -829,6 +852,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
         * attaches to the DSI host, the parameters will be taken from
         * the attached device.
         */
+       dsi->flags = MIPI_DSI_MODE_VIDEO;
        dsi->format = MIPI_DSI_FMT_RGB888;
        dsi->lanes = 4;
 
@@ -872,6 +896,18 @@ static int tegra_dsi_probe(struct platform_device *pdev)
                return err;
        }
 
+       dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
+       if (IS_ERR(dsi->vdd)) {
+               dev_err(&pdev->dev, "cannot get VDD supply\n");
+               return PTR_ERR(dsi->vdd);
+       }
+
+       err = regulator_enable(dsi->vdd);
+       if (err < 0) {
+               dev_err(&pdev->dev, "cannot enable VDD supply\n");
+               return err;
+       }
+
        err = tegra_dsi_setup_clocks(dsi);
        if (err < 0) {
                dev_err(&pdev->dev, "cannot setup clocks\n");
@@ -883,8 +919,6 @@ static int tegra_dsi_probe(struct platform_device *pdev)
        if (IS_ERR(dsi->regs))
                return PTR_ERR(dsi->regs);
 
-       tegra_dsi_initialize(dsi);
-
        dsi->mipi = tegra_mipi_request(&pdev->dev);
        if (IS_ERR(dsi->mipi))
                return PTR_ERR(dsi->mipi);
@@ -929,9 +963,11 @@ static int tegra_dsi_remove(struct platform_device *pdev)
        mipi_dsi_host_unregister(&dsi->host);
        tegra_mipi_free(dsi->mipi);
 
+       regulator_disable(dsi->vdd);
        clk_disable_unprepare(dsi->clk_parent);
        clk_disable_unprepare(dsi->clk_lp);
        clk_disable_unprepare(dsi->clk);
+       reset_control_assert(dsi->rst);
 
        err = tegra_output_remove(&dsi->output);
        if (err < 0) {
index 1db5cc24ea914c253864be6a0f2e72697c08c23c..5ce610d08d770afa2b9a26087a8c2055ec772edc 100644 (file)
 #define DSI_INIT_SEQ_DATA_14           0x5e
 #define DSI_INIT_SEQ_DATA_15           0x5f
 
+/*
+ * pixel format as used in the DSI_CONTROL_FORMAT field
+ */
+enum tegra_dsi_format {
+       TEGRA_DSI_FORMAT_16P,
+       TEGRA_DSI_FORMAT_18NP,
+       TEGRA_DSI_FORMAT_18P,
+       TEGRA_DSI_FORMAT_24P,
+};
+
 #endif
index 6928015d11a49e9fd6e499aed2ed5f02d6d1730e..fec1a63d32c92afc4f47643781677094aeded4fa 100644 (file)
@@ -42,8 +42,9 @@ struct tegra_hdmi {
        struct device *dev;
        bool enabled;
 
-       struct regulator *vdd;
+       struct regulator *hdmi;
        struct regulator *pll;
+       struct regulator *vdd;
 
        void __iomem *regs;
        unsigned int irq;
@@ -317,6 +318,85 @@ static const struct tmds_config tegra114_tmds_config[] = {
        },
 };
 
+static const struct tmds_config tegra124_tmds_config[] = {
+       { /* 480p/576p / 25.2MHz/27MHz modes */
+               .pclk = 27000000,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(0) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_LOADADJ(3) | SOR_PLL_TMDS_TERMADJ(0),
+               .pe_current = PE_CURRENT0(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_0_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_10_400_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA),
+       }, { /* 720p / 74.25MHz modes */
+               .pclk = 74250000,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(1) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_PE_EN | SOR_PLL_LOADADJ(3) |
+                       SOR_PLL_TMDS_TERMADJ(0),
+               .pe_current = PE_CURRENT0(PE_CURRENT_15_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_15_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_15_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_15_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_10_400_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA),
+       }, { /* 1080p / 148.5MHz modes */
+               .pclk = 148500000,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(3) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_PE_EN | SOR_PLL_LOADADJ(3) |
+                       SOR_PLL_TMDS_TERMADJ(0),
+               .pe_current = PE_CURRENT0(PE_CURRENT_10_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_10_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_10_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_10_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_12_400_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_12_400_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_12_400_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_12_400_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA),
+       }, { /* 225/297MHz modes */
+               .pclk = UINT_MAX,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(0xf) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_LOADADJ(3) | SOR_PLL_TMDS_TERMADJ(7)
+                       | SOR_PLL_TMDS_TERM_ENABLE,
+               .pe_current = PE_CURRENT0(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_0_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_25_200_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_25_200_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_25_200_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_19_200_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_3_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_3_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_3_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_800_mA),
+       },
+};
+
 static const struct tegra_hdmi_audio_config *
 tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk)
 {
@@ -716,13 +796,9 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
                return err;
        }
 
-       /*
-        * This assumes that the display controller will divide its parent
-        * clock by 2 to generate the pixel clock.
-        */
-       err = tegra_output_setup_clock(output, hdmi->clk, pclk * 2);
+       err = regulator_enable(hdmi->vdd);
        if (err < 0) {
-               dev_err(hdmi->dev, "failed to setup clock: %d\n", err);
+               dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err);
                return err;
        }
 
@@ -730,7 +806,7 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        if (err < 0)
                return err;
 
-       err = clk_enable(hdmi->clk);
+       err = clk_prepare_enable(hdmi->clk);
        if (err < 0) {
                dev_err(hdmi->dev, "failed to enable clock: %d\n", err);
                return err;
@@ -740,6 +816,17 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        usleep_range(1000, 2000);
        reset_control_deassert(hdmi->rst);
 
+       /* power up sequence */
+       value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0);
+       value &= ~SOR_PLL_PDBG;
+       tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_PLL0);
+
+       usleep_range(10, 20);
+
+       value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0);
+       value &= ~SOR_PLL_PWR;
+       tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_PLL0);
+
        tegra_dc_writel(dc, VSYNC_H_POSITION(1),
                        DC_DISP_DISP_TIMING_OPTIONS);
        tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888,
@@ -838,9 +925,13 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(0));
        tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(8));
 
-       value = 0x1c800;
+       value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_CSTM);
        value &= ~SOR_CSTM_ROTCLK(~0);
        value |= SOR_CSTM_ROTCLK(2);
+       value |= SOR_CSTM_PLLDIV;
+       value &= ~SOR_CSTM_LVDS_ENABLE;
+       value &= ~SOR_CSTM_MODE_MASK;
+       value |= SOR_CSTM_MODE_TMDS;
        tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_CSTM);
 
        /* start SOR */
@@ -930,10 +1021,18 @@ static int tegra_output_hdmi_disable(struct tegra_output *output)
         * sure it's only executed when the output is attached to one.
         */
        if (dc) {
+               /*
+                * XXX: We can't do this here because it causes HDMI to go
+                * into an erroneous state with the result that HDMI won't
+                * properly work once disabled. See also a similar symptom
+                * for the SOR output.
+                */
+               /*
                value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
                value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
                           PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
                tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+               */
 
                value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
                value &= ~DISP_CTRL_MODE_MASK;
@@ -947,8 +1046,9 @@ static int tegra_output_hdmi_disable(struct tegra_output *output)
                tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
        }
 
+       clk_disable_unprepare(hdmi->clk);
        reset_control_assert(hdmi->rst);
-       clk_disable(hdmi->clk);
+       regulator_disable(hdmi->vdd);
        regulator_disable(hdmi->pll);
 
        hdmi->enabled = false;
@@ -957,10 +1057,10 @@ static int tegra_output_hdmi_disable(struct tegra_output *output)
 }
 
 static int tegra_output_hdmi_setup_clock(struct tegra_output *output,
-                                        struct clk *clk, unsigned long pclk)
+                                        struct clk *clk, unsigned long pclk,
+                                        unsigned int *div)
 {
        struct tegra_hdmi *hdmi = to_hdmi(output);
-       struct clk *base;
        int err;
 
        err = clk_set_parent(clk, hdmi->clk_parent);
@@ -969,17 +1069,12 @@ static int tegra_output_hdmi_setup_clock(struct tegra_output *output,
                return err;
        }
 
-       base = clk_get_parent(hdmi->clk_parent);
-
-       /*
-        * This assumes that the parent clock is pll_d_out0 or pll_d2_out
-        * respectively, each of which divides the base pll_d by 2.
-        */
-       err = clk_set_rate(base, pclk * 2);
+       err = clk_set_rate(hdmi->clk_parent, pclk);
        if (err < 0)
-               dev_err(output->dev,
-                       "failed to set base clock rate to %lu Hz\n",
-                       pclk * 2);
+               dev_err(output->dev, "failed to set clock rate to %lu Hz\n",
+                       pclk);
+
+       *div = 0;
 
        return 0;
 }
@@ -1017,7 +1112,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
        struct tegra_hdmi *hdmi = node->info_ent->data;
        int err;
 
-       err = clk_enable(hdmi->clk);
+       err = clk_prepare_enable(hdmi->clk);
        if (err)
                return err;
 
@@ -1186,7 +1281,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
 
 #undef DUMP_REG
 
-       clk_disable(hdmi->clk);
+       clk_disable_unprepare(hdmi->clk);
 
        return 0;
 }
@@ -1256,13 +1351,6 @@ static int tegra_hdmi_init(struct host1x_client *client)
        struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
        int err;
 
-       err = regulator_enable(hdmi->vdd);
-       if (err < 0) {
-               dev_err(client->dev, "failed to enable VDD regulator: %d\n",
-                       err);
-               return err;
-       }
-
        hdmi->output.type = TEGRA_OUTPUT_HDMI;
        hdmi->output.dev = client->dev;
        hdmi->output.ops = &hdmi_ops;
@@ -1279,6 +1367,13 @@ static int tegra_hdmi_init(struct host1x_client *client)
                        dev_err(client->dev, "debugfs setup failed: %d\n", err);
        }
 
+       err = regulator_enable(hdmi->hdmi);
+       if (err < 0) {
+               dev_err(client->dev, "failed to enable HDMI regulator: %d\n",
+                       err);
+               return err;
+       }
+
        return 0;
 }
 
@@ -1287,6 +1382,8 @@ static int tegra_hdmi_exit(struct host1x_client *client)
        struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
        int err;
 
+       regulator_disable(hdmi->hdmi);
+
        if (IS_ENABLED(CONFIG_DEBUG_FS)) {
                err = tegra_hdmi_debugfs_exit(hdmi);
                if (err < 0)
@@ -1306,8 +1403,6 @@ static int tegra_hdmi_exit(struct host1x_client *client)
                return err;
        }
 
-       regulator_disable(hdmi->vdd);
-
        return 0;
 }
 
@@ -1340,7 +1435,16 @@ static const struct tegra_hdmi_config tegra114_hdmi_config = {
        .has_sor_io_peak_current = true,
 };
 
+static const struct tegra_hdmi_config tegra124_hdmi_config = {
+       .tmds = tegra124_tmds_config,
+       .num_tmds = ARRAY_SIZE(tegra124_tmds_config),
+       .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0,
+       .fuse_override_value = 1 << 31,
+       .has_sor_io_peak_current = true,
+};
+
 static const struct of_device_id tegra_hdmi_of_match[] = {
+       { .compatible = "nvidia,tegra124-hdmi", .data = &tegra124_hdmi_config },
        { .compatible = "nvidia,tegra114-hdmi", .data = &tegra114_hdmi_config },
        { .compatible = "nvidia,tegra30-hdmi", .data = &tegra30_hdmi_config },
        { .compatible = "nvidia,tegra20-hdmi", .data = &tegra20_hdmi_config },
@@ -1381,28 +1485,20 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
                return PTR_ERR(hdmi->rst);
        }
 
-       err = clk_prepare(hdmi->clk);
-       if (err < 0)
-               return err;
-
        hdmi->clk_parent = devm_clk_get(&pdev->dev, "parent");
        if (IS_ERR(hdmi->clk_parent))
                return PTR_ERR(hdmi->clk_parent);
 
-       err = clk_prepare(hdmi->clk_parent);
-       if (err < 0)
-               return err;
-
        err = clk_set_parent(hdmi->clk, hdmi->clk_parent);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to setup clocks: %d\n", err);
                return err;
        }
 
-       hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd");
-       if (IS_ERR(hdmi->vdd)) {
-               dev_err(&pdev->dev, "failed to get VDD regulator\n");
-               return PTR_ERR(hdmi->vdd);
+       hdmi->hdmi = devm_regulator_get(&pdev->dev, "hdmi");
+       if (IS_ERR(hdmi->hdmi)) {
+               dev_err(&pdev->dev, "failed to get HDMI regulator\n");
+               return PTR_ERR(hdmi->hdmi);
        }
 
        hdmi->pll = devm_regulator_get(&pdev->dev, "pll");
@@ -1411,6 +1507,12 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
                return PTR_ERR(hdmi->pll);
        }
 
+       hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd");
+       if (IS_ERR(hdmi->vdd)) {
+               dev_err(&pdev->dev, "failed to get VDD regulator\n");
+               return PTR_ERR(hdmi->vdd);
+       }
+
        hdmi->output.dev = &pdev->dev;
 
        err = tegra_output_probe(&hdmi->output);
@@ -1462,8 +1564,8 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
                return err;
        }
 
-       clk_unprepare(hdmi->clk_parent);
-       clk_unprepare(hdmi->clk);
+       clk_disable_unprepare(hdmi->clk_parent);
+       clk_disable_unprepare(hdmi->clk);
 
        return 0;
 }
index 0aebc485f7fa36be983a609f693bfbb06dcb0214..919a19df4e1b59257b3969887fc288c11e43e1d1 100644 (file)
 
 #define HDMI_NV_PDISP_SOR_CSTM                                 0x5a
 #define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24)
+#define SOR_CSTM_PLLDIV (1 << 21)
+#define SOR_CSTM_LVDS_ENABLE (1 << 16)
+#define SOR_CSTM_MODE_LVDS (0 << 12)
+#define SOR_CSTM_MODE_TMDS (1 << 12)
+#define SOR_CSTM_MODE_MASK (3 << 12)
 
 #define HDMI_NV_PDISP_SOR_LVDS                                 0x5b
 #define HDMI_NV_PDISP_SOR_CRCA                                 0x5c
index 0266fb40479eae05f5176e9835d7c2a1ede75519..d6af9be48f42ff1a536bf0c24dc4616839f95f1e 100644 (file)
@@ -159,11 +159,38 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
 }
 
 static int tegra_output_rgb_setup_clock(struct tegra_output *output,
-                                       struct clk *clk, unsigned long pclk)
+                                       struct clk *clk, unsigned long pclk,
+                                       unsigned int *div)
 {
        struct tegra_rgb *rgb = to_rgb(output);
+       int err;
+
+       err = clk_set_parent(clk, rgb->clk_parent);
+       if (err < 0) {
+               dev_err(output->dev, "failed to set parent: %d\n", err);
+               return err;
+       }
 
-       return clk_set_parent(clk, rgb->clk_parent);
+       /*
+        * We may not want to change the frequency of the parent clock, since
+        * it may be a parent for other peripherals. This is due to the fact
+        * that on Tegra20 there's only a single clock dedicated to display
+        * (pll_d_out0), whereas later generations have a second one that can
+        * be used to independently drive a second output (pll_d2_out0).
+        *
+        * As a way to support multiple outputs on Tegra20 as well, pll_p is
+        * typically used as the parent clock for the display controllers.
+        * But this comes at a cost: pll_p is the parent of several other
+        * peripherals, so its frequency shouldn't change out of the blue.
+        *
+        * The best we can do at this point is to use the shift clock divider
+        * and hope that the desired frequency can be matched (or at least
+        * matched sufficiently close that the panel will still work).
+        */
+
+       *div = ((clk_get_rate(clk) * 2) / pclk) - 2;
+
+       return 0;
 }
 
 static int tegra_output_rgb_check_mode(struct tegra_output *output,
index 49ef5729f435daa411c508070a36c3e50a3e7c1a..7d66f6e5391990a650b7ebb7e6056dec256a879c 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
@@ -33,7 +34,10 @@ struct tegra_sor {
 
        struct tegra_dpaux *dpaux;
 
+       struct mutex lock;
        bool enabled;
+
+       struct dentry *debugfs;
 };
 
 static inline struct tegra_sor *
@@ -296,14 +300,16 @@ static int tegra_output_sor_enable(struct tegra_output *output)
        unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
        struct tegra_sor *sor = to_sor(output);
        unsigned long value;
-       int err;
+       int err = 0;
+
+       mutex_lock(&sor->lock);
 
        if (sor->enabled)
-               return 0;
+               goto unlock;
 
        err = clk_prepare_enable(sor->clk);
        if (err < 0)
-               return err;
+               goto unlock;
 
        reset_control_deassert(sor->rst);
 
@@ -385,7 +391,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
        err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS);
        if (err < 0) {
                dev_err(sor->dev, "failed to power on I/O rail: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        usleep_range(5, 100);
@@ -509,21 +515,21 @@ static int tegra_output_sor_enable(struct tegra_output *output)
                if (err < 0) {
                        dev_err(sor->dev, "failed to probe eDP link: %d\n",
                                err);
-                       return err;
+                       goto unlock;
                }
 
                err = drm_dp_link_power_up(aux, &link);
                if (err < 0) {
                        dev_err(sor->dev, "failed to power up eDP link: %d\n",
                                err);
-                       return err;
+                       goto unlock;
                }
 
                err = drm_dp_link_configure(aux, &link);
                if (err < 0) {
                        dev_err(sor->dev, "failed to configure eDP link: %d\n",
                                err);
-                       return err;
+                       goto unlock;
                }
 
                rate = drm_dp_link_rate_to_bw_code(link.rate);
@@ -558,7 +564,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
                if (err < 0) {
                        dev_err(sor->dev, "DP fast link training failed: %d\n",
                                err);
-                       return err;
+                       goto unlock;
                }
 
                dev_dbg(sor->dev, "fast link training succeeded\n");
@@ -567,7 +573,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
        err = tegra_sor_power_up(sor, 250);
        if (err < 0) {
                dev_err(sor->dev, "failed to power up SOR: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        /* start display controller in continuous mode */
@@ -632,7 +638,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
        err = tegra_sor_setup_pwm(sor, 250);
        if (err < 0) {
                dev_err(sor->dev, "failed to setup PWM: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
@@ -644,18 +650,20 @@ static int tegra_output_sor_enable(struct tegra_output *output)
        err = tegra_sor_attach(sor);
        if (err < 0) {
                dev_err(sor->dev, "failed to attach SOR: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        err = tegra_sor_wakeup(sor);
        if (err < 0) {
                dev_err(sor->dev, "failed to enable DC: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        sor->enabled = true;
 
-       return 0;
+unlock:
+       mutex_unlock(&sor->lock);
+       return err;
 }
 
 static int tegra_sor_detach(struct tegra_sor *sor)
@@ -783,15 +791,17 @@ static int tegra_output_sor_disable(struct tegra_output *output)
        struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
        struct tegra_sor *sor = to_sor(output);
        unsigned long value;
-       int err;
+       int err = 0;
+
+       mutex_lock(&sor->lock);
 
        if (!sor->enabled)
-               return 0;
+               goto unlock;
 
        err = tegra_sor_detach(sor);
        if (err < 0) {
                dev_err(sor->dev, "failed to detach SOR: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        tegra_sor_writel(sor, 0, SOR_STATE_1);
@@ -832,21 +842,21 @@ static int tegra_output_sor_disable(struct tegra_output *output)
        err = tegra_sor_power_down(sor);
        if (err < 0) {
                dev_err(sor->dev, "failed to power down SOR: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        if (sor->dpaux) {
                err = tegra_dpaux_disable(sor->dpaux);
                if (err < 0) {
                        dev_err(sor->dev, "failed to disable DP: %d\n", err);
-                       return err;
+                       goto unlock;
                }
        }
 
        err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS);
        if (err < 0) {
                dev_err(sor->dev, "failed to power off I/O rail: %d\n", err);
-               return err;
+               goto unlock;
        }
 
        reset_control_assert(sor->rst);
@@ -854,17 +864,20 @@ static int tegra_output_sor_disable(struct tegra_output *output)
 
        sor->enabled = false;
 
-       return 0;
+unlock:
+       mutex_unlock(&sor->lock);
+       return err;
 }
 
 static int tegra_output_sor_setup_clock(struct tegra_output *output,
-                                       struct clk *clk, unsigned long pclk)
+                                       struct clk *clk, unsigned long pclk,
+                                       unsigned int *div)
 {
        struct tegra_sor *sor = to_sor(output);
        int err;
 
        /* round to next MHz */
-       pclk = DIV_ROUND_UP(pclk / 2, 1000000) * 1000000;
+       pclk = DIV_ROUND_UP(pclk, 1000000) * 1000000;
 
        err = clk_set_parent(clk, sor->clk_parent);
        if (err < 0) {
@@ -874,11 +887,12 @@ static int tegra_output_sor_setup_clock(struct tegra_output *output,
 
        err = clk_set_rate(sor->clk_parent, pclk);
        if (err < 0) {
-               dev_err(sor->dev, "failed to set base clock rate to %lu Hz\n",
-                       pclk * 2);
+               dev_err(sor->dev, "failed to set clock rate to %lu Hz\n", pclk);
                return err;
        }
 
+       *div = 0;
+
        return 0;
 }
 
@@ -914,6 +928,120 @@ static const struct tegra_output_ops sor_ops = {
        .detect = tegra_output_sor_detect,
 };
 
+static int tegra_sor_crc_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+
+       return 0;
+}
+
+static int tegra_sor_crc_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
+{
+       u32 value;
+
+       timeout = jiffies + msecs_to_jiffies(timeout);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_CRC_A);
+               if (value & SOR_CRC_A_VALID)
+                       return 0;
+
+               usleep_range(100, 200);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
+                                 size_t size, loff_t *ppos)
+{
+       struct tegra_sor *sor = file->private_data;
+       ssize_t num, err;
+       char buf[10];
+       u32 value;
+
+       mutex_lock(&sor->lock);
+
+       if (!sor->enabled) {
+               err = -EAGAIN;
+               goto unlock;
+       }
+
+       value = tegra_sor_readl(sor, SOR_STATE_1);
+       value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
+       tegra_sor_writel(sor, value, SOR_STATE_1);
+
+       value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
+       value |= SOR_CRC_CNTRL_ENABLE;
+       tegra_sor_writel(sor, value, SOR_CRC_CNTRL);
+
+       value = tegra_sor_readl(sor, SOR_TEST);
+       value &= ~SOR_TEST_CRC_POST_SERIALIZE;
+       tegra_sor_writel(sor, value, SOR_TEST);
+
+       err = tegra_sor_crc_wait(sor, 100);
+       if (err < 0)
+               goto unlock;
+
+       tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
+       value = tegra_sor_readl(sor, SOR_CRC_B);
+
+       num = scnprintf(buf, sizeof(buf), "%08x\n", value);
+
+       err = simple_read_from_buffer(buffer, size, ppos, buf, num);
+
+unlock:
+       mutex_unlock(&sor->lock);
+       return err;
+}
+
+static const struct file_operations tegra_sor_crc_fops = {
+       .owner = THIS_MODULE,
+       .open = tegra_sor_crc_open,
+       .read = tegra_sor_crc_read,
+       .release = tegra_sor_crc_release,
+};
+
+static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct dentry *root)
+{
+       struct dentry *entry;
+       int err = 0;
+
+       sor->debugfs = debugfs_create_dir("sor", root);
+       if (!sor->debugfs)
+               return -ENOMEM;
+
+       entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
+                                   &tegra_sor_crc_fops);
+       if (!entry) {
+               dev_err(sor->dev,
+                       "cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
+                       root->d_name.name);
+               err = -ENOMEM;
+               goto remove;
+       }
+
+       return err;
+
+remove:
+       debugfs_remove(sor->debugfs);
+       sor->debugfs = NULL;
+       return err;
+}
+
+static int tegra_sor_debugfs_exit(struct tegra_sor *sor)
+{
+       debugfs_remove(sor->debugfs);
+       sor->debugfs = NULL;
+
+       return 0;
+}
+
 static int tegra_sor_init(struct host1x_client *client)
 {
        struct tegra_drm *tegra = dev_get_drvdata(client->parent);
@@ -934,6 +1062,14 @@ static int tegra_sor_init(struct host1x_client *client)
                return err;
        }
 
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               struct dentry *root = tegra->drm->primary->debugfs_root;
+
+               err = tegra_sor_debugfs_init(sor, root);
+               if (err < 0)
+                       dev_err(sor->dev, "debugfs setup failed: %d\n", err);
+       }
+
        if (sor->dpaux) {
                err = tegra_dpaux_attach(sor->dpaux, &sor->output);
                if (err < 0) {
@@ -964,6 +1100,12 @@ static int tegra_sor_exit(struct host1x_client *client)
                }
        }
 
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               err = tegra_sor_debugfs_exit(sor);
+               if (err < 0)
+                       dev_err(sor->dev, "debugfs cleanup failed: %d\n", err);
+       }
+
        err = tegra_output_exit(&sor->output);
        if (err < 0) {
                dev_err(sor->dev, "output cleanup failed: %d\n", err);
@@ -1045,6 +1187,8 @@ static int tegra_sor_probe(struct platform_device *pdev)
        sor->client.ops = &sor_client_ops;
        sor->client.dev = &pdev->dev;
 
+       mutex_init(&sor->lock);
+
        err = host1x_client_register(&sor->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register host1x client: %d\n",
index f4156d54cd058d7f9775cf2892c9bdcc19545622..a5f8853fedb5aaf391e794c45ab49f754cb6df9a 100644 (file)
@@ -47,6 +47,7 @@
 #define SOR_HEAD_STATE_4(x) (0x0d + (x))
 #define SOR_HEAD_STATE_5(x) (0x0f + (x))
 #define SOR_CRC_CNTRL 0x11
+#define  SOR_CRC_CNTRL_ENABLE                  (1 << 0)
 #define SOR_DP_DEBUG_MVID 0x12
 
 #define SOR_CLK_CNTRL 0x13
@@ -69,6 +70,7 @@
 #define  SOR_PWR_NORMAL_STATE_PU               (1 << 0)
 
 #define SOR_TEST 0x16
+#define  SOR_TEST_CRC_POST_SERIALIZE           (1 << 23)
 #define  SOR_TEST_ATTACHED                     (1 << 10)
 #define  SOR_TEST_HEAD_MODE_MASK               (3 << 8)
 #define  SOR_TEST_HEAD_MODE_AWAKE              (2 << 8)
 
 #define SOR_LVDS 0x1c
 #define SOR_CRC_A 0x1d
+#define  SOR_CRC_A_VALID                       (1 << 0)
+#define  SOR_CRC_A_RESET                       (1 << 0)
 #define SOR_CRC_B 0x1e
 #define SOR_BLANK 0x1f
 #define SOR_SEQ_CTL 0x20
index 171a8203892ce16b7767b2fb3fa11fc1995f0fad..b20b69488dc9b28d66e557578fa9ab1680984c3b 100644 (file)
@@ -268,7 +268,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        }
 
        pm_runtime_get_sync(dev->dev);
-       ret = drm_irq_install(dev);
+       ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
        pm_runtime_put_sync(dev->dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to install IRQ handler\n");
index f5ae57406f3447eacf3dbce309583ae303628824..e1038a945f40c6d34ed0aa1635678b3d5c9ac087 100644 (file)
@@ -294,6 +294,7 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = udl;
 
        if (!udl_parse_vendor_descriptor(dev, dev->usbdev)) {
+               ret = -ENODEV;
                DRM_ERROR("firmware not recognized. Assume incompatible device\n");
                goto err;
        }
index 9278891054834992ba30c5b9ac2a4f5b09403438..d70b1e1544bf68f7d99c1c756d00080f435e0815 100644 (file)
@@ -79,7 +79,7 @@ int via_final_context(struct drm_device *dev, int context)
 
        /* Linux specific until context tracking code gets ported to BSD */
        /* Last context, perform cleanup */
-       if (list_is_singular(&dev->ctxlist) && dev->dev_private) {
+       if (list_is_singular(&dev->ctxlist)) {
                DRM_DEBUG("Last Context\n");
                drm_irq_uninstall(dev);
                via_cleanup_futex(dev_priv);
index 4a223bbea3b34ee5489d25810ab04e14f1d2c7e3..6bdd15eea7e85ed098198ea98474213dced5c254 100644 (file)
@@ -806,7 +806,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        }
 
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
-               ret = drm_irq_install(dev);
+               ret = drm_irq_install(dev, dev->pdev->irq);
                if (ret != 0) {
                        DRM_ERROR("Failed installing irq: %d\n", ret);
                        goto out_no_irq;
index 931490b9cfed04b1365a87fb2d83c0526e114fdd..87df0b3674fda203c96baef3ff3030a87424a800 100644 (file)
@@ -1214,14 +1214,36 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
                SVGA3dCmdSurfaceDMA dma;
        } *cmd;
        int ret;
+       SVGA3dCmdSurfaceDMASuffix *suffix;
+       uint32_t bo_size;
 
        cmd = container_of(header, struct vmw_dma_cmd, header);
+       suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->dma +
+                                              header->size - sizeof(*suffix));
+
+       /* Make sure device and verifier stays in sync. */
+       if (unlikely(suffix->suffixSize != sizeof(*suffix))) {
+               DRM_ERROR("Invalid DMA suffix size.\n");
+               return -EINVAL;
+       }
+
        ret = vmw_translate_guest_ptr(dev_priv, sw_context,
                                      &cmd->dma.guest.ptr,
                                      &vmw_bo);
        if (unlikely(ret != 0))
                return ret;
 
+       /* Make sure DMA doesn't cross BO boundaries. */
+       bo_size = vmw_bo->base.num_pages * PAGE_SIZE;
+       if (unlikely(cmd->dma.guest.ptr.offset > bo_size)) {
+               DRM_ERROR("Invalid DMA offset.\n");
+               return -EINVAL;
+       }
+
+       bo_size -= cmd->dma.guest.ptr.offset;
+       if (unlikely(suffix->maximumOffset > bo_size))
+               suffix->maximumOffset = bo_size;
+
        ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                user_surface_converter, &cmd->dma.host.sid,
                                NULL);
index a2dde5ad81385bf932dd398bd522d1a950098f85..e7199b454ca055ce4afd87a3ce1e379b98159eda 100644 (file)
@@ -2001,7 +2001,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
        if (du->pref_mode)
                list_move(&du->pref_mode->head, &connector->probed_modes);
 
-       drm_mode_connector_list_update(connector);
+       drm_mode_connector_list_update(connector, true);
 
        return 1;
 }
index 7af9d0b5dea16f427987e234952c44cd53c540fc..762f15d6ed88bc7f1baf6d94d12065d3286d611f 100644 (file)
@@ -657,6 +657,14 @@ config HID_SUNPLUS
        ---help---
        Support for Sunplus wireless desktop.
 
+config HID_RMI
+       tristate "Synaptics RMI4 device support"
+       depends on HID
+       ---help---
+       Support for Synaptics RMI4 touchpads.
+       Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid
+       and want support for its special functionalities.
+
 config HID_GREENASIA
        tristate "GreenAsia (Product ID 0x12) game controller support"
        depends on HID
index fc712dde02a48f185dcdb4ff01e5dd0aadc96aa6..a6fa6baf368e49a254ba79646bc29abbd6575519 100644 (file)
@@ -97,6 +97,7 @@ obj-$(CONFIG_HID_ROCCAT)      += hid-roccat.o hid-roccat-common.o \
        hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
        hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
        hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-ryos.o hid-roccat-savu.o
+obj-$(CONFIG_HID_RMI)          += hid-rmi.o
 obj-$(CONFIG_HID_SAITEK)       += hid-saitek.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
index 10a2c08664596a3c43d1687cab911ad3fc3ab970..963a8da361b786572c36eec6d199175a4265d2f6 100644 (file)
@@ -1883,6 +1883,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
index 53b771d5683c68108b7b20ccf124d8ee2f288580..941ab3c287ec8f944712679d4c9f2c9b74007d5f 100644 (file)
@@ -855,6 +855,16 @@ static const char *keys[KEY_MAX + 1] = {
        [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
        [KEY_KBDILLUMUP] = "KbdIlluminationUp",
        [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+       [KEY_BUTTONCONFIG] = "ButtonConfig",
+       [KEY_TASKMANAGER] = "TaskManager",
+       [KEY_JOURNAL] = "Journal",
+       [KEY_CONTROLPANEL] = "ControlPanel",
+       [KEY_APPSELECT] = "AppSelect",
+       [KEY_SCREENSAVER] = "ScreenSaver",
+       [KEY_VOICECOMMAND] = "VoiceCommand",
+       [KEY_BRIGHTNESS_MIN] = "BrightnessMin",
+       [KEY_BRIGHTNESS_MAX] = "BrightnessMax",
+       [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
 };
 
 static const char *relatives[REL_MAX + 1] = {
index e7e8b19a928433becdfc7455e2b05733cf763736..9f2076acffb1d4c2dff2ff1520a80afaf78a24d4 100644 (file)
@@ -721,6 +721,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x06c: map_key_clear(KEY_YELLOW);          break;
                case 0x06d: map_key_clear(KEY_ZOOM);            break;
 
+               case 0x06f: map_key_clear(KEY_BRIGHTNESSUP);            break;
+               case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN);          break;
+               case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE);       break;
+               case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN);          break;
+               case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX);          break;
+               case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO);         break;
+
                case 0x082: map_key_clear(KEY_VIDEO_NEXT);      break;
                case 0x083: map_key_clear(KEY_LAST);            break;
                case 0x084: map_key_clear(KEY_ENTER);           break;
@@ -761,6 +768,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x0bf: map_key_clear(KEY_SLOW);            break;
 
                case 0x0cd: map_key_clear(KEY_PLAYPAUSE);       break;
+               case 0x0cf: map_key_clear(KEY_VOICECOMMAND);    break;
                case 0x0e0: map_abs_clear(ABS_VOLUME);          break;
                case 0x0e2: map_key_clear(KEY_MUTE);            break;
                case 0x0e5: map_key_clear(KEY_BASSBOOST);       break;
@@ -768,6 +776,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);      break;
                case 0x0f5: map_key_clear(KEY_SLOW);            break;
 
+               case 0x181: map_key_clear(KEY_BUTTONCONFIG);    break;
                case 0x182: map_key_clear(KEY_BOOKMARKS);       break;
                case 0x183: map_key_clear(KEY_CONFIG);          break;
                case 0x184: map_key_clear(KEY_WORDPROCESSOR);   break;
@@ -781,6 +790,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x18c: map_key_clear(KEY_VOICEMAIL);       break;
                case 0x18d: map_key_clear(KEY_ADDRESSBOOK);     break;
                case 0x18e: map_key_clear(KEY_CALENDAR);        break;
+               case 0x18f: map_key_clear(KEY_TASKMANAGER);     break;
+               case 0x190: map_key_clear(KEY_JOURNAL);         break;
                case 0x191: map_key_clear(KEY_FINANCE);         break;
                case 0x192: map_key_clear(KEY_CALC);            break;
                case 0x193: map_key_clear(KEY_PLAYER);          break;
@@ -789,12 +800,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x199: map_key_clear(KEY_CHAT);            break;
                case 0x19c: map_key_clear(KEY_LOGOFF);          break;
                case 0x19e: map_key_clear(KEY_COFFEE);          break;
+               case 0x19f: map_key_clear(KEY_CONTROLPANEL);            break;
+               case 0x1a2: map_key_clear(KEY_APPSELECT);               break;
                case 0x1a3: map_key_clear(KEY_NEXT);            break;
                case 0x1a4: map_key_clear(KEY_PREVIOUS);        break;
                case 0x1a6: map_key_clear(KEY_HELP);            break;
                case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
                case 0x1ab: map_key_clear(KEY_SPELLCHECK);      break;
                case 0x1ae: map_key_clear(KEY_KEYBOARD);        break;
+               case 0x1b1: map_key_clear(KEY_SCREENSAVER);             break;
                case 0x1b4: map_key_clear(KEY_FILE);            break;
                case 0x1b6: map_key_clear(KEY_IMAGES);          break;
                case 0x1b7: map_key_clear(KEY_AUDIO);           break;
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
new file mode 100644 (file)
index 0000000..7da9509
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ *  Copyright (c) 2013 Andrew Duggan <aduggan@synaptics.com>
+ *  Copyright (c) 2013 Synaptics Incorporated
+ *  Copyright (c) 2014 Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ *  Copyright (c) 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include "hid-ids.h"
+
+#define RMI_MOUSE_REPORT_ID            0x01 /* Mouse emulation Report */
+#define RMI_WRITE_REPORT_ID            0x09 /* Output Report */
+#define RMI_READ_ADDR_REPORT_ID                0x0a /* Output Report */
+#define RMI_READ_DATA_REPORT_ID                0x0b /* Input Report */
+#define RMI_ATTN_REPORT_ID             0x0c /* Input Report */
+#define RMI_SET_RMI_MODE_REPORT_ID     0x0f /* Feature Report */
+
+/* flags */
+#define RMI_READ_REQUEST_PENDING       BIT(0)
+#define RMI_READ_DATA_PENDING          BIT(1)
+#define RMI_STARTED                    BIT(2)
+
+enum rmi_mode_type {
+       RMI_MODE_OFF                    = 0,
+       RMI_MODE_ATTN_REPORTS           = 1,
+       RMI_MODE_NO_PACKED_ATTN_REPORTS = 2,
+};
+
+struct rmi_function {
+       unsigned page;                  /* page of the function */
+       u16 query_base_addr;            /* base address for queries */
+       u16 command_base_addr;          /* base address for commands */
+       u16 control_base_addr;          /* base address for controls */
+       u16 data_base_addr;             /* base address for datas */
+       unsigned int interrupt_base;    /* cross-function interrupt number
+                                        * (uniq in the device)*/
+       unsigned int interrupt_count;   /* number of interrupts */
+       unsigned int report_size;       /* size of a report */
+       unsigned long irq_mask;         /* mask of the interrupts
+                                        * (to be applied against ATTN IRQ) */
+};
+
+/**
+ * struct rmi_data - stores information for hid communication
+ *
+ * @page_mutex: Locks current page to avoid changing pages in unexpected ways.
+ * @page: Keeps track of the current virtual page
+ *
+ * @wait: Used for waiting for read data
+ *
+ * @writeReport: output buffer when writing RMI registers
+ * @readReport: input buffer when reading RMI registers
+ *
+ * @input_report_size: size of an input report (advertised by HID)
+ * @output_report_size: size of an output report (advertised by HID)
+ *
+ * @flags: flags for the current device (started, reading, etc...)
+ *
+ * @f11: placeholder of internal RMI function F11 description
+ * @f30: placeholder of internal RMI function F30 description
+ *
+ * @max_fingers: maximum finger count reported by the device
+ * @max_x: maximum x value reported by the device
+ * @max_y: maximum y value reported by the device
+ *
+ * @gpio_led_count: count of GPIOs + LEDs reported by F30
+ * @button_count: actual physical buttons count
+ * @button_mask: button mask used to decode GPIO ATTN reports
+ * @button_state_mask: pull state of the buttons
+ *
+ * @input: pointer to the kernel input device
+ *
+ * @reset_work: worker which will be called in case of a mouse report
+ * @hdev: pointer to the struct hid_device
+ */
+struct rmi_data {
+       struct mutex page_mutex;
+       int page;
+
+       wait_queue_head_t wait;
+
+       u8 *writeReport;
+       u8 *readReport;
+
+       int input_report_size;
+       int output_report_size;
+
+       unsigned long flags;
+
+       struct rmi_function f11;
+       struct rmi_function f30;
+
+       unsigned int max_fingers;
+       unsigned int max_x;
+       unsigned int max_y;
+       unsigned int x_size_mm;
+       unsigned int y_size_mm;
+
+       unsigned int gpio_led_count;
+       unsigned int button_count;
+       unsigned long button_mask;
+       unsigned long button_state_mask;
+
+       struct input_dev *input;
+
+       struct work_struct reset_work;
+       struct hid_device *hdev;
+};
+
+#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
+
+static int rmi_write_report(struct hid_device *hdev, u8 *report, int len);
+
+/**
+ * rmi_set_page - Set RMI page
+ * @hdev: The pointer to the hid_device struct
+ * @page: The new page address.
+ *
+ * RMI devices have 16-bit addressing, but some of the physical
+ * implementations (like SMBus) only have 8-bit addressing. So RMI implements
+ * a page address at 0xff of every page so we can reliable page addresses
+ * every 256 registers.
+ *
+ * The page_mutex lock must be held when this function is entered.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+static int rmi_set_page(struct hid_device *hdev, u8 page)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       int retval;
+
+       data->writeReport[0] = RMI_WRITE_REPORT_ID;
+       data->writeReport[1] = 1;
+       data->writeReport[2] = 0xFF;
+       data->writeReport[4] = page;
+
+       retval = rmi_write_report(hdev, data->writeReport,
+                       data->output_report_size);
+       if (retval != data->output_report_size) {
+               dev_err(&hdev->dev,
+                       "%s: set page failed: %d.", __func__, retval);
+               return retval;
+       }
+
+       data->page = page;
+       return 0;
+}
+
+static int rmi_set_mode(struct hid_device *hdev, u8 mode)
+{
+       int ret;
+       u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode};
+
+       ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, txbuf,
+                       sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode,
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_write_report(struct hid_device *hdev, u8 *report, int len)
+{
+       int ret;
+
+       ret = hid_hw_output_report(hdev, (void *)report, len);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int rmi_read_block(struct hid_device *hdev, u16 addr, void *buf,
+               const int len)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       int ret;
+       int bytes_read;
+       int bytes_needed;
+       int retries;
+       int read_input_count;
+
+       mutex_lock(&data->page_mutex);
+
+       if (RMI_PAGE(addr) != data->page) {
+               ret = rmi_set_page(hdev, RMI_PAGE(addr));
+               if (ret < 0)
+                       goto exit;
+       }
+
+       for (retries = 5; retries > 0; retries--) {
+               data->writeReport[0] = RMI_READ_ADDR_REPORT_ID;
+               data->writeReport[1] = 0; /* old 1 byte read count */
+               data->writeReport[2] = addr & 0xFF;
+               data->writeReport[3] = (addr >> 8) & 0xFF;
+               data->writeReport[4] = len  & 0xFF;
+               data->writeReport[5] = (len >> 8) & 0xFF;
+
+               set_bit(RMI_READ_REQUEST_PENDING, &data->flags);
+
+               ret = rmi_write_report(hdev, data->writeReport,
+                                               data->output_report_size);
+               if (ret != data->output_report_size) {
+                       clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
+                       dev_err(&hdev->dev,
+                               "failed to write request output report (%d)\n",
+                               ret);
+                       goto exit;
+               }
+
+               bytes_read = 0;
+               bytes_needed = len;
+               while (bytes_read < len) {
+                       if (!wait_event_timeout(data->wait,
+                               test_bit(RMI_READ_DATA_PENDING, &data->flags),
+                                       msecs_to_jiffies(1000))) {
+                               hid_warn(hdev, "%s: timeout elapsed\n",
+                                        __func__);
+                               ret = -EAGAIN;
+                               break;
+                       }
+
+                       read_input_count = data->readReport[1];
+                       memcpy(buf + bytes_read, &data->readReport[2],
+                               read_input_count < bytes_needed ?
+                                       read_input_count : bytes_needed);
+
+                       bytes_read += read_input_count;
+                       bytes_needed -= read_input_count;
+                       clear_bit(RMI_READ_DATA_PENDING, &data->flags);
+               }
+
+               if (ret >= 0) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+exit:
+       clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
+       mutex_unlock(&data->page_mutex);
+       return ret;
+}
+
+static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf)
+{
+       return rmi_read_block(hdev, addr, buf, 1);
+}
+
+static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
+               u8 finger_state, u8 *touch_data)
+{
+       int x, y, wx, wy;
+       int wide, major, minor;
+       int z;
+
+       input_mt_slot(hdata->input, slot);
+       input_mt_report_slot_state(hdata->input, MT_TOOL_FINGER,
+                       finger_state == 0x01);
+       if (finger_state == 0x01) {
+               x = (touch_data[0] << 4) | (touch_data[2] & 0x07);
+               y = (touch_data[1] << 4) | (touch_data[2] >> 4);
+               wx = touch_data[3] & 0x07;
+               wy = touch_data[3] >> 4;
+               wide = (wx > wy);
+               major = max(wx, wy);
+               minor = min(wx, wy);
+               z = touch_data[4];
+
+               /* y is inverted */
+               y = hdata->max_y - y;
+
+               input_event(hdata->input, EV_ABS, ABS_MT_POSITION_X, x);
+               input_event(hdata->input, EV_ABS, ABS_MT_POSITION_Y, y);
+               input_event(hdata->input, EV_ABS, ABS_MT_ORIENTATION, wide);
+               input_event(hdata->input, EV_ABS, ABS_MT_PRESSURE, z);
+               input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+               input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+       }
+}
+
+static void rmi_reset_work(struct work_struct *work)
+{
+       struct rmi_data *hdata = container_of(work, struct rmi_data,
+                                               reset_work);
+
+       /* switch the device to RMI if we receive a generic mouse report */
+       rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS);
+}
+
+static inline int rmi_schedule_reset(struct hid_device *hdev)
+{
+       struct rmi_data *hdata = hid_get_drvdata(hdev);
+       return schedule_work(&hdata->reset_work);
+}
+
+static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
+               int size)
+{
+       struct rmi_data *hdata = hid_get_drvdata(hdev);
+       int offset;
+       int i;
+
+       if (size < hdata->f11.report_size)
+               return 0;
+
+       if (!(irq & hdata->f11.irq_mask))
+               return 0;
+
+       offset = (hdata->max_fingers >> 2) + 1;
+       for (i = 0; i < hdata->max_fingers; i++) {
+               int fs_byte_position = i >> 2;
+               int fs_bit_position = (i & 0x3) << 1;
+               int finger_state = (data[fs_byte_position] >> fs_bit_position) &
+                                       0x03;
+
+               rmi_f11_process_touch(hdata, i, finger_state,
+                               &data[offset + 5 * i]);
+       }
+       input_mt_sync_frame(hdata->input);
+       input_sync(hdata->input);
+       return hdata->f11.report_size;
+}
+
+static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
+               int size)
+{
+       struct rmi_data *hdata = hid_get_drvdata(hdev);
+       int i;
+       int button = 0;
+       bool value;
+
+       if (!(irq & hdata->f30.irq_mask))
+               return 0;
+
+       for (i = 0; i < hdata->gpio_led_count; i++) {
+               if (test_bit(i, &hdata->button_mask)) {
+                       value = (data[i / 8] >> (i & 0x07)) & BIT(0);
+                       if (test_bit(i, &hdata->button_state_mask))
+                               value = !value;
+                       input_event(hdata->input, EV_KEY, BTN_LEFT + button++,
+                                       value);
+               }
+       }
+       return hdata->f30.report_size;
+}
+
+static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
+{
+       struct rmi_data *hdata = hid_get_drvdata(hdev);
+       unsigned long irq_mask = 0;
+       unsigned index = 2;
+
+       if (!(test_bit(RMI_STARTED, &hdata->flags)))
+               return 0;
+
+       irq_mask |= hdata->f11.irq_mask;
+       irq_mask |= hdata->f30.irq_mask;
+
+       if (data[1] & ~irq_mask)
+               hid_warn(hdev, "unknown intr source:%02lx %s:%d\n",
+                       data[1] & ~irq_mask, __FILE__, __LINE__);
+
+       if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) {
+               index += rmi_f11_input_event(hdev, data[1], &data[index],
+                               size - index);
+               index += rmi_f30_input_event(hdev, data[1], &data[index],
+                               size - index);
+       } else {
+               index += rmi_f30_input_event(hdev, data[1], &data[index],
+                               size - index);
+               index += rmi_f11_input_event(hdev, data[1], &data[index],
+                               size - index);
+       }
+
+       return 1;
+}
+
+static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
+{
+       struct rmi_data *hdata = hid_get_drvdata(hdev);
+
+       if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) {
+               hid_err(hdev, "no read request pending\n");
+               return 0;
+       }
+
+       memcpy(hdata->readReport, data, size < hdata->input_report_size ?
+                       size : hdata->input_report_size);
+       set_bit(RMI_READ_DATA_PENDING, &hdata->flags);
+       wake_up(&hdata->wait);
+
+       return 1;
+}
+
+static int rmi_raw_event(struct hid_device *hdev,
+               struct hid_report *report, u8 *data, int size)
+{
+       switch (data[0]) {
+       case RMI_READ_DATA_REPORT_ID:
+               return rmi_read_data_event(hdev, data, size);
+       case RMI_ATTN_REPORT_ID:
+               return rmi_input_event(hdev, data, size);
+       case RMI_MOUSE_REPORT_ID:
+               rmi_schedule_reset(hdev);
+               break;
+       }
+
+       return 0;
+}
+
+static int rmi_post_reset(struct hid_device *hdev)
+{
+       return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+}
+
+static int rmi_post_resume(struct hid_device *hdev)
+{
+       return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+}
+
+#define RMI4_MAX_PAGE 0xff
+#define RMI4_PAGE_SIZE 0x0100
+
+#define PDT_START_SCAN_LOCATION 0x00e9
+#define PDT_END_SCAN_LOCATION  0x0005
+#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
+
+struct pdt_entry {
+       u8 query_base_addr:8;
+       u8 command_base_addr:8;
+       u8 control_base_addr:8;
+       u8 data_base_addr:8;
+       u8 interrupt_source_count:3;
+       u8 bits3and4:2;
+       u8 function_version:2;
+       u8 bit7:1;
+       u8 function_number:8;
+} __attribute__((__packed__));
+
+static inline unsigned long rmi_gen_mask(unsigned irq_base, unsigned irq_count)
+{
+       return GENMASK(irq_count + irq_base - 1, irq_base);
+}
+
+static void rmi_register_function(struct rmi_data *data,
+       struct pdt_entry *pdt_entry, int page, unsigned interrupt_count)
+{
+       struct rmi_function *f = NULL;
+       u16 page_base = page << 8;
+
+       switch (pdt_entry->function_number) {
+       case 0x11:
+               f = &data->f11;
+               break;
+       case 0x30:
+               f = &data->f30;
+               break;
+       }
+
+       if (f) {
+               f->page = page;
+               f->query_base_addr = page_base | pdt_entry->query_base_addr;
+               f->command_base_addr = page_base | pdt_entry->command_base_addr;
+               f->control_base_addr = page_base | pdt_entry->control_base_addr;
+               f->data_base_addr = page_base | pdt_entry->data_base_addr;
+               f->interrupt_base = interrupt_count;
+               f->interrupt_count = pdt_entry->interrupt_source_count;
+               f->irq_mask = rmi_gen_mask(f->interrupt_base,
+                                               f->interrupt_count);
+       }
+}
+
+static int rmi_scan_pdt(struct hid_device *hdev)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       struct pdt_entry entry;
+       int page;
+       bool page_has_function;
+       int i;
+       int retval;
+       int interrupt = 0;
+       u16 page_start, pdt_start , pdt_end;
+
+       hid_info(hdev, "Scanning PDT...\n");
+
+       for (page = 0; (page <= RMI4_MAX_PAGE); page++) {
+               page_start = RMI4_PAGE_SIZE * page;
+               pdt_start = page_start + PDT_START_SCAN_LOCATION;
+               pdt_end = page_start + PDT_END_SCAN_LOCATION;
+
+               page_has_function = false;
+               for (i = pdt_start; i >= pdt_end; i -= sizeof(entry)) {
+                       retval = rmi_read_block(hdev, i, &entry, sizeof(entry));
+                       if (retval) {
+                               hid_err(hdev,
+                                       "Read of PDT entry at %#06x failed.\n",
+                                       i);
+                               goto error_exit;
+                       }
+
+                       if (RMI4_END_OF_PDT(entry.function_number))
+                               break;
+
+                       page_has_function = true;
+
+                       hid_info(hdev, "Found F%02X on page %#04x\n",
+                                       entry.function_number, page);
+
+                       rmi_register_function(data, &entry, page, interrupt);
+                       interrupt += entry.interrupt_source_count;
+               }
+
+               if (!page_has_function)
+                       break;
+       }
+
+       hid_info(hdev, "%s: Done with PDT scan.\n", __func__);
+       retval = 0;
+
+error_exit:
+       return retval;
+}
+
+static int rmi_populate_f11(struct hid_device *hdev)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       u8 buf[20];
+       int ret;
+       bool has_query12;
+       bool has_physical_props;
+       unsigned x_size, y_size;
+
+       if (!data->f11.query_base_addr) {
+               hid_err(hdev, "No 2D sensor found, giving up.\n");
+               return -ENODEV;
+       }
+
+       /* query 0 contains some useful information */
+       ret = rmi_read(hdev, data->f11.query_base_addr, buf);
+       if (ret) {
+               hid_err(hdev, "can not get query 0: %d.\n", ret);
+               return ret;
+       }
+       has_query12 = !!(buf[0] & BIT(5));
+
+       /* query 1 to get the max number of fingers */
+       ret = rmi_read(hdev, data->f11.query_base_addr + 1, buf);
+       if (ret) {
+               hid_err(hdev, "can not get NumberOfFingers: %d.\n", ret);
+               return ret;
+       }
+       data->max_fingers = (buf[0] & 0x07) + 1;
+       if (data->max_fingers > 5)
+               data->max_fingers = 10;
+
+       data->f11.report_size = data->max_fingers * 5 +
+                               DIV_ROUND_UP(data->max_fingers, 4);
+
+       if (!(buf[0] & BIT(4))) {
+               hid_err(hdev, "No absolute events, giving up.\n");
+               return -ENODEV;
+       }
+
+       /*
+        * query 12 to know if the physical properties are reported
+        * (query 12 is at offset 10 for HID devices)
+        */
+       if (has_query12) {
+               ret = rmi_read(hdev, data->f11.query_base_addr + 10, buf);
+               if (ret) {
+                       hid_err(hdev, "can not get query 12: %d.\n", ret);
+                       return ret;
+               }
+               has_physical_props = !!(buf[0] & BIT(5));
+
+               if (has_physical_props) {
+                       ret = rmi_read_block(hdev,
+                                       data->f11.query_base_addr + 11, buf, 4);
+                       if (ret) {
+                               hid_err(hdev, "can not read query 15-18: %d.\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       x_size = buf[0] | (buf[1] << 8);
+                       y_size = buf[2] | (buf[3] << 8);
+
+                       data->x_size_mm = DIV_ROUND_CLOSEST(x_size, 10);
+                       data->y_size_mm = DIV_ROUND_CLOSEST(y_size, 10);
+
+                       hid_info(hdev, "%s: size in mm: %d x %d\n",
+                                __func__, data->x_size_mm, data->y_size_mm);
+               }
+       }
+
+       /* retrieve the ctrl registers */
+       ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 20);
+       if (ret) {
+               hid_err(hdev, "can not read ctrl block of size 20: %d.\n", ret);
+               return ret;
+       }
+
+       data->max_x = buf[6] | (buf[7] << 8);
+       data->max_y = buf[8] | (buf[9] << 8);
+
+       return 0;
+}
+
+static int rmi_populate_f30(struct hid_device *hdev)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       u8 buf[20];
+       int ret;
+       bool has_gpio, has_led;
+       unsigned bytes_per_ctrl;
+       u8 ctrl2_addr;
+       int ctrl2_3_length;
+       int i;
+
+       /* function F30 is for physical buttons */
+       if (!data->f30.query_base_addr) {
+               hid_err(hdev, "No GPIO/LEDs found, giving up.\n");
+               return -ENODEV;
+       }
+
+       ret = rmi_read_block(hdev, data->f30.query_base_addr, buf, 2);
+       if (ret) {
+               hid_err(hdev, "can not get F30 query registers: %d.\n", ret);
+               return ret;
+       }
+
+       has_gpio = !!(buf[0] & BIT(3));
+       has_led = !!(buf[0] & BIT(2));
+       data->gpio_led_count = buf[1] & 0x1f;
+
+       /* retrieve ctrl 2 & 3 registers */
+       bytes_per_ctrl = (data->gpio_led_count + 7) / 8;
+       /* Ctrl0 is present only if both has_gpio and has_led are set*/
+       ctrl2_addr = (has_gpio && has_led) ? bytes_per_ctrl : 0;
+       /* Ctrl1 is always be present */
+       ctrl2_addr += bytes_per_ctrl;
+       ctrl2_3_length = 2 * bytes_per_ctrl;
+
+       data->f30.report_size = bytes_per_ctrl;
+
+       ret = rmi_read_block(hdev, data->f30.control_base_addr + ctrl2_addr,
+                               buf, ctrl2_3_length);
+       if (ret) {
+               hid_err(hdev, "can not read ctrl 2&3 block of size %d: %d.\n",
+                       ctrl2_3_length, ret);
+               return ret;
+       }
+
+       for (i = 0; i < data->gpio_led_count; i++) {
+               int byte_position = i >> 3;
+               int bit_position = i & 0x07;
+               u8 dir_byte = buf[byte_position];
+               u8 data_byte = buf[byte_position + bytes_per_ctrl];
+               bool dir = (dir_byte >> bit_position) & BIT(0);
+               bool dat = (data_byte >> bit_position) & BIT(0);
+
+               if (dir == 0) {
+                       /* input mode */
+                       if (dat) {
+                               /* actual buttons have pull up resistor */
+                               data->button_count++;
+                               set_bit(i, &data->button_mask);
+                               set_bit(i, &data->button_state_mask);
+                       }
+               }
+
+       }
+
+       return 0;
+}
+
+static int rmi_populate(struct hid_device *hdev)
+{
+       int ret;
+
+       ret = rmi_scan_pdt(hdev);
+       if (ret) {
+               hid_err(hdev, "PDT scan failed with code %d.\n", ret);
+               return ret;
+       }
+
+       ret = rmi_populate_f11(hdev);
+       if (ret) {
+               hid_err(hdev, "Error while initializing F11 (%d).\n", ret);
+               return ret;
+       }
+
+       ret = rmi_populate_f30(hdev);
+       if (ret)
+               hid_warn(hdev, "Error while initializing F30 (%d).\n", ret);
+
+       return 0;
+}
+
+static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       struct input_dev *input = hi->input;
+       int ret;
+       int res_x, res_y, i;
+
+       data->input = input;
+
+       hid_dbg(hdev, "Opening low level driver\n");
+       ret = hid_hw_open(hdev);
+       if (ret)
+               return;
+
+       /* Allow incoming hid reports */
+       hid_device_io_start(hdev);
+
+       ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to set rmi mode\n");
+               goto exit;
+       }
+
+       ret = rmi_set_page(hdev, 0);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "failed to set page select to 0.\n");
+               goto exit;
+       }
+
+       ret = rmi_populate(hdev);
+       if (ret)
+               goto exit;
+
+       __set_bit(EV_ABS, input->evbit);
+       input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0);
+
+       if (data->x_size_mm && data->x_size_mm) {
+               res_x = (data->max_x - 1) / data->x_size_mm;
+               res_y = (data->max_y - 1) / data->x_size_mm;
+
+               input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
+               input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
+       }
+
+       input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+       input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
+       input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
+       input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
+
+       input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
+
+       if (data->button_count) {
+               __set_bit(EV_KEY, input->evbit);
+               for (i = 0; i < data->button_count; i++)
+                       __set_bit(BTN_LEFT + i, input->keybit);
+
+               if (data->button_count == 1)
+                       __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+       }
+
+       set_bit(RMI_STARTED, &data->flags);
+
+exit:
+       hid_device_io_stop(hdev);
+       hid_hw_close(hdev);
+}
+
+static int rmi_input_mapping(struct hid_device *hdev,
+               struct hid_input *hi, struct hid_field *field,
+               struct hid_usage *usage, unsigned long **bit, int *max)
+{
+       /* we want to make HID ignore the advertised HID collection */
+       return -1;
+}
+
+static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       struct rmi_data *data = NULL;
+       int ret;
+       size_t alloc_size;
+
+       data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       INIT_WORK(&data->reset_work, rmi_reset_work);
+       data->hdev = hdev;
+
+       hid_set_drvdata(hdev, data);
+
+       hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "parse failed\n");
+               return ret;
+       }
+
+       data->input_report_size = (hdev->report_enum[HID_INPUT_REPORT]
+               .report_id_hash[RMI_ATTN_REPORT_ID]->size >> 3)
+               + 1 /* report id */;
+       data->output_report_size = (hdev->report_enum[HID_OUTPUT_REPORT]
+               .report_id_hash[RMI_WRITE_REPORT_ID]->size >> 3)
+               + 1 /* report id */;
+
+       alloc_size = data->output_report_size + data->input_report_size;
+
+       data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
+       if (!data->writeReport) {
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       data->readReport = data->writeReport + data->output_report_size;
+
+       init_waitqueue_head(&data->wait);
+
+       mutex_init(&data->page_mutex);
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               hid_err(hdev, "hw start failed\n");
+               return ret;
+       }
+
+       if (!test_bit(RMI_STARTED, &data->flags)) {
+               hid_hw_stop(hdev);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void rmi_remove(struct hid_device *hdev)
+{
+       struct rmi_data *hdata = hid_get_drvdata(hdev);
+
+       clear_bit(RMI_STARTED, &hdata->flags);
+
+       hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id rmi_id[] = {
+       { HID_I2C_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, rmi_id);
+
+static struct hid_driver rmi_driver = {
+       .name = "hid-rmi",
+       .id_table               = rmi_id,
+       .probe                  = rmi_probe,
+       .remove                 = rmi_remove,
+       .raw_event              = rmi_raw_event,
+       .input_mapping          = rmi_input_mapping,
+       .input_configured       = rmi_input_configured,
+#ifdef CONFIG_PM
+       .resume                 = rmi_post_resume,
+       .reset_resume           = rmi_post_reset,
+#endif
+};
+
+module_hid_driver(rmi_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_DESCRIPTION("RMI HID driver");
+MODULE_LICENSE("GPL");
index 908de278921944dfae837284f582e117617c479d..2259eaa8b98886d8ae0ec454a2a0fce8aa99e695 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/power_supply.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/idr.h>
 #include <linux/input/mt.h>
 
 #include "hid-ids.h"
@@ -717,8 +718,39 @@ static enum power_supply_property sony_battery_props[] = {
        POWER_SUPPLY_PROP_STATUS,
 };
 
+struct sixaxis_led {
+       __u8 time_enabled; /* the total time the led is active (0xff means forever) */
+       __u8 duty_length;  /* how long a cycle is in deciseconds (0 means "really fast") */
+       __u8 enabled;
+       __u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */
+       __u8 duty_on;  /* % of duty_length the led is on (0xff mean 100%) */
+} __packed;
+
+struct sixaxis_rumble {
+       __u8 padding;
+       __u8 right_duration; /* Right motor duration (0xff means forever) */
+       __u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
+       __u8 left_duration;    /* Left motor duration (0xff means forever) */
+       __u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
+} __packed;
+
+struct sixaxis_output_report {
+       __u8 report_id;
+       struct sixaxis_rumble rumble;
+       __u8 padding[4];
+       __u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
+       struct sixaxis_led led[4];    /* LEDx at (4 - x) */
+       struct sixaxis_led _reserved; /* LED5, not actually soldered */
+} __packed;
+
+union sixaxis_output_report_01 {
+       struct sixaxis_output_report data;
+       __u8 buf[36];
+};
+
 static spinlock_t sony_dev_list_lock;
 static LIST_HEAD(sony_device_list);
+static DEFINE_IDA(sony_device_id_allocator);
 
 struct sony_sc {
        spinlock_t lock;
@@ -728,6 +760,7 @@ struct sony_sc {
        unsigned long quirks;
        struct work_struct state_worker;
        struct power_supply battery;
+       int device_id;
 
 #ifdef CONFIG_SONY_FF
        __u8 left;
@@ -740,6 +773,8 @@ struct sony_sc {
        __u8 battery_charging;
        __u8 battery_capacity;
        __u8 led_state[MAX_LEDS];
+       __u8 led_delay_on[MAX_LEDS];
+       __u8 led_delay_off[MAX_LEDS];
        __u8 led_count;
 };
 
@@ -1048,6 +1083,52 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev)
                                HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
 }
 
+static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS])
+{
+       static const __u8 sixaxis_leds[10][4] = {
+                               { 0x01, 0x00, 0x00, 0x00 },
+                               { 0x00, 0x01, 0x00, 0x00 },
+                               { 0x00, 0x00, 0x01, 0x00 },
+                               { 0x00, 0x00, 0x00, 0x01 },
+                               { 0x01, 0x00, 0x00, 0x01 },
+                               { 0x00, 0x01, 0x00, 0x01 },
+                               { 0x00, 0x00, 0x01, 0x01 },
+                               { 0x01, 0x00, 0x01, 0x01 },
+                               { 0x00, 0x01, 0x01, 0x01 },
+                               { 0x01, 0x01, 0x01, 0x01 }
+       };
+
+       BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0]));
+
+       if (id < 0)
+               return;
+
+       id %= 10;
+       memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id]));
+}
+
+static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS])
+{
+       /* The first 4 color/index entries match what the PS4 assigns */
+       static const __u8 color_code[7][3] = {
+                       /* Blue   */    { 0x00, 0x00, 0x01 },
+                       /* Red    */    { 0x01, 0x00, 0x00 },
+                       /* Green  */    { 0x00, 0x01, 0x00 },
+                       /* Pink   */    { 0x02, 0x00, 0x01 },
+                       /* Orange */    { 0x02, 0x01, 0x00 },
+                       /* Teal   */    { 0x00, 0x01, 0x01 },
+                       /* White  */    { 0x01, 0x01, 0x01 }
+       };
+
+       BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0]));
+
+       if (id < 0)
+               return;
+
+       id %= 7;
+       memcpy(values, color_code[id], sizeof(color_code[id]));
+}
+
 static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
 {
        struct list_head *report_list =
@@ -1066,19 +1147,18 @@ static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
        hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
 }
 
-static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
+static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count)
 {
-       struct sony_sc *drv_data = hid_get_drvdata(hdev);
        int n;
 
        BUG_ON(count > MAX_LEDS);
 
-       if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) {
-               buzz_set_leds(hdev, leds);
+       if (sc->quirks & BUZZ_CONTROLLER && count == 4) {
+               buzz_set_leds(sc->hdev, leds);
        } else {
                for (n = 0; n < count; n++)
-                       drv_data->led_state[n] = leds[n];
-               schedule_work(&drv_data->state_worker);
+                       sc->led_state[n] = leds[n];
+               schedule_work(&sc->state_worker);
        }
 }
 
@@ -1090,6 +1170,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
        struct sony_sc *drv_data;
 
        int n;
+       int force_update;
 
        drv_data = hid_get_drvdata(hdev);
        if (!drv_data) {
@@ -1097,12 +1178,29 @@ static void sony_led_set_brightness(struct led_classdev *led,
                return;
        }
 
+       /*
+        * The Sixaxis on USB will override any LED settings sent to it
+        * and keep flashing all of the LEDs until the PS button is pressed.
+        * Updates, even if redundant, must be always be sent to the
+        * controller to avoid having to toggle the state of an LED just to
+        * stop the flashing later on.
+        */
+       force_update = !!(drv_data->quirks & SIXAXIS_CONTROLLER_USB);
+
        for (n = 0; n < drv_data->led_count; n++) {
-               if (led == drv_data->leds[n]) {
-                       if (value != drv_data->led_state[n]) {
-                               drv_data->led_state[n] = value;
-                               sony_set_leds(hdev, drv_data->led_state, drv_data->led_count);
-                       }
+               if (led == drv_data->leds[n] && (force_update ||
+                       (value != drv_data->led_state[n] ||
+                       drv_data->led_delay_on[n] ||
+                       drv_data->led_delay_off[n]))) {
+
+                       drv_data->led_state[n] = value;
+
+                       /* Setting the brightness stops the blinking */
+                       drv_data->led_delay_on[n] = 0;
+                       drv_data->led_delay_off[n] = 0;
+
+                       sony_set_leds(drv_data, drv_data->led_state,
+                                       drv_data->led_count);
                        break;
                }
        }
@@ -1130,63 +1228,112 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
        return LED_OFF;
 }
 
-static void sony_leds_remove(struct hid_device *hdev)
+static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
+                               unsigned long *delay_off)
 {
-       struct sony_sc *drv_data;
-       struct led_classdev *led;
+       struct device *dev = led->dev->parent;
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct sony_sc *drv_data = hid_get_drvdata(hdev);
        int n;
+       __u8 new_on, new_off;
 
-       drv_data = hid_get_drvdata(hdev);
-       BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
+       if (!drv_data) {
+               hid_err(hdev, "No device data\n");
+               return -EINVAL;
+       }
+
+       /* Max delay is 255 deciseconds or 2550 milliseconds */
+       if (*delay_on > 2550)
+               *delay_on = 2550;
+       if (*delay_off > 2550)
+               *delay_off = 2550;
+
+       /* Blink at 1 Hz if both values are zero */
+       if (!*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       new_on = *delay_on / 10;
+       new_off = *delay_off / 10;
 
        for (n = 0; n < drv_data->led_count; n++) {
-               led = drv_data->leds[n];
-               drv_data->leds[n] = NULL;
+               if (led == drv_data->leds[n])
+                       break;
+       }
+
+       /* This LED is not registered on this device */
+       if (n >= drv_data->led_count)
+               return -EINVAL;
+
+       /* Don't schedule work if the values didn't change */
+       if (new_on != drv_data->led_delay_on[n] ||
+               new_off != drv_data->led_delay_off[n]) {
+               drv_data->led_delay_on[n] = new_on;
+               drv_data->led_delay_off[n] = new_off;
+               schedule_work(&drv_data->state_worker);
+       }
+
+       return 0;
+}
+
+static void sony_leds_remove(struct sony_sc *sc)
+{
+       struct led_classdev *led;
+       int n;
+
+       BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
+
+       for (n = 0; n < sc->led_count; n++) {
+               led = sc->leds[n];
+               sc->leds[n] = NULL;
                if (!led)
                        continue;
                led_classdev_unregister(led);
                kfree(led);
        }
 
-       drv_data->led_count = 0;
+       sc->led_count = 0;
 }
 
-static int sony_leds_init(struct hid_device *hdev)
+static int sony_leds_init(struct sony_sc *sc)
 {
-       struct sony_sc *drv_data;
+       struct hid_device *hdev = sc->hdev;
        int n, ret = 0;
-       int max_brightness;
-       int use_colors;
+       int use_ds4_names;
        struct led_classdev *led;
        size_t name_sz;
        char *name;
        size_t name_len;
        const char *name_fmt;
-       static const char * const color_str[] = { "red", "green", "blue" };
-       static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 };
+       static const char * const ds4_name_str[] = { "red", "green", "blue",
+                                                 "global" };
+       __u8 initial_values[MAX_LEDS] = { 0 };
+       __u8 max_brightness[MAX_LEDS] = { 1 };
+       __u8 use_hw_blink[MAX_LEDS] = { 0 };
 
-       drv_data = hid_get_drvdata(hdev);
-       BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
+       BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
 
-       if (drv_data->quirks & BUZZ_CONTROLLER) {
-               drv_data->led_count = 4;
-               max_brightness = 1;
-               use_colors = 0;
+       if (sc->quirks & BUZZ_CONTROLLER) {
+               sc->led_count = 4;
+               use_ds4_names = 0;
                name_len = strlen("::buzz#");
                name_fmt = "%s::buzz%d";
                /* Validate expected report characteristics. */
                if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
                        return -ENODEV;
-       } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER) {
-               drv_data->led_count = 3;
-               max_brightness = 255;
-               use_colors = 1;
+       } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
+               dualshock4_set_leds_from_id(sc->device_id, initial_values);
+               initial_values[3] = 1;
+               sc->led_count = 4;
+               memset(max_brightness, 255, 3);
+               use_hw_blink[3] = 1;
+               use_ds4_names = 1;
                name_len = 0;
                name_fmt = "%s:%s";
        } else {
-               drv_data->led_count = 4;
-               max_brightness = 1;
-               use_colors = 0;
+               sixaxis_set_leds_from_id(sc->device_id, initial_values);
+               sc->led_count = 4;
+               memset(use_hw_blink, 1, 4);
+               use_ds4_names = 0;
                name_len = strlen("::sony#");
                name_fmt = "%s::sony%d";
        }
@@ -1196,14 +1343,14 @@ static int sony_leds_init(struct hid_device *hdev)
         * only relevant if the driver is loaded after somebody actively set the
         * LEDs to on
         */
-       sony_set_leds(hdev, initial_values, drv_data->led_count);
+       sony_set_leds(sc, initial_values, sc->led_count);
 
        name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1;
 
-       for (n = 0; n < drv_data->led_count; n++) {
+       for (n = 0; n < sc->led_count; n++) {
 
-               if (use_colors)
-                       name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2;
+               if (use_ds4_names)
+                       name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2;
 
                led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
                if (!led) {
@@ -1213,30 +1360,35 @@ static int sony_leds_init(struct hid_device *hdev)
                }
 
                name = (void *)(&led[1]);
-               if (use_colors)
-                       snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]);
+               if (use_ds4_names)
+                       snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev),
+                       ds4_name_str[n]);
                else
                        snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
                led->name = name;
-               led->brightness = 0;
-               led->max_brightness = max_brightness;
+               led->brightness = initial_values[n];
+               led->max_brightness = max_brightness[n];
                led->brightness_get = sony_led_get_brightness;
                led->brightness_set = sony_led_set_brightness;
 
+               if (use_hw_blink[n])
+                       led->blink_set = sony_led_blink_set;
+
+               sc->leds[n] = led;
+
                ret = led_classdev_register(&hdev->dev, led);
                if (ret) {
                        hid_err(hdev, "Failed to register LED %d\n", n);
+                       sc->leds[n] = NULL;
                        kfree(led);
                        goto error_leds;
                }
-
-               drv_data->leds[n] = led;
        }
 
        return ret;
 
 error_leds:
-       sony_leds_remove(hdev);
+       sony_leds_remove(sc);
 
        return ret;
 }
@@ -1244,29 +1396,52 @@ error_leds:
 static void sixaxis_state_worker(struct work_struct *work)
 {
        struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
-       unsigned char buf[] = {
-               0x01,
-               0x00, 0xff, 0x00, 0xff, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00,
-               0xff, 0x27, 0x10, 0x00, 0x32,
-               0xff, 0x27, 0x10, 0x00, 0x32,
-               0xff, 0x27, 0x10, 0x00, 0x32,
-               0xff, 0x27, 0x10, 0x00, 0x32,
-               0x00, 0x00, 0x00, 0x00, 0x00
+       int n;
+       union sixaxis_output_report_01 report = {
+               .buf = {
+                       0x01,
+                       0x00, 0xff, 0x00, 0xff, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xff, 0x27, 0x10, 0x00, 0x32,
+                       0xff, 0x27, 0x10, 0x00, 0x32,
+                       0xff, 0x27, 0x10, 0x00, 0x32,
+                       0xff, 0x27, 0x10, 0x00, 0x32,
+                       0x00, 0x00, 0x00, 0x00, 0x00
+               }
        };
 
 #ifdef CONFIG_SONY_FF
-       buf[3] = sc->right ? 1 : 0;
-       buf[5] = sc->left;
+       report.data.rumble.right_motor_on = sc->right ? 1 : 0;
+       report.data.rumble.left_motor_force = sc->left;
 #endif
 
-       buf[10] |= sc->led_state[0] << 1;
-       buf[10] |= sc->led_state[1] << 2;
-       buf[10] |= sc->led_state[2] << 3;
-       buf[10] |= sc->led_state[3] << 4;
+       report.data.leds_bitmap |= sc->led_state[0] << 1;
+       report.data.leds_bitmap |= sc->led_state[1] << 2;
+       report.data.leds_bitmap |= sc->led_state[2] << 3;
+       report.data.leds_bitmap |= sc->led_state[3] << 4;
+
+       /* Set flag for all leds off, required for 3rd party INTEC controller */
+       if ((report.data.leds_bitmap & 0x1E) == 0)
+               report.data.leds_bitmap |= 0x20;
 
-       hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
-                       HID_REQ_SET_REPORT);
+       /*
+        * The LEDs in the report are indexed in reverse order to their
+        * corresponding light on the controller.
+        * Index 0 = LED 4, index 1 = LED 3, etc...
+        *
+        * In the case of both delay values being zero (blinking disabled) the
+        * default report values should be used or the controller LED will be
+        * always off.
+        */
+       for (n = 0; n < 4; n++) {
+               if (sc->led_delay_on[n] || sc->led_delay_off[n]) {
+                       report.data.led[3 - n].duty_off = sc->led_delay_off[n];
+                       report.data.led[3 - n].duty_on = sc->led_delay_on[n];
+               }
+       }
+
+       hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf,
+                       sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
 }
 
 static void dualshock4_state_worker(struct work_struct *work)
@@ -1279,7 +1454,7 @@ static void dualshock4_state_worker(struct work_struct *work)
 
        if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
                buf[0] = 0x05;
-               buf[1] = 0x03;
+               buf[1] = 0xFF;
                offset = 4;
        } else {
                buf[0] = 0x11;
@@ -1295,9 +1470,18 @@ static void dualshock4_state_worker(struct work_struct *work)
        offset += 2;
 #endif
 
-       buf[offset++] = sc->led_state[0];
-       buf[offset++] = sc->led_state[1];
-       buf[offset++] = sc->led_state[2];
+       /* LED 3 is the global control */
+       if (sc->led_state[3]) {
+               buf[offset++] = sc->led_state[0];
+               buf[offset++] = sc->led_state[1];
+               buf[offset++] = sc->led_state[2];
+       } else {
+               offset += 3;
+       }
+
+       /* If both delay values are zero the DualShock 4 disables blinking. */
+       buf[offset++] = sc->led_delay_on[3];
+       buf[offset++] = sc->led_delay_off[3];
 
        if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
                hid_hw_output_report(hdev, buf, 32);
@@ -1323,9 +1507,9 @@ static int sony_play_effect(struct input_dev *dev, void *data,
        return 0;
 }
 
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_init_ff(struct sony_sc *sc)
 {
-       struct hid_input *hidinput = list_entry(hdev->inputs.next,
+       struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
                                                struct hid_input, list);
        struct input_dev *input_dev = hidinput->input;
 
@@ -1334,7 +1518,7 @@ static int sony_init_ff(struct hid_device *hdev)
 }
 
 #else
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_init_ff(struct sony_sc *sc)
 {
        return 0;
 }
@@ -1384,8 +1568,6 @@ static int sony_battery_get_property(struct power_supply *psy,
 
 static int sony_battery_probe(struct sony_sc *sc)
 {
-       static atomic_t power_id_seq = ATOMIC_INIT(0);
-       unsigned long power_id;
        struct hid_device *hdev = sc->hdev;
        int ret;
 
@@ -1395,15 +1577,13 @@ static int sony_battery_probe(struct sony_sc *sc)
         */
        sc->battery_capacity = 100;
 
-       power_id = (unsigned long)atomic_inc_return(&power_id_seq);
-
        sc->battery.properties = sony_battery_props;
        sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
        sc->battery.get_property = sony_battery_get_property;
        sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
        sc->battery.use_for_apm = 0;
-       sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
-                                    power_id);
+       sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR",
+                                    sc->mac_address);
        if (!sc->battery.name)
                return -ENOMEM;
 
@@ -1578,6 +1758,52 @@ static int sony_check_add(struct sony_sc *sc)
        return sony_check_add_dev_list(sc);
 }
 
+static int sony_set_device_id(struct sony_sc *sc)
+{
+       int ret;
+
+       /*
+        * Only DualShock 4 or Sixaxis controllers get an id.
+        * All others are set to -1.
+        */
+       if ((sc->quirks & SIXAXIS_CONTROLLER) ||
+           (sc->quirks & DUALSHOCK4_CONTROLLER)) {
+               ret = ida_simple_get(&sony_device_id_allocator, 0, 0,
+                                       GFP_KERNEL);
+               if (ret < 0) {
+                       sc->device_id = -1;
+                       return ret;
+               }
+               sc->device_id = ret;
+       } else {
+               sc->device_id = -1;
+       }
+
+       return 0;
+}
+
+static void sony_release_device_id(struct sony_sc *sc)
+{
+       if (sc->device_id >= 0) {
+               ida_simple_remove(&sony_device_id_allocator, sc->device_id);
+               sc->device_id = -1;
+       }
+}
+
+static inline void sony_init_work(struct sony_sc *sc,
+                                       void (*worker)(struct work_struct *))
+{
+       if (!sc->worker_initialized)
+               INIT_WORK(&sc->state_worker, worker);
+
+       sc->worker_initialized = 1;
+}
+
+static inline void sony_cancel_work_sync(struct sony_sc *sc)
+{
+       if (sc->worker_initialized)
+               cancel_work_sync(&sc->state_worker);
+}
 
 static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
@@ -1615,6 +1841,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return ret;
        }
 
+       ret = sony_set_device_id(sc);
+       if (ret < 0) {
+               hid_err(hdev, "failed to allocate the device id\n");
+               goto err_stop;
+       }
+
        if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
                /*
                 * The Sony Sixaxis does not handle HID Output Reports on the
@@ -1629,8 +1861,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
                hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
                ret = sixaxis_set_operational_usb(hdev);
-               sc->worker_initialized = 1;
-               INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+               sony_init_work(sc, sixaxis_state_worker);
        } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
                /*
                 * The Sixaxis wants output reports sent on the ctrl endpoint
@@ -1638,8 +1869,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                 */
                hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
                ret = sixaxis_set_operational_bt(hdev);
-               sc->worker_initialized = 1;
-               INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+               sony_init_work(sc, sixaxis_state_worker);
        } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
                if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
                        /*
@@ -1661,8 +1891,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                if (ret < 0)
                        goto err_stop;
 
-               sc->worker_initialized = 1;
-               INIT_WORK(&sc->state_worker, dualshock4_state_worker);
+               sony_init_work(sc, dualshock4_state_worker);
        } else {
                ret = 0;
        }
@@ -1675,7 +1904,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto err_stop;
 
        if (sc->quirks & SONY_LED_SUPPORT) {
-               ret = sony_leds_init(hdev);
+               ret = sony_leds_init(sc);
                if (ret < 0)
                        goto err_stop;
        }
@@ -1694,7 +1923,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        }
 
        if (sc->quirks & SONY_FF_SUPPORT) {
-               ret = sony_init_ff(hdev);
+               ret = sony_init_ff(sc);
                if (ret < 0)
                        goto err_close;
        }
@@ -1704,12 +1933,12 @@ err_close:
        hid_hw_close(hdev);
 err_stop:
        if (sc->quirks & SONY_LED_SUPPORT)
-               sony_leds_remove(hdev);
+               sony_leds_remove(sc);
        if (sc->quirks & SONY_BATTERY_SUPPORT)
                sony_battery_remove(sc);
-       if (sc->worker_initialized)
-               cancel_work_sync(&sc->state_worker);
+       sony_cancel_work_sync(sc);
        sony_remove_dev_list(sc);
+       sony_release_device_id(sc);
        hid_hw_stop(hdev);
        return ret;
 }
@@ -1719,18 +1948,19 @@ static void sony_remove(struct hid_device *hdev)
        struct sony_sc *sc = hid_get_drvdata(hdev);
 
        if (sc->quirks & SONY_LED_SUPPORT)
-               sony_leds_remove(hdev);
+               sony_leds_remove(sc);
 
        if (sc->quirks & SONY_BATTERY_SUPPORT) {
                hid_hw_close(hdev);
                sony_battery_remove(sc);
        }
 
-       if (sc->worker_initialized)
-               cancel_work_sync(&sc->state_worker);
+       sony_cancel_work_sync(sc);
 
        sony_remove_dev_list(sc);
 
+       sony_release_device_id(sc);
+
        hid_hw_stop(hdev);
 }
 
@@ -1775,6 +2005,22 @@ static struct hid_driver sony_driver = {
        .report_fixup  = sony_report_fixup,
        .raw_event     = sony_raw_event
 };
-module_hid_driver(sony_driver);
+
+static int __init sony_init(void)
+{
+       dbg_hid("Sony:%s\n", __func__);
+
+       return hid_register_driver(&sony_driver);
+}
+
+static void __exit sony_exit(void)
+{
+       dbg_hid("Sony:%s\n", __func__);
+
+       ida_destroy(&sony_device_id_allocator);
+       hid_unregister_driver(&sony_driver);
+}
+module_init(sony_init);
+module_exit(sony_exit);
 
 MODULE_LICENSE("GPL");
index a97c78845f7b19ef6222a5152a812bd23b56951a..31de890d14cf479cbb6cd7ddb9a83b0881c308ef 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ThingM blink(1) USB RGB LED driver
  *
- * Copyright 2013 Savoir-faire Linux Inc.
+ * Copyright 2013-2014 Savoir-faire Linux Inc.
  *     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or
  */
 
 #include <linux/hid.h>
+#include <linux/hidraw.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
 
 #include "hid-ids.h"
 
-#define BLINK1_CMD_SIZE                9
+#define REPORT_ID      1
+#define REPORT_SIZE    9
 
-#define blink1_rgb_to_r(rgb)   ((rgb & 0xFF0000) >> 16)
-#define blink1_rgb_to_g(rgb)   ((rgb & 0x00FF00) >> 8)
-#define blink1_rgb_to_b(rgb)   ((rgb & 0x0000FF) >> 0)
+/* Firmware major number of supported devices */
+#define THINGM_MAJOR_MK1       '1'
+#define THINGM_MAJOR_MK2       '2'
 
-/**
- * struct blink1_data - blink(1) device specific data
- * @hdev:              HID device.
- * @led_cdev:          LED class instance.
- * @rgb:               8-bit per channel RGB notation.
- * @fade:              fade time in hundredths of a second.
- * @brightness:                brightness coefficient.
- * @play:              play/pause in-memory patterns.
- */
-struct blink1_data {
+struct thingm_fwinfo {
+       char major;
+       unsigned numrgb;
+       unsigned first;
+};
+
+const struct thingm_fwinfo thingm_fwinfo[] = {
+       {
+               .major = THINGM_MAJOR_MK1,
+               .numrgb = 1,
+               .first = 0,
+       }, {
+               .major = THINGM_MAJOR_MK2,
+               .numrgb = 2,
+               .first = 1,
+       }
+};
+
+/* A red, green or blue channel, part of an RGB chip */
+struct thingm_led {
+       struct thingm_rgb *rgb;
+       struct led_classdev ldev;
+       char name[32];
+};
+
+/* Basically a WS2812 5050 RGB LED chip */
+struct thingm_rgb {
+       struct thingm_device *tdev;
+       struct thingm_led red;
+       struct thingm_led green;
+       struct thingm_led blue;
+       struct work_struct work;
+       u8 num;
+};
+
+struct thingm_device {
        struct hid_device *hdev;
-       struct led_classdev led_cdev;
-       u32 rgb;
-       u16 fade;
-       u8 brightness;
-       bool play;
+       struct {
+               char major;
+               char minor;
+       } version;
+       const struct thingm_fwinfo *fwinfo;
+       struct mutex lock;
+       struct thingm_rgb *rgb;
 };
 
-static int blink1_send_command(struct blink1_data *data,
-               u8 buf[BLINK1_CMD_SIZE])
+static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
 {
        int ret;
 
-       hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
+       hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
                        buf[0], buf[1], buf[2], buf[3], buf[4],
                        buf[5], buf[6], buf[7], buf[8]);
 
-       ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
-                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 
        return ret < 0 ? ret : 0;
 }
 
-static int blink1_update_color(struct blink1_data *data)
+static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
 {
-       u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 };
-
-       if (data->brightness) {
-               unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
+       int ret;
 
-               buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef);
-               buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef);
-               buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
-       }
+       ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+                       HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+       if (ret < 0)
+               return ret;
 
-       if (data->fade) {
-               buf[1] = 'c';
-               buf[5] = (data->fade & 0xFF00) >> 8;
-               buf[6] = (data->fade & 0x00FF);
-       }
+       hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
+                       buf[0], buf[1], buf[2], buf[3], buf[4],
+                       buf[5], buf[6], buf[7], buf[8]);
 
-       return blink1_send_command(data, buf);
+       return 0;
 }
 
-static void blink1_led_set(struct led_classdev *led_cdev,
-               enum led_brightness brightness)
+static int thingm_version(struct thingm_device *tdev)
 {
-       struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+       u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
+       int err;
 
-       data->brightness = brightness;
-       if (blink1_update_color(data))
-               hid_err(data->hdev, "failed to update color\n");
-}
+       err = thingm_send(tdev, buf);
+       if (err)
+               return err;
 
-static enum led_brightness blink1_led_get(struct led_classdev *led_cdev)
-{
-       struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+       err = thingm_recv(tdev, buf);
+       if (err)
+               return err;
 
-       return data->brightness;
+       tdev->version.major = buf[3];
+       tdev->version.minor = buf[4];
+
+       return 0;
 }
 
-static ssize_t blink1_show_rgb(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static int thingm_write_color(struct thingm_rgb *rgb)
 {
-       struct blink1_data *data = dev_get_drvdata(dev->parent);
+       u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
 
-       return sprintf(buf, "%.6X\n", data->rgb);
+       buf[2] = rgb->red.ldev.brightness;
+       buf[3] = rgb->green.ldev.brightness;
+       buf[4] = rgb->blue.ldev.brightness;
+
+       return thingm_send(rgb->tdev, buf);
 }
 
-static ssize_t blink1_store_rgb(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+static void thingm_work(struct work_struct *work)
 {
-       struct blink1_data *data = dev_get_drvdata(dev->parent);
-       long unsigned int rgb;
-       int ret;
+       struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work);
 
-       ret = kstrtoul(buf, 16, &rgb);
-       if (ret)
-               return ret;
-
-       /* RGB triplet notation is 24-bit hexadecimal */
-       if (rgb > 0xFFFFFF)
-               return -EINVAL;
+       mutex_lock(&rgb->tdev->lock);
 
-       data->rgb = rgb;
-       ret = blink1_update_color(data);
+       if (thingm_write_color(rgb))
+               hid_err(rgb->tdev->hdev, "failed to write color\n");
 
-       return ret ? ret : count;
+       mutex_unlock(&rgb->tdev->lock);
 }
 
-static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
-
-static ssize_t blink1_show_fade(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static void thingm_led_set(struct led_classdev *ldev,
+               enum led_brightness brightness)
 {
-       struct blink1_data *data = dev_get_drvdata(dev->parent);
+       struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
 
-       return sprintf(buf, "%d\n", data->fade * 10);
+       /* the ledclass has already stored the brightness value */
+       schedule_work(&led->rgb->work);
 }
 
-static ssize_t blink1_store_fade(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+static int thingm_init_rgb(struct thingm_rgb *rgb)
 {
-       struct blink1_data *data = dev_get_drvdata(dev->parent);
-       long unsigned int fade;
-       int ret;
+       const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
+       int err;
+
+       /* Register the red diode */
+       snprintf(rgb->red.name, sizeof(rgb->red.name),
+                       "thingm%d:red:led%d", minor, rgb->num);
+       rgb->red.ldev.name = rgb->red.name;
+       rgb->red.ldev.max_brightness = 255;
+       rgb->red.ldev.brightness_set = thingm_led_set;
+       rgb->red.rgb = rgb;
+
+       err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->red.ldev);
+       if (err)
+               return err;
+
+       /* Register the green diode */
+       snprintf(rgb->green.name, sizeof(rgb->green.name),
+                       "thingm%d:green:led%d", minor, rgb->num);
+       rgb->green.ldev.name = rgb->green.name;
+       rgb->green.ldev.max_brightness = 255;
+       rgb->green.ldev.brightness_set = thingm_led_set;
+       rgb->green.rgb = rgb;
+
+       err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->green.ldev);
+       if (err)
+               goto unregister_red;
+
+       /* Register the blue diode */
+       snprintf(rgb->blue.name, sizeof(rgb->blue.name),
+                       "thingm%d:blue:led%d", minor, rgb->num);
+       rgb->blue.ldev.name = rgb->blue.name;
+       rgb->blue.ldev.max_brightness = 255;
+       rgb->blue.ldev.brightness_set = thingm_led_set;
+       rgb->blue.rgb = rgb;
+
+       err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->blue.ldev);
+       if (err)
+               goto unregister_green;
+
+       INIT_WORK(&rgb->work, thingm_work);
 
-       ret = kstrtoul(buf, 10, &fade);
-       if (ret)
-               return ret;
+       return 0;
 
-       /* blink(1) accepts 16-bit fade time, number of 10ms ticks */
-       fade = DIV_ROUND_CLOSEST(fade, 10);
-       if (fade > 65535)
-               return -EINVAL;
+unregister_green:
+       led_classdev_unregister(&rgb->green.ldev);
 
-       data->fade = fade;
+unregister_red:
+       led_classdev_unregister(&rgb->red.ldev);
 
-       return count;
+       return err;
 }
 
-static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
-               blink1_show_fade, blink1_store_fade);
-
-static ssize_t blink1_show_play(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static void thingm_remove_rgb(struct thingm_rgb *rgb)
 {
-       struct blink1_data *data = dev_get_drvdata(dev->parent);
-
-       return sprintf(buf, "%d\n", data->play);
+       flush_work(&rgb->work);
+       led_classdev_unregister(&rgb->red.ldev);
+       led_classdev_unregister(&rgb->green.ldev);
+       led_classdev_unregister(&rgb->blue.ldev);
 }
 
-static ssize_t blink1_store_play(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-       struct blink1_data *data = dev_get_drvdata(dev->parent);
-       u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 };
-       long unsigned int play;
-       int ret;
+       struct thingm_device *tdev;
+       int i, err;
 
-       ret = kstrtoul(buf, 10, &play);
-       if (ret)
-               return ret;
+       tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
+                       GFP_KERNEL);
+       if (!tdev)
+               return -ENOMEM;
 
-       data->play = !!play;
-       cmd[2] = data->play;
-       ret = blink1_send_command(data, cmd);
+       tdev->hdev = hdev;
+       hid_set_drvdata(hdev, tdev);
 
-       return ret ? ret : count;
-}
-
-static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
-               blink1_show_play, blink1_store_play);
+       err = hid_parse(hdev);
+       if (err)
+               goto error;
 
-static const struct attribute_group blink1_sysfs_group = {
-       .attrs = (struct attribute *[]) {
-               &dev_attr_rgb.attr,
-               &dev_attr_fade.attr,
-               &dev_attr_play.attr,
-               NULL
-       },
-};
+       err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+       if (err)
+               goto error;
 
-static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
-       struct blink1_data *data;
-       struct led_classdev *led;
-       char led_name[13];
-       int ret;
+       mutex_init(&tdev->lock);
 
-       data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
+       err = thingm_version(tdev);
+       if (err)
+               goto stop;
 
-       hid_set_drvdata(hdev, data);
-       data->hdev = hdev;
-       data->rgb = 0xFFFFFF; /* set a default white color */
+       hid_dbg(hdev, "firmware version: %c.%c\n",
+                       tdev->version.major, tdev->version.minor);
 
-       ret = hid_parse(hdev);
-       if (ret)
-               goto error;
+       for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
+               if (thingm_fwinfo[i].major == tdev->version.major)
+                       tdev->fwinfo = &thingm_fwinfo[i];
 
-       ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
-       if (ret)
-               goto error;
+       if (!tdev->fwinfo) {
+               hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
+               goto stop;
+       }
 
-       /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */
-       led = &data->led_cdev;
-       snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4);
-       led->name = led_name;
-       led->brightness_set = blink1_led_set;
-       led->brightness_get = blink1_led_get;
-       ret = led_classdev_register(&hdev->dev, led);
-       if (ret)
+       tdev->rgb = devm_kzalloc(&hdev->dev,
+                       sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
+                       GFP_KERNEL);
+       if (!tdev->rgb) {
+               err = -ENOMEM;
                goto stop;
+       }
 
-       ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group);
-       if (ret)
-               goto remove_led;
+       for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
+               struct thingm_rgb *rgb = tdev->rgb + i;
+
+               rgb->tdev = tdev;
+               rgb->num = tdev->fwinfo->first + i;
+               err = thingm_init_rgb(rgb);
+               if (err) {
+                       while (--i >= 0)
+                               thingm_remove_rgb(tdev->rgb + i);
+                       goto stop;
+               }
+       }
 
        return 0;
-
-remove_led:
-       led_classdev_unregister(led);
 stop:
        hid_hw_stop(hdev);
 error:
-       return ret;
+       return err;
 }
 
 static void thingm_remove(struct hid_device *hdev)
 {
-       struct blink1_data *data = hid_get_drvdata(hdev);
-       struct led_classdev *led = &data->led_cdev;
+       struct thingm_device *tdev = hid_get_drvdata(hdev);
+       int i;
+
+       for (i = 0; i < tdev->fwinfo->numrgb; ++i)
+               thingm_remove_rgb(tdev->rgb + i);
 
-       sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group);
-       led_classdev_unregister(led);
        hid_hw_stop(hdev);
 }
 
index 6d02e3b063756f6225078df7e00f981478ef5f45..d76f0b70c6e09a0dd4bf52d77df7aa85651377c9 100644 (file)
@@ -365,12 +365,12 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
                if (cpu_has_tjmax(c))
                        dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
        } else {
-               val = (eax >> 16) & 0x7f;
+               val = (eax >> 16) & 0xff;
                /*
                 * If the TjMax is not plausible, an assumption
                 * will be used
                 */
-               if (val >= 85) {
+               if (val) {
                        dev_dbg(dev, "TjMax is %d degrees C\n", val);
                        return val * 1000;
                }
index 32f5132c4652d43b89037f9ec16934d5f4d685f4..9e57b77ecd34ef3367ed64b4105c5ce65e3c724f 100644 (file)
@@ -1387,10 +1387,8 @@ static int f71805f_probe(struct platform_device *pdev)
 
        data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data),
                            GFP_KERNEL);
-       if (!data) {
-               pr_err("Out of memory\n");
+       if (!data)
                return -ENOMEM;
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2,
index 20ab0fb85395c8bcf9314cf825655c5153e04a65..030e7ff589be9558033ad8283537133c9c72dcf0 100644 (file)
@@ -463,10 +463,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
        int err;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "Insufficient memory for BMC interface.\n");
+       if (!data)
                return;
-       }
 
        data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
        data->address.channel = IPMI_BMC_CHANNEL;
index 505a59e100b0b9a80b099aa8a9abd43fa5ec2220..97204dce162db6a5d3ff4ae703e58b6164683aff 100644 (file)
@@ -47,7 +47,7 @@
 #define LM70_CHIP_LM74         3       /* NS LM74 */
 
 struct lm70 {
-       struct device *hwmon_dev;
+       struct spi_device *spi;
        struct mutex lock;
        unsigned int chip;
 };
@@ -56,11 +56,11 @@ struct lm70 {
 static ssize_t lm70_sense_temp(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct spi_device *spi = to_spi_device(dev);
+       struct lm70 *p_lm70 = dev_get_drvdata(dev);
+       struct spi_device *spi = p_lm70->spi;
        int status, val = 0;
        u8 rxbuf[2];
        s16 raw = 0;
-       struct lm70 *p_lm70 = spi_get_drvdata(spi);
 
        if (mutex_lock_interruptible(&p_lm70->lock))
                return -ERESTARTSYS;
@@ -121,21 +121,20 @@ out:
 
 static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
 
-static ssize_t lm70_show_name(struct device *dev, struct device_attribute
-                             *devattr, char *buf)
-{
-       return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
-}
+static struct attribute *lm70_attrs[] = {
+       &dev_attr_temp1_input.attr,
+       NULL
+};
 
-static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
+ATTRIBUTE_GROUPS(lm70);
 
 /*----------------------------------------------------------------------*/
 
 static int lm70_probe(struct spi_device *spi)
 {
        int chip = spi_get_device_id(spi)->driver_data;
+       struct device *hwmon_dev;
        struct lm70 *p_lm70;
-       int status;
 
        /* signaling is SPI_MODE_0 */
        if (spi->mode & (SPI_CPOL | SPI_CPHA))
@@ -149,46 +148,14 @@ static int lm70_probe(struct spi_device *spi)
 
        mutex_init(&p_lm70->lock);
        p_lm70->chip = chip;
+       p_lm70->spi = spi;
 
-       spi_set_drvdata(spi, p_lm70);
-
-       status = device_create_file(&spi->dev, &dev_attr_temp1_input);
-       if (status)
-               goto out_dev_create_temp_file_failed;
-       status = device_create_file(&spi->dev, &dev_attr_name);
-       if (status)
-               goto out_dev_create_file_failed;
-
-       /* sysfs hook */
-       p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
-       if (IS_ERR(p_lm70->hwmon_dev)) {
-               dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
-               status = PTR_ERR(p_lm70->hwmon_dev);
-               goto out_dev_reg_failed;
-       }
-
-       return 0;
-
-out_dev_reg_failed:
-       device_remove_file(&spi->dev, &dev_attr_name);
-out_dev_create_file_failed:
-       device_remove_file(&spi->dev, &dev_attr_temp1_input);
-out_dev_create_temp_file_failed:
-       return status;
+       hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev,
+                                                          spi->modalias,
+                                                          p_lm70, lm70_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
-static int lm70_remove(struct spi_device *spi)
-{
-       struct lm70 *p_lm70 = spi_get_drvdata(spi);
-
-       hwmon_device_unregister(p_lm70->hwmon_dev);
-       device_remove_file(&spi->dev, &dev_attr_temp1_input);
-       device_remove_file(&spi->dev, &dev_attr_name);
-
-       return 0;
-}
-
-
 static const struct spi_device_id lm70_ids[] = {
        { "lm70",   LM70_CHIP_LM70 },
        { "tmp121", LM70_CHIP_TMP121 },
@@ -205,7 +172,6 @@ static struct spi_driver lm70_driver = {
        },
        .id_table = lm70_ids,
        .probe  = lm70_probe,
-       .remove = lm70_remove,
 };
 
 module_spi_driver(lm70_driver);
index 84a55eacd9034a3ecb470c00a6382007e9a0f779..479ffbeed3f8a0c2d3adb1c9f132e43f5a6a9c57 100644 (file)
@@ -72,6 +72,7 @@ static const u8 LM75_REG_TEMP[3] = {
 
 /* Each client has this additional data */
 struct lm75_data {
+       struct i2c_client       *client;
        struct device           *hwmon_dev;
        struct thermal_zone_device      *tz;
        struct mutex            update_lock;
@@ -130,8 +131,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
                        const char *buf, size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm75_data *data = i2c_get_clientdata(client);
+       struct lm75_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int nr = attr->index;
        long temp;
        int error;
@@ -165,17 +166,14 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
                        show_temp, set_temp, 2);
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
 
-static struct attribute *lm75_attributes[] = {
+static struct attribute *lm75_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 
        NULL
 };
-
-static const struct attribute_group lm75_group = {
-       .attrs = lm75_attributes,
-};
+ATTRIBUTE_GROUPS(lm75);
 
 /*-----------------------------------------------------------------------*/
 
@@ -184,6 +182,7 @@ static const struct attribute_group lm75_group = {
 static int
 lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        struct lm75_data *data;
        int status;
        u8 set_mask, clr_mask;
@@ -194,10 +193,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
                        I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
                return -EIO;
 
-       data = devm_kzalloc(&client->dev, sizeof(struct lm75_data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
+       data->client = client;
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
 
@@ -269,7 +269,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* configure as specified */
        status = lm75_read_value(client, LM75_REG_CONF);
        if (status < 0) {
-               dev_dbg(&client->dev, "Can't read config? %d\n", status);
+               dev_dbg(dev, "Can't read config? %d\n", status);
                return status;
        }
        data->orig_conf = status;
@@ -277,43 +277,32 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
        new |= set_mask;
        if (status != new)
                lm75_write_value(client, LM75_REG_CONF, new);
-       dev_dbg(&client->dev, "Config %02x\n", new);
+       dev_dbg(dev, "Config %02x\n", new);
 
-       /* Register sysfs hooks */
-       status = sysfs_create_group(&client->dev.kobj, &lm75_group);
-       if (status)
-               return status;
+       data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+                                                           data, lm75_groups);
+       if (IS_ERR(data->hwmon_dev))
+               return PTR_ERR(data->hwmon_dev);
 
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               status = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       data->tz = thermal_zone_of_sensor_register(&client->dev,
+       data->tz = thermal_zone_of_sensor_register(data->hwmon_dev,
                                                   0,
-                                                  &client->dev,
+                                                  data->hwmon_dev,
                                                   lm75_read_temp, NULL);
        if (IS_ERR(data->tz))
                data->tz = NULL;
 
-       dev_info(&client->dev, "%s: sensor '%s'\n",
+       dev_info(dev, "%s: sensor '%s'\n",
                 dev_name(data->hwmon_dev), client->name);
 
        return 0;
-
-exit_remove:
-       sysfs_remove_group(&client->dev.kobj, &lm75_group);
-       return status;
 }
 
 static int lm75_remove(struct i2c_client *client)
 {
        struct lm75_data *data = i2c_get_clientdata(client);
 
-       thermal_zone_of_sensor_unregister(&client->dev, data->tz);
+       thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz);
        hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &lm75_group);
        lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
        return 0;
 }
@@ -507,8 +496,8 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
 
 static struct lm75_data *lm75_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm75_data *data = i2c_get_clientdata(client);
+       struct lm75_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        struct lm75_data *ret = data;
 
        mutex_lock(&data->update_lock);
index 502771c06fd99e73ce6bc9b51e5d3413fdc6d95f..5ceb443b938d77b716a5c0e1aecba469becce6e7 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -47,50 +43,33 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
 #define LM77_REG_TEMP_MIN      0x04
 #define LM77_REG_TEMP_MAX      0x05
 
+enum temp_index {
+       t_input = 0,
+       t_crit,
+       t_min,
+       t_max,
+       t_hyst,
+       t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+       [t_input] = LM77_REG_TEMP,
+       [t_min] = LM77_REG_TEMP_MIN,
+       [t_max] = LM77_REG_TEMP_MAX,
+       [t_crit] = LM77_REG_TEMP_CRIT,
+       [t_hyst] = LM77_REG_TEMP_HYST,
+};
+
 /* Each client has this additional data */
 struct lm77_data {
-       struct device           *hwmon_dev;
+       struct i2c_client       *client;
        struct mutex            update_lock;
        char                    valid;
        unsigned long           last_updated;   /* In jiffies */
-       int                     temp_input;     /* Temperatures */
-       int                     temp_crit;
-       int                     temp_min;
-       int                     temp_max;
-       int                     temp_hyst;
+       int                     temp[t_num_temp]; /* index using temp_index */
        u8                      alarms;
 };
 
-static int lm77_probe(struct i2c_client *client,
-                     const struct i2c_device_id *id);
-static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info);
-static void lm77_init_client(struct i2c_client *client);
-static int lm77_remove(struct i2c_client *client);
-static u16 lm77_read_value(struct i2c_client *client, u8 reg);
-static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value);
-
-static struct lm77_data *lm77_update_device(struct device *dev);
-
-
-static const struct i2c_device_id lm77_id[] = {
-       { "lm77", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, lm77_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver lm77_driver = {
-       .class          = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "lm77",
-       },
-       .probe          = lm77_probe,
-       .remove         = lm77_remove,
-       .id_table       = lm77_id,
-       .detect         = lm77_detect,
-       .address_list   = normal_i2c,
-};
-
 /* straight from the datasheet */
 #define LM77_TEMP_MIN (-55000)
 #define LM77_TEMP_MAX 125000
@@ -110,97 +89,109 @@ static inline int LM77_TEMP_FROM_REG(s16 reg)
        return (reg / 8) * 500;
 }
 
-/* sysfs stuff */
-
-/* read routines for temperature limits */
-#define show(value)    \
-static ssize_t show_##value(struct device *dev,                        \
-                           struct device_attribute *attr,      \
-                           char *buf)                          \
-{                                                              \
-       struct lm77_data *data = lm77_update_device(dev);       \
-       return sprintf(buf, "%d\n", data->value);               \
+/*
+ * All registers are word-sized, except for the configuration register.
+ * The LM77 uses the high-byte first convention.
+ */
+static u16 lm77_read_value(struct i2c_client *client, u8 reg)
+{
+       if (reg == LM77_REG_CONF)
+               return i2c_smbus_read_byte_data(client, reg);
+       else
+               return i2c_smbus_read_word_swapped(client, reg);
 }
 
-show(temp_input);
-show(temp_crit);
-show(temp_min);
-show(temp_max);
+static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+       if (reg == LM77_REG_CONF)
+               return i2c_smbus_write_byte_data(client, reg, value);
+       else
+               return i2c_smbus_write_word_swapped(client, reg, value);
+}
 
-/* read routines for hysteresis values */
-static ssize_t show_temp_crit_hyst(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static struct lm77_data *lm77_update_device(struct device *dev)
 {
-       struct lm77_data *data = lm77_update_device(dev);
-       return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst);
+       struct lm77_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               dev_dbg(&client->dev, "Starting lm77 update\n");
+               for (i = 0; i < t_num_temp; i++) {
+                       data->temp[i] =
+                         LM77_TEMP_FROM_REG(lm77_read_value(client,
+                                                            temp_regs[i]));
+               }
+               data->alarms =
+                       lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
 }
-static ssize_t show_temp_min_hyst(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
+
+/* sysfs stuff */
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm77_data *data = lm77_update_device(dev);
-       return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst);
+
+       return sprintf(buf, "%d\n", data->temp[attr->index]);
 }
-static ssize_t show_temp_max_hyst(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_hyst(struct device *dev,
+                             struct device_attribute *devattr, char *buf)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm77_data *data = lm77_update_device(dev);
-       return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst);
-}
+       int nr = attr->index;
+       int temp;
 
-/* write routines */
-#define set(value, reg)        \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
-                          const char *buf, size_t count)               \
-{                                                                      \
-       struct i2c_client *client = to_i2c_client(dev);                 \
-       struct lm77_data *data = i2c_get_clientdata(client);            \
-       long val;                                                       \
-       int err = kstrtol(buf, 10, &val);                               \
-       if (err)                                                        \
-               return err;                                             \
-                                                                       \
-       mutex_lock(&data->update_lock);                                 \
-       data->value = val;                                              \
-       lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value));   \
-       mutex_unlock(&data->update_lock);                               \
-       return count;                                                   \
-}
+       temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
+                            data->temp[nr] - data->temp[t_hyst];
 
-set(temp_min, LM77_REG_TEMP_MIN);
-set(temp_max, LM77_REG_TEMP_MAX);
+       return sprintf(buf, "%d\n", temp);
+}
 
-/*
- * hysteresis is stored as a relative value on the chip, so it has to be
- * converted first
- */
-static ssize_t set_temp_crit_hyst(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm77_data *data = i2c_get_clientdata(client);
-       unsigned long val;
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm77_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       int nr = attr->index;
+       long val;
        int err;
 
-       err = kstrtoul(buf, 10, &val);
+       err = kstrtol(buf, 10, &val);
        if (err)
                return err;
 
        mutex_lock(&data->update_lock);
-       data->temp_hyst = data->temp_crit - val;
-       lm77_write_value(client, LM77_REG_TEMP_HYST,
-                        LM77_TEMP_TO_REG(data->temp_hyst));
+       data->temp[nr] = val;
+       lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-/* preserve hysteresis when setting T_crit */
-static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
+/*
+ * hysteresis is stored as a relative value on the chip, so it has to be
+ * converted first.
+ */
+static ssize_t set_temp_hyst(struct device *dev,
+                            struct device_attribute *devattr,
                             const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm77_data *data = i2c_get_clientdata(client);
-       int oldcrithyst;
+       struct lm77_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
        int err;
 
@@ -209,13 +200,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
                return err;
 
        mutex_lock(&data->update_lock);
-       oldcrithyst = data->temp_crit - data->temp_hyst;
-       data->temp_crit = val;
-       data->temp_hyst = data->temp_crit - oldcrithyst;
-       lm77_write_value(client, LM77_REG_TEMP_CRIT,
-                        LM77_TEMP_TO_REG(data->temp_crit));
+       data->temp[t_hyst] = data->temp[t_crit] - val;
        lm77_write_value(client, LM77_REG_TEMP_HYST,
-                        LM77_TEMP_TO_REG(data->temp_hyst));
+                        LM77_TEMP_TO_REG(data->temp[t_hyst]));
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -228,43 +215,37 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
 }
 
-static DEVICE_ATTR(temp1_input, S_IRUGO,
-                  show_temp_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
-                  show_temp_crit, set_temp_crit);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
-                  show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
-                  show_temp_max, set_temp_max);
-
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
-                  show_temp_crit_hyst, set_temp_crit_hyst);
-static DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
-                  show_temp_min_hyst, NULL);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
-                  show_temp_max_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+                         t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+                         t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+                         t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+                         set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
 
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
 
-static struct attribute *lm77_attributes[] = {
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp1_crit.attr,
-       &dev_attr_temp1_min.attr,
-       &dev_attr_temp1_max.attr,
-       &dev_attr_temp1_crit_hyst.attr,
-       &dev_attr_temp1_min_hyst.attr,
-       &dev_attr_temp1_max_hyst.attr,
+static struct attribute *lm77_attrs[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
        &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        NULL
 };
-
-static const struct attribute_group lm77_group = {
-       .attrs = lm77_attributes,
-};
+ATTRIBUTE_GROUPS(lm77);
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
@@ -337,111 +318,52 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
        return 0;
 }
 
+static void lm77_init_client(struct i2c_client *client)
+{
+       /* Initialize the LM77 chip - turn off shutdown mode */
+       int conf = lm77_read_value(client, LM77_REG_CONF);
+       if (conf & 1)
+               lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
+}
+
 static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
+       struct device *hwmon_dev;
        struct lm77_data *data;
-       int err;
 
        data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, data);
+       data->client = client;
        mutex_init(&data->update_lock);
 
        /* Initialize the LM77 chip */
        lm77_init_client(client);
 
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&dev->kobj, &lm77_group);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       sysfs_remove_group(&dev->kobj, &lm77_group);
-       return err;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data, lm77_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
-static int lm77_remove(struct i2c_client *client)
-{
-       struct lm77_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &lm77_group);
-       return 0;
-}
-
-/*
- * All registers are word-sized, except for the configuration register.
- * The LM77 uses the high-byte first convention.
- */
-static u16 lm77_read_value(struct i2c_client *client, u8 reg)
-{
-       if (reg == LM77_REG_CONF)
-               return i2c_smbus_read_byte_data(client, reg);
-       else
-               return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
-{
-       if (reg == LM77_REG_CONF)
-               return i2c_smbus_write_byte_data(client, reg, value);
-       else
-               return i2c_smbus_write_word_swapped(client, reg, value);
-}
-
-static void lm77_init_client(struct i2c_client *client)
-{
-       /* Initialize the LM77 chip - turn off shutdown mode */
-       int conf = lm77_read_value(client, LM77_REG_CONF);
-       if (conf & 1)
-               lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
-}
-
-static struct lm77_data *lm77_update_device(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm77_data *data = i2c_get_clientdata(client);
-
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
-               dev_dbg(&client->dev, "Starting lm77 update\n");
-               data->temp_input =
-                       LM77_TEMP_FROM_REG(lm77_read_value(client,
-                                                          LM77_REG_TEMP));
-               data->temp_hyst =
-                       LM77_TEMP_FROM_REG(lm77_read_value(client,
-                                                          LM77_REG_TEMP_HYST));
-               data->temp_crit =
-                       LM77_TEMP_FROM_REG(lm77_read_value(client,
-                                                          LM77_REG_TEMP_CRIT));
-               data->temp_min =
-                       LM77_TEMP_FROM_REG(lm77_read_value(client,
-                                                          LM77_REG_TEMP_MIN));
-               data->temp_max =
-                       LM77_TEMP_FROM_REG(lm77_read_value(client,
-                                                          LM77_REG_TEMP_MAX));
-               data->alarms =
-                       lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
+static const struct i2c_device_id lm77_id[] = {
+       { "lm77", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm77_id);
 
-       return data;
-}
+/* This is the driver that will be inserted */
+static struct i2c_driver lm77_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "lm77",
+       },
+       .probe          = lm77_probe,
+       .id_table       = lm77_id,
+       .detect         = lm77_detect,
+       .address_list   = normal_i2c,
+};
 
 module_i2c_driver(lm77_driver);
 
index b9022db6511ae4cc8ee5851d89466725c5384d8b..d2060e245ff589f206fbf57c12e62d0038cae0fa 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -93,46 +89,53 @@ static inline u8 ALARMS_FROM_REG(s16 reg)
        return reg & 0x0007;
 }
 
-/* Driver data (common to all clients) */
-static struct i2c_driver lm92_driver;
+enum temp_index {
+       t_input,
+       t_crit,
+       t_min,
+       t_max,
+       t_hyst,
+       t_num_regs
+};
+
+static const u8 regs[t_num_regs] = {
+       [t_input] = LM92_REG_TEMP,
+       [t_crit] = LM92_REG_TEMP_CRIT,
+       [t_min] = LM92_REG_TEMP_LOW,
+       [t_max] = LM92_REG_TEMP_HIGH,
+       [t_hyst] = LM92_REG_TEMP_HYST,
+};
 
 /* Client data (each client gets its own) */
 struct lm92_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
 
        /* registers values */
-       s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst;
+       s16 temp[t_num_regs];   /* index with enum temp_index */
 };
 
-
 /*
  * Sysfs attributes and callback functions
  */
 
 static struct lm92_data *lm92_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm92_data *data = i2c_get_clientdata(client);
+       struct lm92_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       int i;
 
        mutex_lock(&data->update_lock);
 
        if (time_after(jiffies, data->last_updated + HZ)
         || !data->valid) {
                dev_dbg(&client->dev, "Updating lm92 data\n");
-               data->temp1_input = i2c_smbus_read_word_swapped(client,
-                                   LM92_REG_TEMP);
-               data->temp1_hyst = i2c_smbus_read_word_swapped(client,
-                                   LM92_REG_TEMP_HYST);
-               data->temp1_crit = i2c_smbus_read_word_swapped(client,
-                                   LM92_REG_TEMP_CRIT);
-               data->temp1_min = i2c_smbus_read_word_swapped(client,
-                                   LM92_REG_TEMP_LOW);
-               data->temp1_max = i2c_smbus_read_word_swapped(client,
-                                   LM92_REG_TEMP_HIGH);
-
+               for (i = 0; i < t_num_regs; i++) {
+                       data->temp[i] =
+                               i2c_smbus_read_word_swapped(client, regs[i]);
+               }
                data->last_updated = jiffies;
                data->valid = 1;
        }
@@ -142,68 +145,60 @@ static struct lm92_data *lm92_update_device(struct device *dev)
        return data;
 }
 
-#define show_temp(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \
-                           char *buf) \
-{ \
-       struct lm92_data *data = lm92_update_device(dev); \
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
-}
-show_temp(temp1_input);
-show_temp(temp1_crit);
-show_temp(temp1_min);
-show_temp(temp1_max);
-
-#define set_temp(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
-                          const char *buf, \
-       size_t count) \
-{ \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct lm92_data *data = i2c_get_clientdata(client); \
-       long val; \
-       int err = kstrtol(buf, 10, &val); \
-       if (err) \
-               return err; \
-\
-       mutex_lock(&data->update_lock); \
-       data->value = TEMP_TO_REG(val); \
-       i2c_smbus_write_word_swapped(client, reg, data->value); \
-       mutex_unlock(&data->update_lock); \
-       return count; \
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm92_data *data = lm92_update_device(dev);
+
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
 }
-set_temp(temp1_crit, LM92_REG_TEMP_CRIT);
-set_temp(temp1_min, LM92_REG_TEMP_LOW);
-set_temp(temp1_max, LM92_REG_TEMP_HIGH);
 
-static ssize_t show_temp1_crit_hyst(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+                          const char *buf, size_t count)
 {
-       struct lm92_data *data = lm92_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit)
-                      - TEMP_FROM_REG(data->temp1_hyst));
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm92_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       int nr = attr->index;
+       long val;
+       int err;
+       
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       mutex_lock(&data->update_lock);
+       data->temp[nr] = TEMP_TO_REG(val);
+       i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
 }
-static ssize_t show_temp1_max_hyst(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_hyst(struct device *dev,
+                             struct device_attribute *devattr, char *buf)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm92_data *data = lm92_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max)
-                      - TEMP_FROM_REG(data->temp1_hyst));
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])
+                      - TEMP_FROM_REG(data->temp[t_hyst]));
 }
-static ssize_t show_temp1_min_hyst(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_min_hyst(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
 {
        struct lm92_data *data = lm92_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min)
-                      + TEMP_FROM_REG(data->temp1_hyst));
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min])
+                      + TEMP_FROM_REG(data->temp[t_hyst]));
 }
 
-static ssize_t set_temp1_crit_hyst(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t count)
+static ssize_t set_temp_hyst(struct device *dev,
+                            struct device_attribute *devattr,
+                            const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm92_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm92_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long val;
        int err;
 
@@ -212,9 +207,9 @@ static ssize_t set_temp1_crit_hyst(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val;
+       data->temp[t_hyst] = TEMP_FROM_REG(data->temp[attr->index]) - val;
        i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST,
-                                    TEMP_TO_REG(data->temp1_hyst));
+                                    TEMP_TO_REG(data->temp[t_hyst]));
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -223,7 +218,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
        struct lm92_data *data = lm92_update_device(dev);
-       return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input));
+       return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input]));
 }
 
 static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
@@ -231,26 +226,25 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
 {
        int bitnr = to_sensor_dev_attr(attr)->index;
        struct lm92_data *data = lm92_update_device(dev);
-       return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1);
+       return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1);
 }
 
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit,
-       set_temp1_crit);
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst,
-       set_temp1_crit_hyst);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min,
-       set_temp1_min);
-static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max,
-       set_temp1_max);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+                         t_crit);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+                         set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+                         t_min);
+static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+                         t_max);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
 
-
 /*
  * Detection and registration
  */
@@ -322,24 +316,21 @@ static int max6635_check(struct i2c_client *client)
        return 1;
 }
 
-static struct attribute *lm92_attributes[] = {
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp1_crit.attr,
-       &dev_attr_temp1_crit_hyst.attr,
-       &dev_attr_temp1_min.attr,
+static struct attribute *lm92_attrs[] = {
+       &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_temp1_min.dev_attr.attr,
        &dev_attr_temp1_min_hyst.attr,
-       &dev_attr_temp1_max.attr,
-       &dev_attr_temp1_max_hyst.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
        &dev_attr_alarms.attr,
        &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        NULL
 };
-
-static const struct attribute_group lm92_group = {
-       .attrs = lm92_attributes,
-};
+ATTRIBUTE_GROUPS(lm92);
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int lm92_detect(struct i2c_client *new_client,
@@ -371,46 +362,24 @@ static int lm92_detect(struct i2c_client *new_client,
 static int lm92_probe(struct i2c_client *new_client,
                      const struct i2c_device_id *id)
 {
+       struct device *hwmon_dev;
        struct lm92_data *data;
-       int err;
 
        data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data),
                            GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(new_client, data);
+       data->client = new_client;
        mutex_init(&data->update_lock);
 
        /* Initialize the chipset */
        lm92_init_client(new_client);
 
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&new_client->dev.kobj, &lm92_group);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
-       return err;
-}
-
-static int lm92_remove(struct i2c_client *client)
-{
-       struct lm92_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &lm92_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev,
+                                                          new_client->name,
+                                                          data, lm92_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 
@@ -431,7 +400,6 @@ static struct i2c_driver lm92_driver = {
                .name   = "lm92",
        },
        .probe          = lm92_probe,
-       .remove         = lm92_remove,
        .id_table       = lm92_id,
        .detect         = lm92_detect,
        .address_list   = normal_i2c,
index adf23165a6a709ca2785cad332b8626da2a73b80..6c2df576f2530486d3acde797105ba92d7b17646 100644 (file)
@@ -2747,10 +2747,8 @@ static int lm93_probe(struct i2c_client *client,
        }
 
        data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL);
-       if (!data) {
-               dev_dbg(&client->dev, "out of memory!\n");
+       if (!data)
                return -ENOMEM;
-       }
        i2c_set_clientdata(client, data);
 
        /* housekeeping */
index eda077de8a9f726dd956f48e7e909fcc6ea8f148..f67d71ee8386a4ff8a485ec8c3a03c498dd661e5 100644 (file)
@@ -192,10 +192,8 @@ static int max1111_probe(struct spi_device *spi)
                return err;
 
        data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL);
-       if (data == NULL) {
-               dev_err(&spi->dev, "failed to allocate memory\n");
+       if (data == NULL)
                return -ENOMEM;
-       }
 
        switch (chip) {
        case max1110:
index 96dccaf919d1da4c02b26de8f937f5c401f84ff4..82128ad79a911c893e784b8a5623f1e04c4afb5a 100644 (file)
@@ -275,10 +275,8 @@ static int max197_probe(struct platform_device *pdev)
        }
 
        data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&pdev->dev, "devm_kzalloc failed\n");
+       if (!data)
                return -ENOMEM;
-       }
 
        data->pdata = pdata;
        mutex_init(&data->lock);
index d847e0a084e0f605ed4f02cc7091a4caf4631617..9e4684e747eace17b2c6d00a84d5da33553ffd93 100644 (file)
@@ -1081,10 +1081,8 @@ static int pc87427_probe(struct platform_device *pdev)
 
        data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data),
                            GFP_KERNEL);
-       if (!data) {
-               pr_err("Out of memory\n");
+       if (!data)
                return -ENOMEM;
-       }
 
        data->address[0] = sio_data->address[0];
        data->address[1] = sio_data->address[1];
index 73bd64e8c30a8bc8ad6dfdd947cf7a33bf52f142..0674c13bbd4bffe73f626cdd6881a85c3d70445e 100644 (file)
@@ -285,10 +285,8 @@ static int s3c_hwmon_probe(struct platform_device *dev)
        }
 
        hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL);
-       if (hwmon == NULL) {
-               dev_err(&dev->dev, "no memory\n");
+       if (hwmon == NULL)
                return -ENOMEM;
-       }
 
        platform_set_drvdata(dev, hwmon);
 
index 6748b4583e7b35c2381ecaa3afa29748247b4f1c..51719956cc03f52e5b25f5bb12b41725ebc3100e 100644 (file)
@@ -51,6 +51,7 @@
 #define        TMP102_THIGH_REG                0x03
 
 struct tmp102 {
+       struct i2c_client *client;
        struct device *hwmon_dev;
        struct thermal_zone_device *tz;
        struct mutex lock;
@@ -77,9 +78,10 @@ static const u8 tmp102_reg[] = {
        TMP102_THIGH_REG,
 };
 
-static struct tmp102 *tmp102_update_device(struct i2c_client *client)
+static struct tmp102 *tmp102_update_device(struct device *dev)
 {
-       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+       struct tmp102 *tmp102 = dev_get_drvdata(dev);
+       struct i2c_client *client = tmp102->client;
 
        mutex_lock(&tmp102->lock);
        if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
@@ -98,7 +100,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client)
 
 static int tmp102_read_temp(void *dev, long *temp)
 {
-       struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
+       struct tmp102 *tmp102 = tmp102_update_device(dev);
 
        *temp = tmp102->temp[0];
 
@@ -110,7 +112,7 @@ static ssize_t tmp102_show_temp(struct device *dev,
                                char *buf)
 {
        struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
-       struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
+       struct tmp102 *tmp102 = tmp102_update_device(dev);
 
        return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
 }
@@ -120,8 +122,8 @@ static ssize_t tmp102_set_temp(struct device *dev,
                               const char *buf, size_t count)
 {
        struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+       struct tmp102 *tmp102 = dev_get_drvdata(dev);
+       struct i2c_client *client = tmp102->client;
        long val;
        int status;
 
@@ -145,16 +147,13 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
 static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
                          tmp102_set_temp, 2);
 
-static struct attribute *tmp102_attributes[] = {
+static struct attribute *tmp102_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        NULL
 };
-
-static const struct attribute_group tmp102_attr_group = {
-       .attrs = tmp102_attributes,
-};
+ATTRIBUTE_GROUPS(tmp102);
 
 #define TMP102_CONFIG  (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
 #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
@@ -162,72 +161,68 @@ static const struct attribute_group tmp102_attr_group = {
 static int tmp102_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
+       struct device *hwmon_dev;
        struct tmp102 *tmp102;
        int status;
 
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_WORD_DATA)) {
-               dev_err(&client->dev,
+               dev_err(dev,
                        "adapter doesn't support SMBus word transactions\n");
                return -ENODEV;
        }
 
-       tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL);
+       tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL);
        if (!tmp102)
                return -ENOMEM;
 
        i2c_set_clientdata(client, tmp102);
+       tmp102->client = client;
 
        status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
        if (status < 0) {
-               dev_err(&client->dev, "error reading config register\n");
+               dev_err(dev, "error reading config register\n");
                return status;
        }
        tmp102->config_orig = status;
        status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
                                              TMP102_CONFIG);
        if (status < 0) {
-               dev_err(&client->dev, "error writing config register\n");
+               dev_err(dev, "error writing config register\n");
                goto fail_restore_config;
        }
        status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
        if (status < 0) {
-               dev_err(&client->dev, "error reading config register\n");
+               dev_err(dev, "error reading config register\n");
                goto fail_restore_config;
        }
        status &= ~TMP102_CONFIG_RD_ONLY;
        if (status != TMP102_CONFIG) {
-               dev_err(&client->dev, "config settings did not stick\n");
+               dev_err(dev, "config settings did not stick\n");
                status = -ENODEV;
                goto fail_restore_config;
        }
        tmp102->last_update = jiffies - HZ;
        mutex_init(&tmp102->lock);
 
-       status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group);
-       if (status) {
-               dev_dbg(&client->dev, "could not create sysfs files\n");
+       hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+                                                     tmp102, tmp102_groups);
+       if (IS_ERR(hwmon_dev)) {
+               dev_dbg(dev, "unable to register hwmon device\n");
+               status = PTR_ERR(hwmon_dev);
                goto fail_restore_config;
        }
-       tmp102->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(tmp102->hwmon_dev)) {
-               dev_dbg(&client->dev, "unable to register hwmon device\n");
-               status = PTR_ERR(tmp102->hwmon_dev);
-               goto fail_remove_sysfs;
-       }
-
-       tmp102->tz = thermal_zone_of_sensor_register(&client->dev, 0,
-                                                    &client->dev,
+       tmp102->hwmon_dev = hwmon_dev;
+       tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
                                                     tmp102_read_temp, NULL);
        if (IS_ERR(tmp102->tz))
                tmp102->tz = NULL;
 
-       dev_info(&client->dev, "initialized\n");
+       dev_info(dev, "initialized\n");
 
        return 0;
 
-fail_remove_sysfs:
-       sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
 fail_restore_config:
        i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
                                     tmp102->config_orig);
@@ -238,9 +233,8 @@ static int tmp102_remove(struct i2c_client *client)
 {
        struct tmp102 *tmp102 = i2c_get_clientdata(client);
 
-       thermal_zone_of_sensor_unregister(&client->dev, tmp102->tz);
+       thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz);
        hwmon_device_unregister(tmp102->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
 
        /* Stop monitoring if device was stopped originally */
        if (tmp102->config_orig & TMP102_CONF_SD) {
index ae26b06fa8190dd478456d12a637889c61bde0fe..7bab7a9bedc6699f7a59d9926b913505116e02f6 100644 (file)
@@ -69,7 +69,7 @@ static const struct i2c_device_id tmp421_id[] = {
 MODULE_DEVICE_TABLE(i2c, tmp421_id);
 
 struct tmp421_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex update_lock;
        char valid;
        unsigned long last_updated;
@@ -99,8 +99,8 @@ static int temp_from_u16(u16 reg)
 
 static struct tmp421_data *tmp421_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct tmp421_data *data = i2c_get_clientdata(client);
+       struct tmp421_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int i;
 
        mutex_lock(&data->update_lock);
@@ -198,6 +198,11 @@ static const struct attribute_group tmp421_group = {
        .is_visible = tmp421_is_visible,
 };
 
+static const struct attribute_group *tmp421_groups[] = {
+       &tmp421_group,
+       NULL
+};
+
 static int tmp421_init_client(struct i2c_client *client)
 {
        int config, config_orig;
@@ -264,47 +269,26 @@ static int tmp421_detect(struct i2c_client *client,
 static int tmp421_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
+       struct device *hwmon_dev;
        struct tmp421_data *data;
        int err;
 
-       data = devm_kzalloc(&client->dev, sizeof(struct tmp421_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
        data->channels = id->driver_data;
+       data->client = client;
 
        err = tmp421_init_client(client);
        if (err)
                return err;
 
-       err = sysfs_create_group(&client->dev.kobj, &tmp421_group);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               data->hwmon_dev = NULL;
-               goto exit_remove;
-       }
-       return 0;
-
-exit_remove:
-       sysfs_remove_group(&client->dev.kobj, &tmp421_group);
-       return err;
-}
-
-static int tmp421_remove(struct i2c_client *client)
-{
-       struct tmp421_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &tmp421_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data, tmp421_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static struct i2c_driver tmp421_driver = {
@@ -313,7 +297,6 @@ static struct i2c_driver tmp421_driver = {
                .name   = "tmp421",
        },
        .probe = tmp421_probe,
-       .remove = tmp421_remove,
        .id_table = tmp421_id,
        .detect = tmp421_detect,
        .address_list = normal_i2c,
index 6b2f1a42b3ff9d43f200234f6a408ad00a798170..344b22ec25533e0e39770d36aa0c87af29c815fd 100644 (file)
@@ -1152,10 +1152,8 @@ static int vt1211_probe(struct platform_device *pdev)
        int i, err;
 
        data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "Out of memory\n");
+       if (!data)
                return -ENOMEM;
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(dev, res->start, resource_size(res),
index 8fb46aab2d87d5bf85ddc2a1b68ca38341bcb058..a04c49f2a0118a887e22c16b9716656af6e87723 100644 (file)
@@ -416,6 +416,7 @@ config BLK_DEV_CY82C693
 
 config BLK_DEV_CS5520
        tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
+       depends on X86_32 || COMPILE_TEST
        select BLK_DEV_IDEDMA_PCI
        help
          Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
@@ -426,6 +427,7 @@ config BLK_DEV_CS5520
 
 config BLK_DEV_CS5530
        tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
+       depends on X86_32 || COMPILE_TEST
        select BLK_DEV_IDEDMA_PCI
        help
          Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
@@ -435,7 +437,7 @@ config BLK_DEV_CS5530
 
 config BLK_DEV_CS5535
        tristate "AMD CS5535 chipset support"
-       depends on X86 && !X86_64
+       depends on X86_32
        select BLK_DEV_IDEDMA_PCI
        help
          Include support for UDMA on the NSC/AMD CS5535 companion chipset.
@@ -486,6 +488,7 @@ config BLK_DEV_JMICRON
 
 config BLK_DEV_SC1200
        tristate "National SCx200 chipset support"
+       depends on X86_32 || COMPILE_TEST
        select BLK_DEV_IDEDMA_PCI
        help
          This driver adds support for the on-board IDE controller on the
index 16f69be820c7bb13da94f253b5e7bb33c831fea5..ee880382e3bce50b03775e9ab48504febb4ab6b3 100644 (file)
@@ -188,10 +188,9 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 
        ledtrig_ide_activity();
 
-       pr_debug("%s: %sing: block=%llu, sectors=%u, buffer=0x%08lx\n",
+       pr_debug("%s: %sing: block=%llu, sectors=%u\n",
                 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
-                (unsigned long long)block, blk_rq_sectors(rq),
-                (unsigned long)rq->buffer);
+                (unsigned long long)block, blk_rq_sectors(rq));
 
        if (hwif->rw_disk)
                hwif->rw_disk(drive, rq);
index 2a744a91370e640d1fe3603409b80e776d8041de..a3d3b1733c49c667f7f1495d9dfef23623e28fa0 100644 (file)
@@ -853,8 +853,9 @@ static int init_irq (ide_hwif_t *hwif)
        if (irq_handler == NULL)
                irq_handler = ide_intr;
 
-       if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
-               goto out_up;
+       if (!host->get_lock)
+               if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
+                       goto out_up;
 
 #if !defined(__mc68000__)
        printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
@@ -1533,7 +1534,8 @@ static void ide_unregister(ide_hwif_t *hwif)
 
        ide_proc_unregister_port(hwif);
 
-       free_irq(hwif->irq, hwif);
+       if (!hwif->host->get_lock)
+               free_irq(hwif->irq, hwif);
 
        device_unregister(hwif->portdev);
        device_unregister(&hwif->gendev);
index d86196cfe4b47091add5d756da6d3dbf7fded9eb..24c28e3f93a3c960b7fd5c51e9f5348e003ababf 100644 (file)
@@ -106,7 +106,7 @@ config AT91_ADC
          Say yes here to build support for Atmel AT91 ADC.
 
 config EXYNOS_ADC
-       bool "Exynos ADC driver support"
+       tristate "Exynos ADC driver support"
        depends on OF
        help
          Core support for the ADC block found in the Samsung EXYNOS series
@@ -114,7 +114,7 @@ config EXYNOS_ADC
          this resource.
 
 config LP8788_ADC
-       bool "LP8788 ADC driver"
+       tristate "LP8788 ADC driver"
        depends on MFD_LP8788
        help
          Say yes here to build support for TI LP8788 ADC.
index d25b262193a7d4bccad40a42b79685cf4956e6fc..affa93f517893b1c6db2ece1c1e83afeea1828aa 100644 (file)
@@ -344,7 +344,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
        exynos_adc_hw_init(info);
 
-       ret = of_platform_populate(np, exynos_adc_match, NULL, &pdev->dev);
+       ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed adding child nodes\n");
                goto err_of_populate;
@@ -353,7 +353,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
        return 0;
 
 err_of_populate:
-       device_for_each_child(&pdev->dev, NULL,
+       device_for_each_child(&indio_dev->dev, NULL,
                                exynos_adc_remove_devices);
        regulator_disable(info->vdd);
        clk_disable_unprepare(info->clk);
@@ -369,7 +369,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
        struct exynos_adc *info = iio_priv(indio_dev);
 
-       device_for_each_child(&pdev->dev, NULL,
+       device_for_each_child(&indio_dev->dev, NULL,
                                exynos_adc_remove_devices);
        regulator_disable(info->vdd);
        clk_disable_unprepare(info->clk);
index cb9f96b446a55cd138f129db3443d44821b32781..d8ad606c7cd0c7e054d3764afe1b9edb069aaed7 100644 (file)
@@ -660,6 +660,7 @@ static int inv_mpu_probe(struct i2c_client *client,
 {
        struct inv_mpu6050_state *st;
        struct iio_dev *indio_dev;
+       struct inv_mpu6050_platform_data *pdata;
        int result;
 
        if (!i2c_check_functionality(client->adapter,
@@ -672,8 +673,10 @@ static int inv_mpu_probe(struct i2c_client *client,
 
        st = iio_priv(indio_dev);
        st->client = client;
-       st->plat_data = *(struct inv_mpu6050_platform_data
-                               *)dev_get_platdata(&client->dev);
+       pdata = (struct inv_mpu6050_platform_data
+                       *)dev_get_platdata(&client->dev);
+       if (pdata)
+               st->plat_data = *pdata;
        /* power is turned on inside check chip type*/
        result = inv_check_and_setup_chip(st, id);
        if (result)
index d4e8983fba537d71b8da25b5b0768f088678722d..23f38cf2c5cd030c2ba9e3aebd0d199c4925e930 100644 (file)
@@ -1,10 +1,10 @@
 config INFINIBAND_CXGB4
-       tristate "Chelsio T4 RDMA Driver"
+       tristate "Chelsio T4/T5 RDMA Driver"
        depends on CHELSIO_T4 && INET && (IPV6 || IPV6=n)
        select GENERIC_ALLOCATOR
        ---help---
-         This is an iWARP/RDMA driver for the Chelsio T4 1GbE and
-         10GbE adapters.
+         This is an iWARP/RDMA driver for the Chelsio T4 and T5
+         1GbE, 10GbE adapters and T5 40GbE adapter.
 
          For general information about Chelsio and our products, visit
          our website at <http://www.chelsio.com>.
index 185452abf32cf336049e20802759a4352996392b..1f863a96a480fd1ab087989acea029a781c7c23e 100644 (file)
@@ -587,6 +587,10 @@ static int send_connect(struct c4iw_ep *ep)
                opt2 |= SACK_EN(1);
        if (wscale && enable_tcp_window_scaling)
                opt2 |= WND_SCALE_EN(1);
+       if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
+               opt2 |= T5_OPT_2_VALID;
+               opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
+       }
        t4_set_arp_err_handler(skb, NULL, act_open_req_arp_failure);
 
        if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
@@ -996,7 +1000,7 @@ static void close_complete_upcall(struct c4iw_ep *ep, int status)
 static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
 {
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
-       state_set(&ep->com, ABORTING);
+       __state_set(&ep->com, ABORTING);
        set_bit(ABORT_CONN, &ep->com.history);
        return send_abort(ep, skb, gfp);
 }
@@ -1154,7 +1158,7 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)
        return credits;
 }
 
-static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
+static int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
 {
        struct mpa_message *mpa;
        struct mpa_v2_conn_params *mpa_v2_params;
@@ -1164,6 +1168,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
        struct c4iw_qp_attributes attrs;
        enum c4iw_qp_attr_mask mask;
        int err;
+       int disconnect = 0;
 
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
 
@@ -1173,7 +1178,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
         * will abort the connection.
         */
        if (stop_ep_timer(ep))
-               return;
+               return 0;
 
        /*
         * If we get more than the supported amount of private data
@@ -1195,7 +1200,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
         * if we don't even have the mpa message, then bail.
         */
        if (ep->mpa_pkt_len < sizeof(*mpa))
-               return;
+               return 0;
        mpa = (struct mpa_message *) ep->mpa_pkt;
 
        /* Validate MPA header. */
@@ -1235,7 +1240,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
         * We'll continue process when more data arrives.
         */
        if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
-               return;
+               return 0;
 
        if (mpa->flags & MPA_REJECT) {
                err = -ECONNREFUSED;
@@ -1337,9 +1342,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
                attrs.layer_etype = LAYER_MPA | DDP_LLP;
                attrs.ecode = MPA_NOMATCH_RTR;
                attrs.next_state = C4IW_QP_STATE_TERMINATE;
+               attrs.send_term = 1;
                err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
-                               C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
+                               C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
                err = -ENOMEM;
+               disconnect = 1;
                goto out;
        }
 
@@ -1355,9 +1362,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
                attrs.layer_etype = LAYER_MPA | DDP_LLP;
                attrs.ecode = MPA_INSUFF_IRD;
                attrs.next_state = C4IW_QP_STATE_TERMINATE;
+               attrs.send_term = 1;
                err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
-                               C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
+                               C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
                err = -ENOMEM;
+               disconnect = 1;
                goto out;
        }
        goto out;
@@ -1366,7 +1375,7 @@ err:
        send_abort(ep, skb, GFP_KERNEL);
 out:
        connect_reply_upcall(ep, err);
-       return;
+       return disconnect;
 }
 
 static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
@@ -1524,6 +1533,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
        unsigned int tid = GET_TID(hdr);
        struct tid_info *t = dev->rdev.lldi.tids;
        __u8 status = hdr->status;
+       int disconnect = 0;
 
        ep = lookup_tid(t, tid);
        if (!ep)
@@ -1539,7 +1549,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
        switch (ep->com.state) {
        case MPA_REQ_SENT:
                ep->rcv_seq += dlen;
-               process_mpa_reply(ep, skb);
+               disconnect = process_mpa_reply(ep, skb);
                break;
        case MPA_REQ_WAIT:
                ep->rcv_seq += dlen;
@@ -1555,13 +1565,16 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
                               ep->com.state, ep->hwtid, status);
                attrs.next_state = C4IW_QP_STATE_TERMINATE;
                c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
-                              C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
+                              C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+               disconnect = 1;
                break;
        }
        default:
                break;
        }
        mutex_unlock(&ep->com.mutex);
+       if (disconnect)
+               c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
        return 0;
 }
 
@@ -2009,6 +2022,10 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
                if (tcph->ece && tcph->cwr)
                        opt2 |= CCTRL_ECN(1);
        }
+       if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
+               opt2 |= T5_OPT_2_VALID;
+               opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
+       }
 
        rpl = cplhdr(skb);
        INIT_TP_WR(rpl, ep->hwtid);
@@ -3482,9 +3499,9 @@ static void process_timeout(struct c4iw_ep *ep)
                        __func__, ep, ep->hwtid, ep->com.state);
                abort = 0;
        }
-       mutex_unlock(&ep->com.mutex);
        if (abort)
                abort_connection(ep, NULL, GFP_KERNEL);
+       mutex_unlock(&ep->com.mutex);
        c4iw_put_ep(&ep->com);
 }
 
index 7b8c5806a09d84d912d274d4a5da814109e921b8..7474b490760a413f9f13d9e04ead79319a6fd55e 100644 (file)
@@ -435,6 +435,7 @@ struct c4iw_qp_attributes {
        u8 ecode;
        u16 sq_db_inc;
        u16 rq_db_inc;
+       u8 send_term;
 };
 
 struct c4iw_qp {
index 7b5114cb486f64f118beb7f2415ad415d75f40ae..086f62f5dc9e2ba5978e81f02e8e392c8e201774 100644 (file)
@@ -1388,11 +1388,12 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                        qhp->attr.layer_etype = attrs->layer_etype;
                        qhp->attr.ecode = attrs->ecode;
                        ep = qhp->ep;
-                       disconnect = 1;
-                       c4iw_get_ep(&qhp->ep->com);
-                       if (!internal)
+                       if (!internal) {
+                               c4iw_get_ep(&qhp->ep->com);
                                terminate = 1;
-                       else {
+                               disconnect = 1;
+                       } else {
+                               terminate = qhp->attr.send_term;
                                ret = rdma_fini(rhp, qhp, ep);
                                if (ret)
                                        goto err;
@@ -1776,11 +1777,15 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        /*
         * Use SQ_PSN and RQ_PSN to pass in IDX_INC values for
         * ringing the queue db when we're in DB_FULL mode.
+        * Only allow this on T4 devices.
         */
        attrs.sq_db_inc = attr->sq_psn;
        attrs.rq_db_inc = attr->rq_psn;
        mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0;
        mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0;
+       if (is_t5(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) &&
+           (mask & (C4IW_QP_ATTR_SQ_DB|C4IW_QP_ATTR_RQ_DB)))
+               return -EINVAL;
 
        return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0);
 }
index dc193c292671ca49e889bc6bedb10d7c1a5fe8ce..6121ca08fe588bff67aab81fe7df06119287292b 100644 (file)
@@ -836,4 +836,18 @@ struct ulptx_idata {
 #define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
 #define F_RX_DACK_CHANGE    V_RX_DACK_CHANGE(1U)
 
+enum {                     /* TCP congestion control algorithms */
+       CONG_ALG_RENO,
+       CONG_ALG_TAHOE,
+       CONG_ALG_NEWRENO,
+       CONG_ALG_HIGHSPEED
+};
+
+#define S_CONG_CNTRL    14
+#define M_CONG_CNTRL    0x3
+#define V_CONG_CNTRL(x) ((x) << S_CONG_CNTRL)
+#define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL)
+
+#define T5_OPT_2_VALID       (1 << 31)
+
 #endif /* _T4FW_RI_API_H_ */
index ce953d895f5b2b92d3bbb0d1a19be8a86d563d6b..fd325ec9f064c95fafd532a7ef64e87ca88828d1 100644 (file)
@@ -629,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
        return copy_to_user(p, str, len) ? -EFAULT : len;
 }
 
-#define OLD_KEY_MAX    0x1ff
 static int handle_eviocgbit(struct input_dev *dev,
                            unsigned int type, unsigned int size,
                            void __user *p, int compat_mode)
 {
-       static unsigned long keymax_warn_time;
        unsigned long *bits;
        int len;
 
@@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev,
        default: return -EINVAL;
        }
 
-       /*
-        * Work around bugs in userspace programs that like to do
-        * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
-        * should be in bytes, not in bits.
-        */
-       if (type == EV_KEY && size == OLD_KEY_MAX) {
-               len = OLD_KEY_MAX;
-               if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
-                       pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
-                                  "limiting output to %zu bytes. See "
-                                  "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
-                                  OLD_KEY_MAX,
-                                  BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
-       }
-
        return bits_to_user(bits, len, size, p, compat_mode);
 }
-#undef OLD_KEY_MAX
 
 static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
 {
index 76842d7dc2e3dac1c8964e22141f0de8c20e1d39..948a30304870915596490b3e78a6b4eed93e7cef 100644 (file)
@@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY
          To compile this driver as a module, choose M here: the
          module will be called stowaway.
 
+config KEYBOARD_ST_KEYSCAN
+       tristate "STMicroelectronics keyscan support"
+       depends on ARCH_STI || COMPILE_TEST
+       select INPUT_MATRIXKMAP
+       help
+         Say Y here if you want to use a keypad attached to the keyscan block
+         on some STMicroelectronics SoC devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called st-keyscan.
+
 config KEYBOARD_SUNKBD
        tristate "Sun Type 4 and Type 5 keyboard"
        select SERIO
index 11cff7b84b47cd58474b81e395eb2438bbb00e62..7504ae19049dabec09076ef83ddd43712ca13caa 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC)               += sh_keysc.o
 obj-$(CONFIG_KEYBOARD_SPEAR)           += spear-keyboard.o
 obj-$(CONFIG_KEYBOARD_STMPE)           += stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
+obj-$(CONFIG_KEYBOARD_ST_KEYSCAN)      += st-keyscan.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
 obj-$(CONFIG_KEYBOARD_TC3589X)         += tc3589x-keypad.o
 obj-$(CONFIG_KEYBOARD_TEGRA)           += tegra-kbc.o
index 2626773ff29b956de97d5c62d383e36e13ee4868..2dd1d0dd4f7de03233752e57704ff60c17e6d992 100644 (file)
@@ -243,6 +243,12 @@ static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
 static void *atkbd_platform_fixup_data;
 static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int);
 
+/*
+ * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding
+ * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed.
+ */
+static bool atkbd_skip_deactivate;
+
 static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
                                ssize_t (*handler)(struct atkbd *, char *));
 static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
@@ -768,7 +774,8 @@ static int atkbd_probe(struct atkbd *atkbd)
  * Make sure nothing is coming from the keyboard and disturbs our
  * internal state.
  */
-       atkbd_deactivate(atkbd);
+       if (!atkbd_skip_deactivate)
+               atkbd_deactivate(atkbd);
 
        return 0;
 }
@@ -1638,6 +1645,12 @@ static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
        return 1;
 }
 
+static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
+{
+       atkbd_skip_deactivate = true;
+       return 1;
+}
+
 static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
        {
                .matches = {
@@ -1775,6 +1788,20 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
                .callback = atkbd_setup_scancode_fixup,
                .driver_data = atkbd_oqo_01plus_scancode_fixup,
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LW25-B7HV"),
+               },
+               .callback = atkbd_deactivate_fixup,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "P1-J273B"),
+               },
+               .callback = atkbd_deactivate_fixup,
+       },
        { }
 };
 
index 2db13246eb8e0ba360a9cddc8c7d82b842f62ff8..52dc872c23c0780ed9fa07170e7590e4e54f93e3 100644 (file)
@@ -578,23 +578,18 @@ gpio_keys_get_devtree_pdata(struct device *dev)
        int i;
 
        node = dev->of_node;
-       if (!node) {
-               error = -ENODEV;
-               goto err_out;
-       }
+       if (!node)
+               return ERR_PTR(-ENODEV);
 
        nbuttons = of_get_child_count(node);
-       if (nbuttons == 0) {
-               error = -ENODEV;
-               goto err_out;
-       }
+       if (nbuttons == 0)
+               return ERR_PTR(-ENODEV);
 
-       pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
-                       GFP_KERNEL);
-       if (!pdata) {
-               error = -ENOMEM;
-               goto err_out;
-       }
+       pdata = devm_kzalloc(dev,
+                            sizeof(*pdata) + nbuttons * sizeof(*button),
+                            GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
 
        pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
        pdata->nbuttons = nbuttons;
@@ -619,7 +614,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                                dev_err(dev,
                                        "Failed to get gpio flags, error: %d\n",
                                        error);
-                       goto err_free_pdata;
+                       return ERR_PTR(error);
                }
 
                button = &pdata->buttons[i++];
@@ -630,8 +625,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
                        dev_err(dev, "Button without keycode: 0x%x\n",
                                button->gpio);
-                       error = -EINVAL;
-                       goto err_free_pdata;
+                       return ERR_PTR(-EINVAL);
                }
 
                button->desc = of_get_property(pp, "label", NULL);
@@ -646,17 +640,10 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                        button->debounce_interval = 5;
        }
 
-       if (pdata->nbuttons == 0) {
-               error = -EINVAL;
-               goto err_free_pdata;
-       }
+       if (pdata->nbuttons == 0)
+               return ERR_PTR(-EINVAL);
 
        return pdata;
-
-err_free_pdata:
-       kfree(pdata);
-err_out:
-       return ERR_PTR(error);
 }
 
 static struct of_device_id gpio_keys_of_match[] = {
@@ -691,6 +678,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
        struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
+       size_t size;
        int i, error;
        int wakeup = 0;
 
@@ -700,14 +688,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
                        return PTR_ERR(pdata);
        }
 
-       ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
-                       pdata->nbuttons * sizeof(struct gpio_button_data),
-                       GFP_KERNEL);
-       input = input_allocate_device();
-       if (!ddata || !input) {
+       size = sizeof(struct gpio_keys_drvdata) +
+                       pdata->nbuttons * sizeof(struct gpio_button_data);
+       ddata = devm_kzalloc(dev, size, GFP_KERNEL);
+       if (!ddata) {
                dev_err(dev, "failed to allocate state\n");
-               error = -ENOMEM;
-               goto fail1;
+               return -ENOMEM;
+       }
+
+       input = devm_input_allocate_device(dev);
+       if (!input) {
+               dev_err(dev, "failed to allocate input device\n");
+               return -ENOMEM;
        }
 
        ddata->pdata = pdata;
@@ -768,20 +760,12 @@ static int gpio_keys_probe(struct platform_device *pdev)
        while (--i >= 0)
                gpio_remove_key(&ddata->data[i]);
 
- fail1:
-       input_free_device(input);
-       kfree(ddata);
-       /* If we have no platform data, we allocated pdata dynamically. */
-       if (!dev_get_platdata(&pdev->dev))
-               kfree(pdata);
-
        return error;
 }
 
 static int gpio_keys_remove(struct platform_device *pdev)
 {
        struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
-       struct input_dev *input = ddata->input;
        int i;
 
        sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -791,14 +775,6 @@ static int gpio_keys_remove(struct platform_device *pdev)
        for (i = 0; i < ddata->pdata->nbuttons; i++)
                gpio_remove_key(&ddata->data[i]);
 
-       input_unregister_device(input);
-
-       /* If we have no platform data, we allocated pdata dynamically. */
-       if (!dev_get_platdata(&pdev->dev))
-               kfree(ddata->pdata);
-
-       kfree(ddata);
-
        return 0;
 }
 
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
new file mode 100644 (file)
index 0000000..758b487
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * STMicroelectronics Key Scanning driver
+ *
+ * Copyright (c) 2014 STMicroelectonics Ltd.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ *
+ * Based on sh_keysc.c, copyright 2008 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/input/matrix_keypad.h>
+
+#define ST_KEYSCAN_MAXKEYS 16
+
+#define KEYSCAN_CONFIG_OFF             0x0
+#define KEYSCAN_CONFIG_ENABLE          0x1
+#define KEYSCAN_DEBOUNCE_TIME_OFF      0x4
+#define KEYSCAN_MATRIX_STATE_OFF       0x8
+#define KEYSCAN_MATRIX_DIM_OFF         0xc
+#define KEYSCAN_MATRIX_DIM_X_SHIFT     0x0
+#define KEYSCAN_MATRIX_DIM_Y_SHIFT     0x2
+
+struct st_keyscan {
+       void __iomem *base;
+       int irq;
+       struct clk *clk;
+       struct input_dev *input_dev;
+       unsigned long last_state;
+       unsigned int n_rows;
+       unsigned int n_cols;
+       unsigned int debounce_us;
+};
+
+static irqreturn_t keyscan_isr(int irq, void *dev_id)
+{
+       struct st_keyscan *keypad = dev_id;
+       unsigned short *keycode = keypad->input_dev->keycode;
+       unsigned long state, change;
+       int bit_nr;
+
+       state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff;
+       change = keypad->last_state ^ state;
+       keypad->last_state = state;
+
+       for_each_set_bit(bit_nr, &change, BITS_PER_LONG)
+               input_report_key(keypad->input_dev,
+                                keycode[bit_nr], state & BIT(bit_nr));
+
+       input_sync(keypad->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int keyscan_start(struct st_keyscan *keypad)
+{
+       int error;
+
+       error = clk_enable(keypad->clk);
+       if (error)
+               return error;
+
+       writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000),
+              keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF);
+
+       writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) |
+              ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT),
+              keypad->base + KEYSCAN_MATRIX_DIM_OFF);
+
+       writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF);
+
+       return 0;
+}
+
+static void keyscan_stop(struct st_keyscan *keypad)
+{
+       writel(0, keypad->base + KEYSCAN_CONFIG_OFF);
+
+       clk_disable(keypad->clk);
+}
+
+static int keyscan_open(struct input_dev *dev)
+{
+       struct st_keyscan *keypad = input_get_drvdata(dev);
+
+       return keyscan_start(keypad);
+}
+
+static void keyscan_close(struct input_dev *dev)
+{
+       struct st_keyscan *keypad = input_get_drvdata(dev);
+
+       keyscan_stop(keypad);
+}
+
+static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
+{
+       struct device *dev = keypad_data->input_dev->dev.parent;
+       struct device_node *np = dev->of_node;
+       int error;
+
+       error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows,
+                                             &keypad_data->n_cols);
+       if (error) {
+               dev_err(dev, "failed to parse keypad params\n");
+               return error;
+       }
+
+       of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us);
+
+       dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n",
+               keypad_data->n_rows, keypad_data->n_cols,
+               keypad_data->debounce_us);
+
+       return 0;
+}
+
+static int keyscan_probe(struct platform_device *pdev)
+{
+       struct st_keyscan *keypad_data;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int error;
+
+       if (!pdev->dev.of_node) {
+               dev_err(&pdev->dev, "no DT data present\n");
+               return -EINVAL;
+       }
+
+       keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data),
+                                  GFP_KERNEL);
+       if (!keypad_data)
+               return -ENOMEM;
+
+       input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!input_dev) {
+               dev_err(&pdev->dev, "failed to allocate the input device\n");
+               return -ENOMEM;
+       }
+
+       input_dev->name = pdev->name;
+       input_dev->phys = "keyscan-keys/input0";
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->open = keyscan_open;
+       input_dev->close = keyscan_close;
+
+       input_dev->id.bustype = BUS_HOST;
+
+       error = keypad_matrix_key_parse_dt(keypad_data);
+       if (error)
+               return error;
+
+       error = matrix_keypad_build_keymap(NULL, NULL,
+                                          keypad_data->n_rows,
+                                          keypad_data->n_cols,
+                                          NULL, input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to build keymap\n");
+               return error;
+       }
+
+       input_set_drvdata(input_dev, keypad_data);
+
+       keypad_data->input_dev = input_dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(keypad_data->base))
+               return PTR_ERR(keypad_data->base);
+
+       keypad_data->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(keypad_data->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               return PTR_ERR(keypad_data->clk);
+       }
+
+       error = clk_enable(keypad_data->clk);
+       if (error) {
+               dev_err(&pdev->dev, "failed to enable clock\n");
+               return error;
+       }
+
+       keyscan_stop(keypad_data);
+
+       keypad_data->irq = platform_get_irq(pdev, 0);
+       if (keypad_data->irq < 0) {
+               dev_err(&pdev->dev, "no IRQ specified\n");
+               return -EINVAL;
+       }
+
+       error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
+                                pdev->name, keypad_data);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               return error;
+       }
+
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               return error;
+       }
+
+       platform_set_drvdata(pdev, keypad_data);
+
+       device_set_wakeup_capable(&pdev->dev, 1);
+
+       return 0;
+}
+
+static int keyscan_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct st_keyscan *keypad = platform_get_drvdata(pdev);
+       struct input_dev *input = keypad->input_dev;
+
+       mutex_lock(&input->mutex);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(keypad->irq);
+       else if (input->users)
+               keyscan_stop(keypad);
+
+       mutex_unlock(&input->mutex);
+       return 0;
+}
+
+static int keyscan_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct st_keyscan *keypad = platform_get_drvdata(pdev);
+       struct input_dev *input = keypad->input_dev;
+       int retval = 0;
+
+       mutex_lock(&input->mutex);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(keypad->irq);
+       else if (input->users)
+               retval = keyscan_start(keypad);
+
+       mutex_unlock(&input->mutex);
+       return retval;
+}
+
+static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume);
+
+static const struct of_device_id keyscan_of_match[] = {
+       { .compatible = "st,sti-keyscan" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, keyscan_of_match);
+
+static struct platform_driver keyscan_device_driver = {
+       .probe          = keyscan_probe,
+       .driver         = {
+               .name   = "st-keyscan",
+               .pm     = &keyscan_dev_pm_ops,
+               .of_match_table = of_match_ptr(keyscan_of_match),
+       }
+};
+
+module_platform_driver(keyscan_device_driver);
+
+MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics keyscan device driver");
+MODULE_LICENSE("GPL");
index 74494a357522db3506a5b29cbd86b3409e13f22b..ad7abae690781a089a80aa126b67f566fabf7ed5 100644 (file)
@@ -296,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input)
        tc3589x_keypad_disable(keypad);
 }
 
+#ifdef CONFIG_OF
+static const struct tc3589x_keypad_platform_data *
+tc3589x_keypad_of_probe(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct tc3589x_keypad_platform_data *plat;
+       u32 cols, rows;
+       u32 debounce_ms;
+       int proplen;
+
+       if (!np)
+               return ERR_PTR(-ENODEV);
+
+       plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
+       if (!plat)
+               return ERR_PTR(-ENOMEM);
+
+       of_property_read_u32(np, "keypad,num-columns", &cols);
+       of_property_read_u32(np, "keypad,num-rows", &rows);
+       plat->kcol = (u8) cols;
+       plat->krow = (u8) rows;
+       if (!plat->krow || !plat->kcol ||
+            plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) {
+               dev_err(dev,
+                       "keypad columns/rows not properly specified (%ux%u)\n",
+                       plat->kcol, plat->krow);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (!of_get_property(np, "linux,keymap", &proplen)) {
+               dev_err(dev, "property linux,keymap not found\n");
+               return ERR_PTR(-ENOENT);
+       }
+
+       plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
+       plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup");
+
+       /* The custom delay format is ms/16 */
+       of_property_read_u32(np, "debounce-delay-ms", &debounce_ms);
+       if (debounce_ms)
+               plat->debounce_period = debounce_ms * 16;
+       else
+               plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD;
+
+       plat->settle_time = TC_KPD_SETTLE_TIME;
+       /* FIXME: should be property of the IRQ resource? */
+       plat->irqtype = IRQF_TRIGGER_FALLING;
+
+       return plat;
+}
+#else
+static inline const struct tc3589x_keypad_platform_data *
+tc3589x_keypad_of_probe(struct device *dev)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
+
+
 static int tc3589x_keypad_probe(struct platform_device *pdev)
 {
        struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
@@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
 
        plat = tc3589x->pdata->keypad;
        if (!plat) {
-               dev_err(&pdev->dev, "invalid keypad platform data\n");
-               return -EINVAL;
+               plat = tc3589x_keypad_of_probe(&pdev->dev);
+               if (IS_ERR(plat)) {
+                       dev_err(&pdev->dev, "invalid keypad platform data\n");
+                       return PTR_ERR(plat);
+               }
        }
 
        irq = platform_get_irq(pdev, 0);
index 55c15304ddbce997a1027e319b81e7b3fc8ba98b..4e491c1762cfe5e1ecd9bd562e8244237261aa07 100644 (file)
@@ -392,6 +392,13 @@ static const struct of_device_id tca8418_dt_ids[] = {
        { }
 };
 MODULE_DEVICE_TABLE(of, tca8418_dt_ids);
+
+/*
+ * The device tree based i2c loader looks for
+ * "i2c:" + second_component_of(property("compatible"))
+ * and therefore we need an alias to be found.
+ */
+MODULE_ALIAS("i2c:tca8418");
 #endif
 
 static struct i2c_driver tca8418_keypad_driver = {
index 5928ea71dd696324807c7181e62eb96f93e2f65e..2ff4425a893b36787afc8a54e6fa9d9a64450419 100644 (file)
@@ -224,7 +224,7 @@ config INPUT_GP2A
 
 config INPUT_GPIO_BEEPER
        tristate "Generic GPIO Beeper support"
-       depends on OF_GPIO
+       depends on GPIOLIB
        help
          Say Y here if you have a beeper connected to a GPIO pin.
 
index 52d3a9b28f0b80a253eb04584016b767c90c22cc..b36831c828d3fe7a19be14872a7eabb2b8a38ecd 100644 (file)
@@ -70,6 +70,7 @@
 #define BMA150_CFG_5_REG       0x11
 
 #define BMA150_CHIP_ID         2
+#define BMA180_CHIP_ID         3
 #define BMA150_CHIP_ID_REG     BMA150_DATA_0_REG
 
 #define BMA150_ACC_X_LSB_REG   BMA150_DATA_2_REG
@@ -539,7 +540,7 @@ static int bma150_probe(struct i2c_client *client,
        }
 
        chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
-       if (chip_id != BMA150_CHIP_ID) {
+       if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {
                dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
                return -EINVAL;
        }
@@ -643,6 +644,7 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
 
 static const struct i2c_device_id bma150_id[] = {
        { "bma150", 0 },
+       { "bma180", 0 },
        { "smb380", 0 },
        { "bma023", 0 },
        { }
index b757435e2b3d0eda193f5d1265bd4a730ddcf255..5be291d34630202875a080cf7aab7236d01842db 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic GPIO beeper driver
  *
- * Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -11,7 +11,8 @@
 
 #include <linux/input.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 
 
 struct gpio_beeper {
        struct work_struct      work;
-       int                     gpio;
-       bool                    active_low;
+       struct gpio_desc        *desc;
        bool                    beeping;
 };
 
 static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on)
 {
-       gpio_set_value_cansleep(beep->gpio, on ^ beep->active_low);
+       gpiod_set_value_cansleep(beep->desc, on);
 }
 
 static void gpio_beeper_work(struct work_struct *work)
@@ -65,18 +65,18 @@ static void gpio_beeper_close(struct input_dev *input)
 static int gpio_beeper_probe(struct platform_device *pdev)
 {
        struct gpio_beeper *beep;
-       enum of_gpio_flags flags;
        struct input_dev *input;
-       unsigned long gflags;
        int err;
 
        beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
        if (!beep)
                return -ENOMEM;
 
-       beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
-       if (!gpio_is_valid(beep->gpio))
-               return beep->gpio;
+       beep->desc = devm_gpiod_get(&pdev->dev, NULL);
+       if (!beep->desc)
+               return -EINVAL;
+       if (IS_ERR(beep->desc))
+               return PTR_ERR(beep->desc);
 
        input = devm_input_allocate_device(&pdev->dev);
        if (!input)
@@ -94,10 +94,7 @@ static int gpio_beeper_probe(struct platform_device *pdev)
 
        input_set_capability(input, EV_SND, SND_BELL);
 
-       beep->active_low = flags & OF_GPIO_ACTIVE_LOW;
-       gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-
-       err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name);
+       err = gpiod_direction_output(beep->desc, 0);
        if (err)
                return err;
 
@@ -106,17 +103,19 @@ static int gpio_beeper_probe(struct platform_device *pdev)
        return input_register_device(input);
 }
 
+#ifdef CONFIG_OF
 static struct of_device_id gpio_beeper_of_match[] = {
        { .compatible = BEEPER_MODNAME, },
        { }
 };
 MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
+#endif
 
 static struct platform_driver gpio_beeper_platform_driver = {
        .driver = {
                .name           = BEEPER_MODNAME,
                .owner          = THIS_MODULE,
-               .of_match_table = gpio_beeper_of_match,
+               .of_match_table = of_match_ptr(gpio_beeper_of_match),
        },
        .probe  = gpio_beeper_probe,
 };
index 77dc23b94eb1eaad2232d8671024dc1ff4af359a..6d26eecc278c7e63d4e251ebbdbe3d03fdcf7de1 100644 (file)
@@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
        struct vibra_info *info;
        int vddvibl_uV = 0;
        int vddvibr_uV = 0;
-       int ret;
+       int error;
 
        twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
                                                 "vibra");
@@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
 
        mutex_init(&info->mutex);
 
-       ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
-                                       twl6040_vib_irq_handler, 0,
-                                       "twl6040_irq_vib", info);
-       if (ret) {
-               dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
-               return ret;
+       error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+                                         twl6040_vib_irq_handler, 0,
+                                         "twl6040_irq_vib", info);
+       if (error) {
+               dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
+               return error;
        }
 
        info->supplies[0].supply = "vddvibl";
@@ -323,40 +323,40 @@ 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(twl6040_core_dev, ARRAY_SIZE(info->supplies),
-                                info->supplies);
-       if (ret) {
-               dev_err(info->dev, "couldn't get regulators %d\n", ret);
-               return ret;
+       error = devm_regulator_bulk_get(twl6040_core_dev,
+                                       ARRAY_SIZE(info->supplies),
+                                       info->supplies);
+       if (error) {
+               dev_err(info->dev, "couldn't get regulators %d\n", error);
+               return error;
        }
 
        if (vddvibl_uV) {
-               ret = regulator_set_voltage(info->supplies[0].consumer,
-                                           vddvibl_uV, vddvibl_uV);
-               if (ret) {
+               error = regulator_set_voltage(info->supplies[0].consumer,
+                                             vddvibl_uV, vddvibl_uV);
+               if (error) {
                        dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
-                               ret);
-                       goto err_regulator;
+                               error);
+                       return error;
                }
        }
 
        if (vddvibr_uV) {
-               ret = regulator_set_voltage(info->supplies[1].consumer,
-                                           vddvibr_uV, vddvibr_uV);
-               if (ret) {
+               error = regulator_set_voltage(info->supplies[1].consumer,
+                                             vddvibr_uV, vddvibr_uV);
+               if (error) {
                        dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
-                               ret);
-                       goto err_regulator;
+                               error);
+                       return error;
                }
        }
 
        INIT_WORK(&info->play_work, vibra_play_work);
 
-       info->input_dev = input_allocate_device();
-       if (info->input_dev == NULL) {
+       info->input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!info->input_dev) {
                dev_err(info->dev, "couldn't allocate input device\n");
-               ret = -ENOMEM;
-               goto err_regulator;
+               return -ENOMEM;
        }
 
        input_set_drvdata(info->input_dev, info);
@@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
        info->input_dev->close = twl6040_vibra_close;
        __set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
-       ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
-       if (ret < 0) {
+       error = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+       if (error) {
                dev_err(info->dev, "couldn't register vibrator to FF\n");
-               goto err_ialloc;
+               return error;
        }
 
-       ret = input_register_device(info->input_dev);
-       if (ret < 0) {
+       error = input_register_device(info->input_dev);
+       if (error) {
                dev_err(info->dev, "couldn't register input device\n");
-               goto err_iff;
+               return error;
        }
 
        platform_set_drvdata(pdev, info);
 
-       return 0;
-
-err_iff:
-       input_ff_destroy(info->input_dev);
-err_ialloc:
-       input_free_device(info->input_dev);
-err_regulator:
-       regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-       return ret;
-}
-
-static int twl6040_vibra_remove(struct platform_device *pdev)
-{
-       struct vibra_info *info = platform_get_drvdata(pdev);
-
-       input_unregister_device(info->input_dev);
-       regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-
        return 0;
 }
 
 static struct platform_driver twl6040_vibra_driver = {
        .probe          = twl6040_vibra_probe,
-       .remove         = twl6040_vibra_remove,
        .driver         = {
                .name   = "twl6040-vibra",
                .owner  = THIS_MODULE,
index ef9f4913450d12a06262dd906b8ebe93b0401dbe..d68d33fb5ac20f50fdedf503eb19e39e8de790a2 100644 (file)
@@ -1565,6 +1565,14 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
                },
                .driver_data = (int []){1232, 5710, 1156, 4696},
        },
+       {
+               /* Lenovo ThinkPad Edge E431 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Edge E431"),
+               },
+               .driver_data = (int []){1024, 5022, 2508, 4832},
+       },
        {
                /* Lenovo ThinkPad T431s */
                .matches = {
index 4822c57a3756f4e3175fac3e1def90611028eb6d..378e3bb0520523833e04941ed43ae7f966fb403f 100644 (file)
@@ -484,6 +484,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
                input_report_key(input, BTN_TOUCH, 0);
                input_report_abs(input, ABS_PRESSURE, 0);
                input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
+               if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+                       wacom->shared->stylus_in_proximity = true;
        }
 
        /* Exit report */
@@ -558,6 +560,55 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
        }
 }
 
+static bool wacom_intuos_outbound(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       unsigned int bound = 200;
+       bool outbound = false;
+
+       /* Intuos and old Cintiqs use ready bit for outbound tracking */
+       if (!(data[1] & 0x40))
+               outbound = true;
+
+       /* New Cintiqs have 200 counts of outbound */
+       if (features->type >= WACOM_21UX2 && features->type <= WACOM_13HD) {
+               if (wacom->x_mapped < bound) {
+                       wacom->x_mapped = 0;
+                       outbound = true;
+               } else {
+                       wacom->x_mapped -= bound;
+                       if (wacom->x_mapped > features->x_max) {
+                               wacom->x_mapped = features->x_max;
+                               outbound = true;
+                       }
+               }
+
+               if (wacom->y_mapped < bound) {
+                       wacom->y_mapped = 0;
+                       outbound = true;
+               } else {
+                       wacom->y_mapped -= bound;
+                       if (wacom->y_mapped > features->y_max) {
+                               wacom->y_mapped = features->y_max;
+                               outbound = true;
+                       }
+               }
+       }
+
+       /* Intuos supports outbound tracking */
+       if (outbound && (features->type >= INTUOS3S && features->type <= INTUOSPL)) {
+               input_report_abs(input, ABS_X, wacom->x_mapped);
+               input_report_abs(input, ABS_Y, wacom->y_mapped);
+               input_report_abs(input, ABS_MISC, wacom->id[0]);
+               input_report_key(input, wacom->tool[0], 1);
+               input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+       }
+
+       return outbound;
+}
+
 static int wacom_intuos_irq(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
@@ -798,17 +849,22 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                return 0;
        }
 
-       /* Cintiq doesn't send data when RDY bit isn't set */
-       if (features->type == CINTIQ && !(data[1] & 0x40))
-                 return 0;
+       if (features->type >= INTUOS3S) {
+               wacom->x_mapped = (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1);
+               wacom->y_mapped = (data[4] << 9) | (data[5] << 1) | (data[9] & 1);
+       } else {
+               wacom->x_mapped = be16_to_cpup((__be16 *)&data[2]);
+               wacom->y_mapped = be16_to_cpup((__be16 *)&data[4]);
+       }
+
+       if (wacom_intuos_outbound(wacom))
+               return 0;
 
+       input_report_abs(input, ABS_X, wacom->x_mapped);
+       input_report_abs(input, ABS_Y, wacom->y_mapped);
        if (features->type >= INTUOS3S) {
-               input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
-               input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
                input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
        } else {
-               input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
-               input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
                input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
        }
 
@@ -2123,10 +2179,10 @@ static const struct wacom_features wacom_features_0x317 =
          63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          .touch_max = 16 };
 static const struct wacom_features wacom_features_0xF4 =
-       { "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
+       { "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104080, 65200, 2047,
          63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xF8 =
-       { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104480, 65600, 2047, /* Pen */
+       { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104080, 65200, 2047, /* Pen */
          63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
 static const struct wacom_features wacom_features_0xF6 =
@@ -2142,7 +2198,7 @@ static const struct wacom_features wacom_features_0xC6 =
        { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023,
          63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x304 =
-       { "Wacom Cintiq 13HD",    WACOM_PKGLEN_INTUOS,    59552, 33848, 1023,
+       { "Wacom Cintiq 13HD",    WACOM_PKGLEN_INTUOS,    59152, 33448, 1023,
          63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xC7 =
        { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,
@@ -2157,23 +2213,23 @@ static const struct wacom_features wacom_features_0xFB =
        { "Wacom DTU1031",        WACOM_PKGLEN_DTUS,      22096, 13960,  511,
          0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x57 =
-       { "Wacom DTK2241",        WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
+       { "Wacom DTK2241",        WACOM_PKGLEN_INTUOS,    95440, 53860, 2047,
          63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES};
 static const struct wacom_features wacom_features_0x59 = /* Pen */
-       { "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
+       { "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95440, 53860, 2047,
          63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
 static const struct wacom_features wacom_features_0x5D = /* Touch */
        { "Wacom DTH2242",       .type = WACOM_24HDT,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
 static const struct wacom_features wacom_features_0xCC =
-       { "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047,
+       { "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    86400, 64800, 2047,
          63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xFA =
-       { "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
+       { "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95440, 53860, 2047,
          63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x5B =
-       { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS,      95840, 54260, 2047,
+       { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS,      95440, 53860, 2047,
          63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
 static const struct wacom_features wacom_features_0x5E =
@@ -2316,7 +2372,7 @@ static const struct wacom_features wacom_features_0x6004 =
        { "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x0307 =
-       { "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS,  59552,  33848, 2047,
+       { "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS,  59152,  33448, 2047,
          63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
 static const struct wacom_features wacom_features_0x0309 =
index f69c0ebe7fa90d66a65b065ea838550e538b742d..9f947c31ec2caabe7be5cb3106f9dd6af6726074 100644 (file)
@@ -93,9 +93,9 @@ enum {
        DTK,
        WACOM_24HD,
        CINTIQ_HYBRID,
+       WACOM_13HD,
        CINTIQ,
        WACOM_BEE,
-       WACOM_13HD,
        WACOM_MO,
        WIRELESS,
        BAMBOO_PT,
@@ -148,6 +148,8 @@ struct wacom_wac {
        int tool[2];
        int id[2];
        __u32 serial[2];
+       unsigned int x_mapped;
+       unsigned int y_mapped;
        struct wacom_features features;
        struct wacom_shared *shared;
        struct input_dev *input;
index 68edc9db2c6446c7534a0a5708d1b01e2c5ced98..e2f0264af5cc93e9259c319bdc5b21390d122946 100644 (file)
@@ -858,7 +858,7 @@ config TOUCHSCREEN_TSC2007
 
 config TOUCHSCREEN_W90X900
        tristate "W90P910 touchscreen driver"
-       depends on HAVE_CLK
+       depends on ARCH_W90X900
        help
          Say Y here if you have a W90P910 based touchscreen.
 
index 6793c85903aeb75f2813881b2d6af2eae2ca7e39..523865daa1d39c6fbe8604eedb0c237f167c7c85 100644 (file)
@@ -210,11 +210,6 @@ static bool gpio3;
 module_param(gpio3, bool, 0);
 MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
 
-/*
- * ad7877_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done using spi_async() in the interrupt handler.
- */
-
 static int ad7877_read(struct spi_device *spi, u16 reg)
 {
        struct ser_req *req;
index 7f8aa981500d88c10d8b23cc19f489befe7bedd6..da201b8e37dc90aac807a7158278e82a81c59772 100644 (file)
@@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)
                m = &ts->msg[msg_idx];
                error = spi_sync(ts->spi, m);
                if (error) {
-                       dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
+                       dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
                        packet->tc.ignore = true;
                        return;
                }
index 550adcbbfc2321b3110bf6a62d2c87805c6cabec..d981e49368adf4421220fcaafda0973c0fae7367 100644 (file)
@@ -579,7 +579,7 @@ static int tsc2005_probe(struct spi_device *spi)
        int error;
 
        if (!pdata) {
-               dev_dbg(&spi->dev, "no platform data\n");
+               dev_err(&spi->dev, "no platform data\n");
                return -ENODEV;
        }
 
@@ -591,7 +591,7 @@ static int tsc2005_probe(struct spi_device *spi)
        max_p   = pdata->ts_pressure_max   ? : MAX_12BIT;
 
        if (spi->irq <= 0) {
-               dev_dbg(&spi->dev, "no irq\n");
+               dev_err(&spi->dev, "no irq\n");
                return -ENODEV;
        }
 
@@ -604,12 +604,13 @@ static int tsc2005_probe(struct spi_device *spi)
        if (error)
                return error;
 
-       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ts || !input_dev) {
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
+       ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       input_dev = devm_input_allocate_device(&spi->dev);
+       if (!input_dev)
+               return -ENOMEM;
 
        ts->spi = spi;
        ts->idev = input_dev;
@@ -649,12 +650,13 @@ static int tsc2005_probe(struct spi_device *spi)
        /* Ensure the touchscreen is off */
        tsc2005_stop_scan(ts);
 
-       error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
-                                    IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                    "tsc2005", ts);
+       error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+                                         tsc2005_irq_thread,
+                                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                         "tsc2005", ts);
        if (error) {
                dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
-               goto err_free_mem;
+               return error;
        }
 
        spi_set_drvdata(spi, ts);
@@ -662,7 +664,7 @@ static int tsc2005_probe(struct spi_device *spi)
        if (error) {
                dev_err(&spi->dev,
                        "Failed to create sysfs attributes, err: %d\n", error);
-               goto err_clear_drvdata;
+               return error;
        }
 
        error = input_register_device(ts->idev);
@@ -677,23 +679,12 @@ static int tsc2005_probe(struct spi_device *spi)
 
 err_remove_sysfs:
        sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
-err_clear_drvdata:
-       free_irq(spi->irq, ts);
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(ts);
        return error;
 }
 
 static int tsc2005_remove(struct spi_device *spi)
 {
-       struct tsc2005 *ts = spi_get_drvdata(spi);
-
-       sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
-
-       free_irq(ts->spi->irq, ts);
-       input_unregister_device(ts->idev);
-       kfree(ts);
+       sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
 
        return 0;
 }
index 41be897df8d5521250d79dee5362c08fe0f80067..c887e6eebc414310d9b283445b96997538c42a73 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/cpu.h>
 #include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -41,6 +42,7 @@
 #define ARMADA_370_XP_INT_SET_ENABLE_OFFS      (0x30)
 #define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS    (0x34)
 #define ARMADA_370_XP_INT_SOURCE_CTL(irq)      (0x100 + irq*4)
+#define ARMADA_370_XP_INT_SOURCE_CPU_MASK      0xF
 
 #define ARMADA_370_XP_CPU_INTACK_OFFS          (0x44)
 #define ARMADA_375_PPI_CAUSE                   (0x10)
@@ -132,8 +134,7 @@ static int armada_370_xp_setup_msi_irq(struct msi_chip *chip,
                                       struct msi_desc *desc)
 {
        struct msi_msg msg;
-       irq_hw_number_t hwirq;
-       int virq;
+       int virq, hwirq;
 
        hwirq = armada_370_xp_alloc_msi();
        if (hwirq < 0)
@@ -159,8 +160,19 @@ static void armada_370_xp_teardown_msi_irq(struct msi_chip *chip,
                                           unsigned int irq)
 {
        struct irq_data *d = irq_get_irq_data(irq);
+       unsigned long hwirq = d->hwirq;
+
        irq_dispose_mapping(irq);
-       armada_370_xp_free_msi(d->hwirq);
+       armada_370_xp_free_msi(hwirq);
+}
+
+static int armada_370_xp_check_msi_device(struct msi_chip *chip, struct pci_dev *dev,
+                                         int nvec, int type)
+{
+       /* We support MSI, but not MSI-X */
+       if (type == PCI_CAP_ID_MSI)
+               return 0;
+       return -EINVAL;
 }
 
 static struct irq_chip armada_370_xp_msi_irq_chip = {
@@ -201,6 +213,7 @@ static int armada_370_xp_msi_init(struct device_node *node,
 
        msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
        msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
+       msi_chip->check_device = armada_370_xp_check_msi_device;
        msi_chip->of_node = node;
 
        armada_370_xp_msi_domain =
@@ -244,35 +257,18 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 static int armada_xp_set_affinity(struct irq_data *d,
                                  const struct cpumask *mask_val, bool force)
 {
-       unsigned long reg;
-       unsigned long new_mask = 0;
-       unsigned long online_mask = 0;
-       unsigned long count = 0;
        irq_hw_number_t hwirq = irqd_to_hwirq(d);
+       unsigned long reg, mask;
        int cpu;
 
-       for_each_cpu(cpu, mask_val) {
-               new_mask |= 1 << cpu_logical_map(cpu);
-               count++;
-       }
-
-       /*
-        * Forbid mutlicore interrupt affinity
-        * This is required since the MPIC HW doesn't limit
-        * several CPUs from acknowledging the same interrupt.
-        */
-       if (count > 1)
-               return -EINVAL;
-
-       for_each_cpu(cpu, cpu_online_mask)
-               online_mask |= 1 << cpu_logical_map(cpu);
+       /* Select a single core from the affinity mask which is online */
+       cpu = cpumask_any_and(mask_val, cpu_online_mask);
+       mask = 1UL << cpu_logical_map(cpu);
 
        raw_spin_lock(&irq_controller_lock);
-
        reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
-       reg = (reg & (~online_mask)) | new_mask;
+       reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask;
        writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
-
        raw_spin_unlock(&irq_controller_lock);
 
        return 0;
@@ -315,7 +311,8 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
 }
 
 #ifdef CONFIG_SMP
-void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq)
+static void armada_mpic_send_doorbell(const struct cpumask *mask,
+                                     unsigned int irq)
 {
        int cpu;
        unsigned long map = 0;
@@ -335,7 +332,7 @@ void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq)
                ARMADA_370_XP_SW_TRIG_INT_OFFS);
 }
 
-void armada_xp_mpic_smp_cpu_init(void)
+static void armada_xp_mpic_smp_cpu_init(void)
 {
        /* Clear pending IPIs */
        writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
@@ -347,6 +344,20 @@ void armada_xp_mpic_smp_cpu_init(void)
        /* Unmask IPI interrupt */
        writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 }
+
+static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
+                                        unsigned long action, void *hcpu)
+{
+       if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+               armada_xp_mpic_smp_cpu_init();
+       return NOTIFY_OK;
+}
+
+static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
+       .notifier_call = armada_xp_mpic_secondary_init,
+       .priority = 100,
+};
+
 #endif /* CONFIG_SMP */
 
 static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
@@ -494,15 +505,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
 
 #ifdef CONFIG_SMP
        armada_xp_mpic_smp_cpu_init();
-
-       /*
-        * Set the default affinity from all CPUs to the boot cpu.
-        * This is required since the MPIC doesn't limit several CPUs
-        * from acknowledging the same interrupt.
-        */
-       cpumask_clear(irq_default_affinity);
-       cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
-
 #endif
 
        armada_370_xp_msi_init(node, main_int_res.start);
@@ -511,6 +513,10 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
        if (parent_irq <= 0) {
                irq_set_default_host(armada_370_xp_mpic_domain);
                set_handle_irq(armada_370_xp_handle_irq);
+#ifdef CONFIG_SMP
+               set_smp_cross_call(armada_mpic_send_doorbell);
+               register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
+#endif
        } else {
                irq_set_chained_handler(parent_irq,
                                        armada_370_xp_mpic_handle_cascade_irq);
index fc817d28d1fe50341bc4c9fe0d4de188f599d947..3d15d16a7088d2d886ef769f96534d896ded1b73 100644 (file)
@@ -107,7 +107,7 @@ static int __init crossbar_of_init(struct device_node *node)
        int i, size, max, reserved = 0, entry;
        const __be32 *irqsr;
 
-       cb = kzalloc(sizeof(struct cb_device *), GFP_KERNEL);
+       cb = kzalloc(sizeof(*cb), GFP_KERNEL);
 
        if (!cb)
                return -ENOMEM;
index e25f246cd2fb9a75d90ab57a4d1d1e12feb494f1..34d18b48bb78fe11d130f2dcd10304b261ed98eb 100644 (file)
@@ -42,7 +42,7 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
                u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
                        gc->mask_cache;
                while (stat) {
-                       u32 hwirq = ffs(stat) - 1;
+                       u32 hwirq = __fls(stat);
                        u32 irq = irq_find_mapping(orion_irq_domain,
                                                   gc->irq_base + hwirq);
                        handle_IRQ(irq, regs);
@@ -117,7 +117,7 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
                   gc->mask_cache;
 
        while (stat) {
-               u32 hwirq = ffs(stat) - 1;
+               u32 hwirq = __fls(stat);
 
                generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
                stat &= ~(1 << hwirq);
index 51dae9167238a3ed1ff972508a02f338de6702a0..96d1df05044fb48ffceb988dd90540db9f125cdd 100644 (file)
@@ -425,7 +425,7 @@ afterXPR:
                                if (cs->debug & L1_DEB_MONITOR)
                                        debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
                        }
-               AfterMOX1:
+               AfterMOX1: ;
 #endif
                }
        }
index 6de9dfbf61c197fe6078a633aabc47cd47805bcf..83af5f42b743dd25a73d312e4741fed680ea3153 100644 (file)
@@ -479,6 +479,8 @@ config LEDS_OT200
          This option enables support for the LEDs on the Bachmann OT200.
          Say Y to enable LEDs on the Bachmann OT200.
 
+comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
+
 config LEDS_BLINKM
        tristate "LED support for the BlinkM I2C RGB LED"
        depends on LEDS_CLASS
@@ -487,6 +489,14 @@ config LEDS_BLINKM
          This option enables support for the BlinkM RGB LED connected
          through I2C. Say Y to enable support for the BlinkM LED.
 
+config LEDS_VERSATILE
+       bool "LED support for the ARM Versatile and RealView"
+       depends on ARCH_REALVIEW || ARCH_VERSATILE
+       depends on LEDS_CLASS
+       help
+         This option enabled support for the LEDs on the ARM Versatile
+         and RealView boards. Say Y to enabled these.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
index 3cd76dbd9be2ff9bd1763b34adad1d0c692ce054..8b4c956e11bad78162fe20c254e4f8f6d58566bd 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_LEDS_ASIC3)              += leds-asic3.o
 obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
 obj-$(CONFIG_LEDS_LM355x)              += leds-lm355x.o
 obj-$(CONFIG_LEDS_BLINKM)              += leds-blinkm.o
+obj-$(CONFIG_LEDS_VERSATILE)           += leds-versatile.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
similarity index 68%
rename from arch/arm/plat-versatile/leds.c
rename to drivers/leds/leds-versatile.c
index d2490d00b46cd4e2e6c17a685eda16942ee930d6..80553022d661fcbd09e1a0048472deb5486b70ef 100644 (file)
@@ -7,22 +7,14 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
-
-#include <mach/hardware.h>
-#include <mach/platform.h>
-
-#ifdef VERSATILE_SYS_BASE
-#define LEDREG (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
-#endif
-
-#ifdef REALVIEW_SYS_BASE
-#define LEDREG (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
-#endif
+#include <linux/platform_device.h>
 
 struct versatile_led {
+       void __iomem            *base;
        struct led_classdev     cdev;
        u8                      mask;
 };
@@ -50,30 +42,37 @@ static void versatile_led_set(struct led_classdev *cdev,
 {
        struct versatile_led *led = container_of(cdev,
                                                 struct versatile_led, cdev);
-       u32 reg = readl(LEDREG);
+       u32 reg = readl(led->base);
 
        if (b != LED_OFF)
                reg |= led->mask;
        else
                reg &= ~led->mask;
-       writel(reg, LEDREG);
+       writel(reg, led->base);
 }
 
 static enum led_brightness versatile_led_get(struct led_classdev *cdev)
 {
        struct versatile_led *led = container_of(cdev,
                                                 struct versatile_led, cdev);
-       u32 reg = readl(LEDREG);
+       u32 reg = readl(led->base);
 
        return (reg & led->mask) ? LED_FULL : LED_OFF;
 }
 
-static int __init versatile_leds_init(void)
+static int versatile_leds_probe(struct platform_device *dev)
 {
        int i;
+       struct resource *res;
+       void __iomem *base;
 
-       /* All ON */
-       writel(0xff, LEDREG);
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&dev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       /* All off */
+       writel(0, base);
        for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) {
                struct versatile_led *led;
 
@@ -81,6 +80,7 @@ static int __init versatile_leds_init(void)
                if (!led)
                        break;
 
+               led->base = base;
                led->cdev.name = versatile_leds[i].name;
                led->cdev.brightness_set = versatile_led_set;
                led->cdev.brightness_get = versatile_led_get;
@@ -96,8 +96,15 @@ static int __init versatile_leds_init(void)
        return 0;
 }
 
-/*
- * Since we may have triggers on any subsystem, defer registration
- * until after subsystem_init.
- */
-fs_initcall(versatile_leds_init);
+static struct platform_driver versatile_leds_driver = {
+       .driver = {
+               .name   = "versatile-leds",
+       },
+       .probe = versatile_leds_probe,
+};
+
+module_platform_driver(versatile_leds_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("ARM Versatile LED driver");
+MODULE_LICENSE("GPL v2");
index 1bf4a71919ec73957a00550dec49b3a3b3a1292c..9380be7b18954b9308ed42abe5fafa2f87c0f76a 100644 (file)
@@ -2488,6 +2488,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
 
                } else {
                        inc_hit_counter(cache, bio);
+                       pb->all_io_entry = dm_deferred_entry_inc(cache->all_io_ds);
 
                        if (bio_data_dir(bio) == WRITE && writethrough_mode(&cache->features) &&
                            !is_dirty(cache, lookup_result.cblock))
index 53728be84dee35ac8dfabbf48087919841049f1a..13abade76ad9bbd65c83c67d35f075506b17b63f 100644 (file)
@@ -232,6 +232,13 @@ struct thin_c {
        struct bio_list deferred_bio_list;
        struct bio_list retry_on_resume_list;
        struct rb_root sort_bio_list; /* sorted list of deferred bios */
+
+       /*
+        * Ensures the thin is not destroyed until the worker has finished
+        * iterating the active_thins list.
+        */
+       atomic_t refcount;
+       struct completion can_destroy;
 };
 
 /*----------------------------------------------------------------*/
@@ -1486,6 +1493,45 @@ static void process_thin_deferred_bios(struct thin_c *tc)
        blk_finish_plug(&plug);
 }
 
+static void thin_get(struct thin_c *tc);
+static void thin_put(struct thin_c *tc);
+
+/*
+ * We can't hold rcu_read_lock() around code that can block.  So we
+ * find a thin with the rcu lock held; bump a refcount; then drop
+ * the lock.
+ */
+static struct thin_c *get_first_thin(struct pool *pool)
+{
+       struct thin_c *tc = NULL;
+
+       rcu_read_lock();
+       if (!list_empty(&pool->active_thins)) {
+               tc = list_entry_rcu(pool->active_thins.next, struct thin_c, list);
+               thin_get(tc);
+       }
+       rcu_read_unlock();
+
+       return tc;
+}
+
+static struct thin_c *get_next_thin(struct pool *pool, struct thin_c *tc)
+{
+       struct thin_c *old_tc = tc;
+
+       rcu_read_lock();
+       list_for_each_entry_continue_rcu(tc, &pool->active_thins, list) {
+               thin_get(tc);
+               thin_put(old_tc);
+               rcu_read_unlock();
+               return tc;
+       }
+       thin_put(old_tc);
+       rcu_read_unlock();
+
+       return NULL;
+}
+
 static void process_deferred_bios(struct pool *pool)
 {
        unsigned long flags;
@@ -1493,10 +1539,11 @@ static void process_deferred_bios(struct pool *pool)
        struct bio_list bios;
        struct thin_c *tc;
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(tc, &pool->active_thins, list)
+       tc = get_first_thin(pool);
+       while (tc) {
                process_thin_deferred_bios(tc);
-       rcu_read_unlock();
+               tc = get_next_thin(pool, tc);
+       }
 
        /*
         * If there are any deferred flush bios, we must commit
@@ -1578,7 +1625,7 @@ static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
 {
        struct noflush_work w;
 
-       INIT_WORK(&w.worker, fn);
+       INIT_WORK_ONSTACK(&w.worker, fn);
        w.tc = tc;
        atomic_set(&w.complete, 0);
        init_waitqueue_head(&w.wait);
@@ -3061,11 +3108,25 @@ static struct target_type pool_target = {
 /*----------------------------------------------------------------
  * Thin target methods
  *--------------------------------------------------------------*/
+static void thin_get(struct thin_c *tc)
+{
+       atomic_inc(&tc->refcount);
+}
+
+static void thin_put(struct thin_c *tc)
+{
+       if (atomic_dec_and_test(&tc->refcount))
+               complete(&tc->can_destroy);
+}
+
 static void thin_dtr(struct dm_target *ti)
 {
        struct thin_c *tc = ti->private;
        unsigned long flags;
 
+       thin_put(tc);
+       wait_for_completion(&tc->can_destroy);
+
        spin_lock_irqsave(&tc->pool->lock, flags);
        list_del_rcu(&tc->list);
        spin_unlock_irqrestore(&tc->pool->lock, flags);
@@ -3101,6 +3162,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
        struct thin_c *tc;
        struct dm_dev *pool_dev, *origin_dev;
        struct mapped_device *pool_md;
+       unsigned long flags;
 
        mutex_lock(&dm_thin_pool_table.mutex);
 
@@ -3191,9 +3253,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        mutex_unlock(&dm_thin_pool_table.mutex);
 
-       spin_lock(&tc->pool->lock);
+       atomic_set(&tc->refcount, 1);
+       init_completion(&tc->can_destroy);
+
+       spin_lock_irqsave(&tc->pool->lock, flags);
        list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
-       spin_unlock(&tc->pool->lock);
+       spin_unlock_irqrestore(&tc->pool->lock, flags);
        /*
         * This synchronize_rcu() call is needed here otherwise we risk a
         * wake_worker() call finding no bios to process (because the newly
index 796007a5e0e1a4b6e83b0871c1fca1ef8c0c461f..7a7bab8947ae3485d31c132cb3398251c7d507cf 100644 (file)
@@ -330,15 +330,17 @@ test_block_hash:
                                return r;
                        }
                }
-
                todo = 1 << v->data_dev_block_bits;
-               while (io->iter.bi_size) {
+               do {
                        u8 *page;
+                       unsigned len;
                        struct bio_vec bv = bio_iter_iovec(bio, io->iter);
 
                        page = kmap_atomic(bv.bv_page);
-                       r = crypto_shash_update(desc, page + bv.bv_offset,
-                                               bv.bv_len);
+                       len = bv.bv_len;
+                       if (likely(len >= todo))
+                               len = todo;
+                       r = crypto_shash_update(desc, page + bv.bv_offset, len);
                        kunmap_atomic(page);
 
                        if (r < 0) {
@@ -346,8 +348,9 @@ test_block_hash:
                                return r;
                        }
 
-                       bio_advance_iter(bio, &io->iter, bv.bv_len);
-               }
+                       bio_advance_iter(bio, &io->iter, len);
+                       todo -= len;
+               } while (todo);
 
                if (!v->version) {
                        r = crypto_shash_update(desc, v->salt, v->salt_size);
index 455e6491649889d1970cd8ef3425e93f2ea6a93c..6a71bc7c9133a1d5e63ec13493593449a22f1044 100644 (file)
@@ -1544,7 +1544,6 @@ static int setup_clone(struct request *clone, struct request *rq,
        clone->cmd = rq->cmd;
        clone->cmd_len = rq->cmd_len;
        clone->sense = rq->sense;
-       clone->buffer = rq->buffer;
        clone->end_io = end_clone_request;
        clone->end_io_data = tio;
 
index 8fda38d23e3847aa4d96ecd147e996514a5a4af7..f477e4ca0f786ebe526dba7d3db7380be21c22cb 100644 (file)
@@ -3448,6 +3448,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
                mddev->level = LEVEL_NONE;
                return rv;
        }
+       if (mddev->ro)
+               return  -EROFS;
 
        /* request to change the personality.  Need to ensure:
         *  - array is not engaged in resync/recovery/reshape
@@ -3634,6 +3636,8 @@ layout_store(struct mddev *mddev, const char *buf, size_t len)
                int err;
                if (mddev->pers->check_reshape == NULL)
                        return -EBUSY;
+               if (mddev->ro)
+                       return -EROFS;
                mddev->new_layout = n;
                err = mddev->pers->check_reshape(mddev);
                if (err) {
@@ -3723,6 +3727,8 @@ chunk_size_store(struct mddev *mddev, const char *buf, size_t len)
                int err;
                if (mddev->pers->check_reshape == NULL)
                        return -EBUSY;
+               if (mddev->ro)
+                       return -EROFS;
                mddev->new_chunk_sectors = n >> 9;
                err = mddev->pers->check_reshape(mddev);
                if (err) {
@@ -6135,6 +6141,8 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
         */
        if (mddev->sync_thread)
                return -EBUSY;
+       if (mddev->ro)
+               return -EROFS;
 
        rdev_for_each(rdev, mddev) {
                sector_t avail = rdev->sectors;
@@ -6157,6 +6165,8 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
        /* change the number of raid disks */
        if (mddev->pers->check_reshape == NULL)
                return -EINVAL;
+       if (mddev->ro)
+               return -EROFS;
        if (raid_disks <= 0 ||
            (mddev->max_disks && raid_disks >= mddev->max_disks))
                return -EINVAL;
@@ -8516,7 +8526,8 @@ static int md_notify_reboot(struct notifier_block *this,
                if (mddev_trylock(mddev)) {
                        if (mddev->pers)
                                __md_stop_writes(mddev);
-                       mddev->safemode = 2;
+                       if (mddev->persistent)
+                               mddev->safemode = 2;
                        mddev_unlock(mddev);
                }
                need_delay = 1;
index 33fc408e5eacef0a1dce55fd5c0d578fc244b663..cb882aae9e20d4f7032a400884f45f50de57528f 100644 (file)
@@ -1172,6 +1172,13 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
        int max_sectors;
        int sectors;
 
+       /*
+        * Register the new request and wait if the reconstruction
+        * thread has put up a bar for new requests.
+        * Continue immediately if no resync is active currently.
+        */
+       wait_barrier(conf);
+
        sectors = bio_sectors(bio);
        while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
            bio->bi_iter.bi_sector < conf->reshape_progress &&
@@ -1552,12 +1559,6 @@ static void make_request(struct mddev *mddev, struct bio *bio)
 
        md_write_start(mddev, bio);
 
-       /*
-        * Register the new request and wait if the reconstruction
-        * thread has put up a bar for new requests.
-        * Continue immediately if no resync is active currently.
-        */
-       wait_barrier(conf);
 
        do {
 
index ad1b9bea446ebdbaea0083cb976ed4207c618cc1..633e20a96b346e2aa7fdfc1f53f413db7818934c 100644 (file)
@@ -479,6 +479,7 @@ static void shrink_buffers(struct stripe_head *sh)
        int num = sh->raid_conf->pool_size;
 
        for (i = 0; i < num ; i++) {
+               WARN_ON(sh->dev[i].page != sh->dev[i].orig_page);
                p = sh->dev[i].page;
                if (!p)
                        continue;
@@ -499,6 +500,7 @@ static int grow_buffers(struct stripe_head *sh)
                        return 1;
                }
                sh->dev[i].page = page;
+               sh->dev[i].orig_page = page;
        }
        return 0;
 }
@@ -855,6 +857,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
                                bi->bi_rw |= REQ_NOMERGE;
 
+                       if (test_bit(R5_SkipCopy, &sh->dev[i].flags))
+                               WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags));
+                       sh->dev[i].vec.bv_page = sh->dev[i].page;
                        bi->bi_vcnt = 1;
                        bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
                        bi->bi_io_vec[0].bv_offset = 0;
@@ -899,6 +904,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        else
                                rbi->bi_iter.bi_sector = (sh->sector
                                                  + rrdev->data_offset);
+                       if (test_bit(R5_SkipCopy, &sh->dev[i].flags))
+                               WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags));
+                       sh->dev[i].rvec.bv_page = sh->dev[i].page;
                        rbi->bi_vcnt = 1;
                        rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
                        rbi->bi_io_vec[0].bv_offset = 0;
@@ -927,8 +935,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
 }
 
 static struct dma_async_tx_descriptor *
-async_copy_data(int frombio, struct bio *bio, struct page *page,
-       sector_t sector, struct dma_async_tx_descriptor *tx)
+async_copy_data(int frombio, struct bio *bio, struct page **page,
+       sector_t sector, struct dma_async_tx_descriptor *tx,
+       struct stripe_head *sh)
 {
        struct bio_vec bvl;
        struct bvec_iter iter;
@@ -965,11 +974,16 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
                if (clen > 0) {
                        b_offset += bvl.bv_offset;
                        bio_page = bvl.bv_page;
-                       if (frombio)
-                               tx = async_memcpy(page, bio_page, page_offset,
+                       if (frombio) {
+                               if (sh->raid_conf->skip_copy &&
+                                   b_offset == 0 && page_offset == 0 &&
+                                   clen == STRIPE_SIZE)
+                                       *page = bio_page;
+                               else
+                                       tx = async_memcpy(*page, bio_page, page_offset,
                                                  b_offset, clen, &submit);
-                       else
-                               tx = async_memcpy(bio_page, page, b_offset,
+                       else
+                               tx = async_memcpy(bio_page, *page, b_offset,
                                                  page_offset, clen, &submit);
                }
                /* chain the operations */
@@ -1045,8 +1059,8 @@ static void ops_run_biofill(struct stripe_head *sh)
                        spin_unlock_irq(&sh->stripe_lock);
                        while (rbi && rbi->bi_iter.bi_sector <
                                dev->sector + STRIPE_SECTORS) {
-                               tx = async_copy_data(0, rbi, dev->page,
-                                       dev->sector, tx);
+                               tx = async_copy_data(0, rbi, &dev->page,
+                                       dev->sector, tx, sh);
                                rbi = r5_next_bio(rbi, dev->sector);
                        }
                }
@@ -1384,6 +1398,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
                        BUG_ON(dev->written);
                        wbi = dev->written = chosen;
                        spin_unlock_irq(&sh->stripe_lock);
+                       WARN_ON(dev->page != dev->orig_page);
 
                        while (wbi && wbi->bi_iter.bi_sector <
                                dev->sector + STRIPE_SECTORS) {
@@ -1393,9 +1408,15 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
                                        set_bit(R5_SyncIO, &dev->flags);
                                if (wbi->bi_rw & REQ_DISCARD)
                                        set_bit(R5_Discard, &dev->flags);
-                               else
-                                       tx = async_copy_data(1, wbi, dev->page,
-                                               dev->sector, tx);
+                               else {
+                                       tx = async_copy_data(1, wbi, &dev->page,
+                                               dev->sector, tx, sh);
+                                       if (dev->page != dev->orig_page) {
+                                               set_bit(R5_SkipCopy, &dev->flags);
+                                               clear_bit(R5_UPTODATE, &dev->flags);
+                                               clear_bit(R5_OVERWRITE, &dev->flags);
+                                       }
+                               }
                                wbi = r5_next_bio(wbi, dev->sector);
                        }
                }
@@ -1426,7 +1447,7 @@ static void ops_complete_reconstruct(void *stripe_head_ref)
                struct r5dev *dev = &sh->dev[i];
 
                if (dev->written || i == pd_idx || i == qd_idx) {
-                       if (!discard)
+                       if (!discard && !test_bit(R5_SkipCopy, &dev->flags))
                                set_bit(R5_UPTODATE, &dev->flags);
                        if (fua)
                                set_bit(R5_WantFUA, &dev->flags);
@@ -2133,24 +2154,20 @@ static void raid5_end_write_request(struct bio *bi, int error)
 }
 
 static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous);
-       
+
 static void raid5_build_block(struct stripe_head *sh, int i, int previous)
 {
        struct r5dev *dev = &sh->dev[i];
 
        bio_init(&dev->req);
        dev->req.bi_io_vec = &dev->vec;
-       dev->req.bi_vcnt++;
-       dev->req.bi_max_vecs++;
+       dev->req.bi_max_vecs = 1;
        dev->req.bi_private = sh;
-       dev->vec.bv_page = dev->page;
 
        bio_init(&dev->rreq);
        dev->rreq.bi_io_vec = &dev->rvec;
-       dev->rreq.bi_vcnt++;
-       dev->rreq.bi_max_vecs++;
+       dev->rreq.bi_max_vecs = 1;
        dev->rreq.bi_private = sh;
-       dev->rvec.bv_page = dev->page;
 
        dev->flags = 0;
        dev->sector = compute_blocknr(sh, i, previous);
@@ -2750,6 +2767,11 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                /* and fail all 'written' */
                bi = sh->dev[i].written;
                sh->dev[i].written = NULL;
+               if (test_and_clear_bit(R5_SkipCopy, &sh->dev[i].flags)) {
+                       WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags));
+                       sh->dev[i].page = sh->dev[i].orig_page;
+               }
+
                if (bi) bitmap_end = 1;
                while (bi && bi->bi_iter.bi_sector <
                       sh->dev[i].sector + STRIPE_SECTORS) {
@@ -2991,12 +3013,17 @@ static void handle_stripe_clean_event(struct r5conf *conf,
                        dev = &sh->dev[i];
                        if (!test_bit(R5_LOCKED, &dev->flags) &&
                            (test_bit(R5_UPTODATE, &dev->flags) ||
-                            test_bit(R5_Discard, &dev->flags))) {
+                            test_bit(R5_Discard, &dev->flags) ||
+                            test_bit(R5_SkipCopy, &dev->flags))) {
                                /* We can return any write requests */
                                struct bio *wbi, *wbi2;
                                pr_debug("Return write for disc %d\n", i);
                                if (test_and_clear_bit(R5_Discard, &dev->flags))
                                        clear_bit(R5_UPTODATE, &dev->flags);
+                               if (test_and_clear_bit(R5_SkipCopy, &dev->flags)) {
+                                       WARN_ON(test_bit(R5_UPTODATE, &dev->flags));
+                                       dev->page = dev->orig_page;
+                               }
                                wbi = dev->written;
                                dev->written = NULL;
                                while (wbi && wbi->bi_iter.bi_sector <
@@ -3015,6 +3042,8 @@ static void handle_stripe_clean_event(struct r5conf *conf,
                                                0);
                        } else if (test_bit(R5_Discard, &dev->flags))
                                discard_pending = 1;
+                       WARN_ON(test_bit(R5_SkipCopy, &dev->flags));
+                       WARN_ON(dev->page != dev->orig_page);
                }
        if (!discard_pending &&
            test_bit(R5_Discard, &sh->dev[sh->pd_idx].flags)) {
@@ -5354,6 +5383,50 @@ raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold,
                                        raid5_show_preread_threshold,
                                        raid5_store_preread_threshold);
 
+static ssize_t
+raid5_show_skip_copy(struct mddev *mddev, char *page)
+{
+       struct r5conf *conf = mddev->private;
+       if (conf)
+               return sprintf(page, "%d\n", conf->skip_copy);
+       else
+               return 0;
+}
+
+static ssize_t
+raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len)
+{
+       struct r5conf *conf = mddev->private;
+       unsigned long new;
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       if (kstrtoul(page, 10, &new))
+               return -EINVAL;
+       new = !!new;
+       if (new == conf->skip_copy)
+               return len;
+
+       mddev_suspend(mddev);
+       conf->skip_copy = new;
+       if (new)
+               mddev->queue->backing_dev_info.capabilities |=
+                                               BDI_CAP_STABLE_WRITES;
+       else
+               mddev->queue->backing_dev_info.capabilities &=
+                                               ~BDI_CAP_STABLE_WRITES;
+       mddev_resume(mddev);
+       return len;
+}
+
+static struct md_sysfs_entry
+raid5_skip_copy = __ATTR(skip_copy, S_IRUGO | S_IWUSR,
+                                       raid5_show_skip_copy,
+                                       raid5_store_skip_copy);
+
+
 static ssize_t
 stripe_cache_active_show(struct mddev *mddev, char *page)
 {
@@ -5439,6 +5512,7 @@ static struct attribute *raid5_attrs[] =  {
        &raid5_stripecache_active.attr,
        &raid5_preread_bypass_threshold.attr,
        &raid5_group_thread_cnt.attr,
+       &raid5_skip_copy.attr,
        NULL,
 };
 static struct attribute_group raid5_attrs_group = {
index 01ad8ae8f57830a04de4e1e30b731f74660bda62..bc72cd4be5f8e16eaa49add51fd39aaf34d3d4e3 100644 (file)
@@ -232,7 +232,7 @@ struct stripe_head {
                 */
                struct bio      req, rreq;
                struct bio_vec  vec, rvec;
-               struct page     *page;
+               struct page     *page, *orig_page;
                struct bio      *toread, *read, *towrite, *written;
                sector_t        sector;                 /* sector of this page */
                unsigned long   flags;
@@ -299,6 +299,7 @@ enum r5dev_flags {
                         * data in, and now is a good time to write it out.
                         */
        R5_Discard,     /* Discard the stripe */
+       R5_SkipCopy,    /* Don't copy data from bio to stripe cache */
 };
 
 /*
@@ -436,6 +437,7 @@ struct r5conf {
        atomic_t                pending_full_writes; /* full write backlog */
        int                     bypass_count; /* bypassed prereads */
        int                     bypass_threshold; /* preread nice */
+       int                     skip_copy; /* Don't copy data from bio to stripe cache */
        struct list_head        *last_hold; /* detect hold_list promotions */
 
        atomic_t                reshape_stripes; /* stripes with pending writes for reshape */
index a4459301b5f829efcae8563241ef1108933194d7..ee0f57e01b5677df58c9f74565767bcaf57d54af 100644 (file)
@@ -1616,7 +1616,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
        if (ret < 0)
                return -EINVAL;
 
-       node_ep = v4l2_of_get_next_endpoint(node, NULL);
+       node_ep = of_graph_get_next_endpoint(node, NULL);
        if (!node_ep) {
                dev_warn(dev, "no endpoint defined for node: %s\n",
                                                node->full_name);
index b4f12d00be059c3f381b31295d435074ee291dab..65670825296209917cc33546d1d43abb60af5ed5 100644 (file)
@@ -372,18 +372,32 @@ static int vpbe_stop_streaming(struct vb2_queue *vq)
 {
        struct vpbe_fh *fh = vb2_get_drv_priv(vq);
        struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp = fh->disp_dev;
+       unsigned long flags;
 
        if (!vb2_is_streaming(vq))
                return 0;
 
        /* release all active buffers */
+       spin_lock_irqsave(&disp->dma_queue_lock, flags);
+       if (layer->cur_frm == layer->next_frm) {
+               vb2_buffer_done(&layer->cur_frm->vb, VB2_BUF_STATE_ERROR);
+       } else {
+               if (layer->cur_frm != NULL)
+                       vb2_buffer_done(&layer->cur_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+               if (layer->next_frm != NULL)
+                       vb2_buffer_done(&layer->next_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+       }
+
        while (!list_empty(&layer->dma_queue)) {
                layer->next_frm = list_entry(layer->dma_queue.next,
                                                struct vpbe_disp_buffer, list);
                list_del(&layer->next_frm->list);
                vb2_buffer_done(&layer->next_frm->vb, VB2_BUF_STATE_ERROR);
        }
-
+       spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
        return 0;
 }
 
index d762246eabf5a3b78a8c348e7a5e5f149580e143..0379cb9f9a9c25c7b0a4efb52e741d4723ddcdc4 100644 (file)
@@ -734,6 +734,8 @@ static int vpfe_release(struct file *file)
                }
                vpfe_dev->io_usrs = 0;
                vpfe_dev->numbuffers = config_params.numbuffers;
+               videobuf_stop(&vpfe_dev->buffer_queue);
+               videobuf_mmap_free(&vpfe_dev->buffer_queue);
        }
 
        /* Decrement device usrs counter */
index 756da78bac23109dbd3e7da464243da381354231..8dea0b84a3ad66788ab29b2437303ebd3bc38d6f 100644 (file)
@@ -358,8 +358,31 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
 
        common = &ch->common[VPIF_VIDEO_INDEX];
 
+       /* Disable channel as per its device type and channel id */
+       if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
+               enable_channel0(0);
+               channel0_intr_enable(0);
+       }
+       if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
+               (2 == common->started)) {
+               enable_channel1(0);
+               channel1_intr_enable(0);
+       }
+       common->started = 0;
+
        /* release all active buffers */
        spin_lock_irqsave(&common->irqlock, flags);
+       if (common->cur_frm == common->next_frm) {
+               vb2_buffer_done(&common->cur_frm->vb, VB2_BUF_STATE_ERROR);
+       } else {
+               if (common->cur_frm != NULL)
+                       vb2_buffer_done(&common->cur_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+               if (common->next_frm != NULL)
+                       vb2_buffer_done(&common->next_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+       }
+
        while (!list_empty(&common->dma_queue)) {
                common->next_frm = list_entry(common->dma_queue.next,
                                                struct vpif_cap_buffer, list);
@@ -933,17 +956,6 @@ static int vpif_release(struct file *filep)
        if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
                /* Reset io_usrs member of channel object */
                common->io_usrs = 0;
-               /* Disable channel as per its device type and channel id */
-               if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
-                       enable_channel0(0);
-                       channel0_intr_enable(0);
-               }
-               if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
-                   (2 == common->started)) {
-                       enable_channel1(0);
-                       channel1_intr_enable(0);
-               }
-               common->started = 0;
                /* Free buffers allocated */
                vb2_queue_release(&common->buffer_queue);
                vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
index 0ac841e35aa48dd59bdf17b32f97afbe94b561b5..aed41edd050102e89248cecbb2607a4f45e6eb12 100644 (file)
@@ -320,8 +320,31 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
 
        common = &ch->common[VPIF_VIDEO_INDEX];
 
+       /* Disable channel */
+       if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+               enable_channel2(0);
+               channel2_intr_enable(0);
+       }
+       if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+               (2 == common->started)) {
+               enable_channel3(0);
+               channel3_intr_enable(0);
+       }
+       common->started = 0;
+
        /* release all active buffers */
        spin_lock_irqsave(&common->irqlock, flags);
+       if (common->cur_frm == common->next_frm) {
+               vb2_buffer_done(&common->cur_frm->vb, VB2_BUF_STATE_ERROR);
+       } else {
+               if (common->cur_frm != NULL)
+                       vb2_buffer_done(&common->cur_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+               if (common->next_frm != NULL)
+                       vb2_buffer_done(&common->next_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+       }
+
        while (!list_empty(&common->dma_queue)) {
                common->next_frm = list_entry(common->dma_queue.next,
                                                struct vpif_disp_buffer, list);
@@ -773,18 +796,6 @@ static int vpif_release(struct file *filep)
        if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
                /* Reset io_usrs member of channel object */
                common->io_usrs = 0;
-               /* Disable channel */
-               if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
-                       enable_channel2(0);
-                       channel2_intr_enable(0);
-               }
-               if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
-                   (2 == common->started)) {
-                       enable_channel3(0);
-                       channel3_intr_enable(0);
-               }
-               common->started = 0;
-
                /* Free buffers allocated */
                vb2_queue_release(&common->buffer_queue);
                vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
index da2fc86cc52433bd8f1c6b32a898baa87c2a1064..25dbf5b05a96186527cf520f568f03721b181a80 100644 (file)
@@ -122,7 +122,7 @@ static struct fimc_fmt fimc_formats[] = {
        }, {
                .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
                .fourcc         = V4L2_PIX_FMT_YUV422P,
-               .depth          = { 12 },
+               .depth          = { 16 },
                .color          = FIMC_FMT_YCBYCR422,
                .memplanes      = 1,
                .colplanes      = 3,
index 7407b8338ccfa33ce6a4179e5b9e99632a3f6ebf..bc38f03394cda0e1a397b390f354b620fe486a73 100644 (file)
@@ -41,4 +41,3 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
 ccflags-y += -I$(srctree)/drivers/media/tuners
 ccflags-y += -I$(srctree)/drivers/media/common
-ccflags-y += -I$(srctree)/drivers/staging/media/rtl2832u_sdr
index 61d196e8b3abde6dc0d97e26fe3ca7cae9292957..dcbd392e6efc8f38265d8b7fd805c4b38eff9410 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "rtl2830.h"
 #include "rtl2832.h"
-#include "rtl2832_sdr.h"
 
 #include "qt1010.h"
 #include "mt2060.h"
 #include "tua9001.h"
 #include "r820t.h"
 
+/*
+ * RTL2832_SDR module is in staging. That logic is added in order to avoid any
+ * hard dependency to drivers/staging/ directory as we want compile mainline
+ * driver even whole staging directory is missing.
+ */
+#include <media/v4l2-subdev.h>
+
+#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR)
+struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+       struct v4l2_subdev *sd);
+#else
+static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+       struct v4l2_subdev *sd)
+{
+       return NULL;
+}
+#endif
+
+#ifdef CONFIG_MEDIA_ATTACH
+#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
+       void *__r = NULL; \
+       typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+       if (__a) { \
+               __r = (void *) __a(ARGS); \
+               if (__r == NULL) \
+                       symbol_put(FUNCTION); \
+       } \
+       __r; \
+})
+
+#else
+#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
+       FUNCTION(ARGS); \
+})
+
+#endif
+
 static int rtl28xxu_disable_rc;
 module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644);
 MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller");
@@ -908,7 +946,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
 
                /* attach SDR */
-               dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+               dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
                                &rtl28xxu_rtl2832_fc0012_config, NULL);
                break;
        case TUNER_RTL2832_FC0013:
@@ -920,7 +958,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
 
                /* attach SDR */
-               dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+               dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
                                &rtl28xxu_rtl2832_fc0013_config, NULL);
                break;
        case TUNER_RTL2832_E4000: {
@@ -951,7 +989,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                        i2c_set_adapdata(i2c_adap_internal, d);
 
                        /* attach SDR */
-                       dvb_attach(rtl2832_sdr_attach, adap->fe[0],
+                       dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0],
                                        i2c_adap_internal,
                                        &rtl28xxu_rtl2832_e4000_config, sd);
                }
@@ -982,7 +1020,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
 
                /* attach SDR */
-               dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+               dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
                                &rtl28xxu_rtl2832_r820t_config, NULL);
                break;
        case TUNER_RTL2832_R828D:
index 7277dbd2afcdb8c88629aafc2c9013b38cd79390..ecbcb39feb71ad21f7b765c36ac20858234d01f6 100644 (file)
@@ -1430,10 +1430,8 @@ static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
        {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
        {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
-#if !IS_ENABLED(CONFIG_USB_SN9C102)
        {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
        {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
-#endif
        {USB_DEVICE(0x0c45, 0x6027), SB(OV7630, 101)}, /* Genius Eye 310 */
        {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
        {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
index 110c03627051cb749ef92d853e47322714b1dd51..ff7138fd66d14378ff2adef5f6d1a4901be994b5 100644 (file)
@@ -2,7 +2,7 @@
  * Marvell EBU SoC Device Bus Controller
  * (memory controller for NOR/NAND/SRAM/FPGA devices)
  *
- * Copyright (C) 2013 Marvell
+ * Copyright (C) 2013-2014 Marvell
  *
  * This 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/platform_device.h>
 
 /* Register definitions */
-#define DEV_WIDTH_BIT          30
-#define BADR_SKEW_BIT          28
-#define RD_HOLD_BIT            23
-#define ACC_NEXT_BIT           17
-#define RD_SETUP_BIT           12
-#define ACC_FIRST_BIT          6
-
-#define SYNC_ENABLE_BIT                24
-#define WR_HIGH_BIT            16
-#define WR_LOW_BIT             8
-
-#define READ_PARAM_OFFSET      0x0
-#define WRITE_PARAM_OFFSET     0x4
+#define ARMADA_DEV_WIDTH_SHIFT         30
+#define ARMADA_BADR_SKEW_SHIFT         28
+#define ARMADA_RD_HOLD_SHIFT           23
+#define ARMADA_ACC_NEXT_SHIFT          17
+#define ARMADA_RD_SETUP_SHIFT          12
+#define ARMADA_ACC_FIRST_SHIFT         6
+
+#define ARMADA_SYNC_ENABLE_SHIFT       24
+#define ARMADA_WR_HIGH_SHIFT           16
+#define ARMADA_WR_LOW_SHIFT            8
+
+#define ARMADA_READ_PARAM_OFFSET       0x0
+#define ARMADA_WRITE_PARAM_OFFSET      0x4
+
+#define ORION_RESERVED                 (0x2 << 30)
+#define ORION_BADR_SKEW_SHIFT          28
+#define ORION_WR_HIGH_EXT_BIT          BIT(27)
+#define ORION_WR_HIGH_EXT_MASK         0x8
+#define ORION_WR_LOW_EXT_BIT           BIT(26)
+#define ORION_WR_LOW_EXT_MASK          0x8
+#define ORION_ALE_WR_EXT_BIT           BIT(25)
+#define ORION_ALE_WR_EXT_MASK          0x8
+#define ORION_ACC_NEXT_EXT_BIT         BIT(24)
+#define ORION_ACC_NEXT_EXT_MASK                0x10
+#define ORION_ACC_FIRST_EXT_BIT                BIT(23)
+#define ORION_ACC_FIRST_EXT_MASK       0x10
+#define ORION_TURN_OFF_EXT_BIT         BIT(22)
+#define ORION_TURN_OFF_EXT_MASK                0x8
+#define ORION_DEV_WIDTH_SHIFT          20
+#define ORION_WR_HIGH_SHIFT            17
+#define ORION_WR_HIGH_MASK             0x7
+#define ORION_WR_LOW_SHIFT             14
+#define ORION_WR_LOW_MASK              0x7
+#define ORION_ALE_WR_SHIFT             11
+#define ORION_ALE_WR_MASK              0x7
+#define ORION_ACC_NEXT_SHIFT           7
+#define ORION_ACC_NEXT_MASK            0xF
+#define ORION_ACC_FIRST_SHIFT          3
+#define ORION_ACC_FIRST_MASK           0xF
+#define ORION_TURN_OFF_SHIFT           0
+#define ORION_TURN_OFF_MASK            0x7
 
 struct devbus_read_params {
        u32 bus_width;
@@ -89,117 +117,167 @@ static int get_timing_param_ps(struct devbus *devbus,
        return 0;
 }
 
-static int devbus_set_timing_params(struct devbus *devbus,
-                                   struct device_node *node)
+static int devbus_get_timing_params(struct devbus *devbus,
+                                   struct device_node *node,
+                                   struct devbus_read_params *r,
+                                   struct devbus_write_params *w)
 {
-       struct devbus_read_params r;
-       struct devbus_write_params w;
-       u32 value;
        int err;
 
-       dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n",
-               devbus->tick_ps);
-
-       /* Get read timings */
-       err = of_property_read_u32(node, "devbus,bus-width", &r.bus_width);
+       err = of_property_read_u32(node, "devbus,bus-width", &r->bus_width);
        if (err < 0) {
                dev_err(devbus->dev,
                        "%s has no 'devbus,bus-width' property\n",
                        node->full_name);
                return err;
        }
-       /* Convert bit width to byte width */
-       r.bus_width /= 8;
+
+       /*
+        * The bus width is encoded into the register as 0 for 8 bits,
+        * and 1 for 16 bits, so we do the necessary conversion here.
+        */
+       if (r->bus_width == 8)
+               r->bus_width = 0;
+       else if (r->bus_width == 16)
+               r->bus_width = 1;
+       else {
+               dev_err(devbus->dev, "invalid bus width %d\n", r->bus_width);
+               return -EINVAL;
+       }
 
        err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps",
-                                &r.badr_skew);
+                                &r->badr_skew);
        if (err < 0)
                return err;
 
        err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps",
-                                &r.turn_off);
+                                &r->turn_off);
        if (err < 0)
                return err;
 
        err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps",
-                                &r.acc_first);
+                                &r->acc_first);
        if (err < 0)
                return err;
 
        err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps",
-                                &r.acc_next);
+                                &r->acc_next);
        if (err < 0)
                return err;
 
-       err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps",
-                                &r.rd_setup);
-       if (err < 0)
-               return err;
-
-       err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps",
-                                &r.rd_hold);
-       if (err < 0)
-               return err;
-
-       /* Get write timings */
-       err = of_property_read_u32(node, "devbus,sync-enable",
-                                 &w.sync_enable);
-       if (err < 0) {
-               dev_err(devbus->dev,
-                       "%s has no 'devbus,sync-enable' property\n",
-                       node->full_name);
-               return err;
+       if (of_device_is_compatible(devbus->dev->of_node, "marvell,mvebu-devbus")) {
+               err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps",
+                                         &r->rd_setup);
+               if (err < 0)
+                       return err;
+
+               err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps",
+                                         &r->rd_hold);
+               if (err < 0)
+                       return err;
+
+               err = of_property_read_u32(node, "devbus,sync-enable",
+                                          &w->sync_enable);
+               if (err < 0) {
+                       dev_err(devbus->dev,
+                               "%s has no 'devbus,sync-enable' property\n",
+                               node->full_name);
+                       return err;
+               }
        }
 
        err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps",
-                                &w.ale_wr);
+                                &w->ale_wr);
        if (err < 0)
                return err;
 
        err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps",
-                                &w.wr_low);
+                                &w->wr_low);
        if (err < 0)
                return err;
 
        err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps",
-                                &w.wr_high);
+                                &w->wr_high);
        if (err < 0)
                return err;
 
+       return 0;
+}
+
+static void devbus_orion_set_timing_params(struct devbus *devbus,
+                                         struct device_node *node,
+                                         struct devbus_read_params *r,
+                                         struct devbus_write_params *w)
+{
+       u32 value;
+
+       /*
+        * The hardware designers found it would be a good idea to
+        * split most of the values in the register into two fields:
+        * one containing all the low-order bits, and another one
+        * containing just the high-order bit. For all of those
+        * fields, we have to split the value into these two parts.
+        */
+       value = (r->turn_off   & ORION_TURN_OFF_MASK)  << ORION_TURN_OFF_SHIFT  |
+               (r->acc_first  & ORION_ACC_FIRST_MASK) << ORION_ACC_FIRST_SHIFT |
+               (r->acc_next   & ORION_ACC_NEXT_MASK)  << ORION_ACC_NEXT_SHIFT  |
+               (w->ale_wr     & ORION_ALE_WR_MASK)    << ORION_ALE_WR_SHIFT    |
+               (w->wr_low     & ORION_WR_LOW_MASK)    << ORION_WR_LOW_SHIFT    |
+               (w->wr_high    & ORION_WR_HIGH_MASK)   << ORION_WR_HIGH_SHIFT   |
+               r->bus_width                           << ORION_DEV_WIDTH_SHIFT |
+               ((r->turn_off  & ORION_TURN_OFF_EXT_MASK)  ? ORION_TURN_OFF_EXT_BIT  : 0) |
+               ((r->acc_first & ORION_ACC_FIRST_EXT_MASK) ? ORION_ACC_FIRST_EXT_BIT : 0) |
+               ((r->acc_next  & ORION_ACC_NEXT_EXT_MASK)  ? ORION_ACC_NEXT_EXT_BIT  : 0) |
+               ((w->ale_wr    & ORION_ALE_WR_EXT_MASK)    ? ORION_ALE_WR_EXT_BIT    : 0) |
+               ((w->wr_low    & ORION_WR_LOW_EXT_MASK)    ? ORION_WR_LOW_EXT_BIT    : 0) |
+               ((w->wr_high   & ORION_WR_HIGH_EXT_MASK)   ? ORION_WR_HIGH_EXT_BIT   : 0) |
+               (r->badr_skew << ORION_BADR_SKEW_SHIFT) |
+               ORION_RESERVED;
+
+       writel(value, devbus->base);
+}
+
+static void devbus_armada_set_timing_params(struct devbus *devbus,
+                                          struct device_node *node,
+                                          struct devbus_read_params *r,
+                                          struct devbus_write_params *w)
+{
+       u32 value;
+
        /* Set read timings */
-       value = r.bus_width << DEV_WIDTH_BIT |
-               r.badr_skew << BADR_SKEW_BIT |
-               r.rd_hold   << RD_HOLD_BIT   |
-               r.acc_next  << ACC_NEXT_BIT  |
-               r.rd_setup  << RD_SETUP_BIT  |
-               r.acc_first << ACC_FIRST_BIT |
-               r.turn_off;
+       value = r->bus_width << ARMADA_DEV_WIDTH_SHIFT |
+               r->badr_skew << ARMADA_BADR_SKEW_SHIFT |
+               r->rd_hold   << ARMADA_RD_HOLD_SHIFT   |
+               r->acc_next  << ARMADA_ACC_NEXT_SHIFT  |
+               r->rd_setup  << ARMADA_RD_SETUP_SHIFT  |
+               r->acc_first << ARMADA_ACC_FIRST_SHIFT |
+               r->turn_off;
 
        dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x\n",
-               devbus->base + READ_PARAM_OFFSET,
+               devbus->base + ARMADA_READ_PARAM_OFFSET,
                value);
 
-       writel(value, devbus->base + READ_PARAM_OFFSET);
+       writel(value, devbus->base + ARMADA_READ_PARAM_OFFSET);
 
        /* Set write timings */
-       value = w.sync_enable  << SYNC_ENABLE_BIT |
-               w.wr_low       << WR_LOW_BIT      |
-               w.wr_high      << WR_HIGH_BIT     |
-               w.ale_wr;
+       value = w->sync_enable  << ARMADA_SYNC_ENABLE_SHIFT |
+               w->wr_low       << ARMADA_WR_LOW_SHIFT      |
+               w->wr_high      << ARMADA_WR_HIGH_SHIFT     |
+               w->ale_wr;
 
        dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x\n",
-               devbus->base + WRITE_PARAM_OFFSET,
+               devbus->base + ARMADA_WRITE_PARAM_OFFSET,
                value);
 
-       writel(value, devbus->base + WRITE_PARAM_OFFSET);
-
-       return 0;
+       writel(value, devbus->base + ARMADA_WRITE_PARAM_OFFSET);
 }
 
 static int mvebu_devbus_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *node = pdev->dev.of_node;
+       struct devbus_read_params r;
+       struct devbus_write_params w;
        struct devbus *devbus;
        struct resource *res;
        struct clk *clk;
@@ -229,10 +307,21 @@ static int mvebu_devbus_probe(struct platform_device *pdev)
        rate = clk_get_rate(clk) / 1000;
        devbus->tick_ps = 1000000000 / rate;
 
-       /* Read the device tree node and set the new timing parameters */
-       err = devbus_set_timing_params(devbus, node);
-       if (err < 0)
-               return err;
+       dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n",
+               devbus->tick_ps);
+
+       if (!of_property_read_bool(node, "devbus,keep-config")) {
+               /* Read the Device Tree node */
+               err = devbus_get_timing_params(devbus, node, &r, &w);
+               if (err < 0)
+                       return err;
+
+               /* Set the new timing parameters */
+               if (of_device_is_compatible(node, "marvell,orion-devbus"))
+                       devbus_orion_set_timing_params(devbus, node, &r, &w);
+               else
+                       devbus_armada_set_timing_params(devbus, node, &r, &w);
+       }
 
        /*
         * We need to create a child device explicitly from here to
@@ -248,6 +337,7 @@ static int mvebu_devbus_probe(struct platform_device *pdev)
 
 static const struct of_device_id mvebu_devbus_of_match[] = {
        { .compatible = "marvell,mvebu-devbus" },
+       { .compatible = "marvell,orion-devbus" },
        {},
 };
 MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match);
index 33834120d057117f5b98284227ee0e3ec59df371..bc9bbf6b5649bbdd17aaace9b34cad004a0948ef 100644 (file)
@@ -250,6 +250,16 @@ config MFD_INTEL_MSIC
          Passage) chip. This chip embeds audio, battery, GPIO, etc.
          devices used in Intel Medfield platforms.
 
+config MFD_IPAQ_MICRO
+       bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
+       depends on SA1100_H3100 || SA1100_H3600
+       select MFD_CORE
+       help
+         Select this to get support for the Microcontroller found in
+         the Compaq iPAQ handheld computers. This is an Atmel
+         AT90LS8535 microcontroller flashed with a special iPAQ
+         firmware using the custom protocol implemented in this driver.
+
 config MFD_JANZ_CMODIO
        tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
        select MFD_CORE
@@ -331,15 +341,15 @@ config MFD_88PM860X
          battery-charger under the corresponding menus.
 
 config MFD_MAX14577
-       bool "Maxim Semiconductor MAX14577 MUIC + Charger Support"
+       bool "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support"
        depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
        select IRQ_DOMAIN
        help
-         Say yes here to add support for Maxim Semiconductor MAX14577.
-         This is a Micro-USB IC with Charger controls on chip.
+         Say yes here to add support for Maxim Semiconductor MAX14577 and
+         MAX77836 Micro-USB ICs with battery charger.
          This driver provides common support for accessing the device;
          additional drivers must be enabled in order to use the functionality
          of the device.
index 2851275e2656f8d1f012fee8a7f740b857c21262..59132084f2cd61581686b6ca0ad94d78cc4e1f70 100644 (file)
@@ -166,3 +166,4 @@ obj-$(CONFIG_MFD_RETU)              += retu-mfd.o
 obj-$(CONFIG_MFD_AS3711)       += as3711.o
 obj-$(CONFIG_MFD_AS3722)       += as3722.o
 obj-$(CONFIG_MFD_STW481X)      += stw481x.o
+obj-$(CONFIG_MFD_IPAQ_MICRO)   += ipaq-micro.o
index 1c3ae57082ed7bc1a2dcd8583a507875f3b7d92b..07e6e27be23cbc178254c26dcf77031128eebf42 100644 (file)
@@ -508,19 +508,31 @@ int arizona_of_get_type(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(arizona_of_get_type);
 
+int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
+                             bool mandatory)
+{
+       int gpio;
+
+       gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
+       if (gpio < 0) {
+               if (mandatory)
+                       dev_err(arizona->dev,
+                               "Mandatory DT gpio %s missing/malformed: %d\n",
+                               prop, gpio);
+
+               gpio = 0;
+       }
+
+       return gpio;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
+
 static int arizona_of_get_core_pdata(struct arizona *arizona)
 {
+       struct arizona_pdata *pdata = &arizona->pdata;
        int ret, i;
 
-       arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
-                                                "wlf,reset", 0);
-       if (arizona->pdata.reset < 0)
-               arizona->pdata.reset = 0;
-
-       arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
-                                                 "wlf,ldoena", 0);
-       if (arizona->pdata.ldoena < 0)
-               arizona->pdata.ldoena = 0;
+       pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
 
        ret = of_property_read_u32_array(arizona->dev->of_node,
                                         "wlf,gpio-defaults",
@@ -652,6 +664,9 @@ int arizona_dev_init(struct arizona *arizona)
                return -EINVAL;
        }
 
+       /* Mark DCVDD as external, LDO1 driver will clear if internal */
+       arizona->external_dcvdd = true;
+
        ret = mfd_add_devices(arizona->dev, -1, early_devs,
                              ARRAY_SIZE(early_devs), NULL, 0, NULL);
        if (ret != 0) {
@@ -851,14 +866,6 @@ int arizona_dev_init(struct arizona *arizona)
                             arizona->pdata.gpio_defaults[i]);
        }
 
-       /*
-        * LDO1 can only be used to supply DCVDD so if it has no
-        * consumers then DCVDD is supplied externally.
-        */
-       if (arizona->pdata.ldo1 &&
-           arizona->pdata.ldo1->num_consumer_supplies == 0)
-               arizona->external_dcvdd = true;
-
        pm_runtime_set_autosuspend_delay(arizona->dev, 100);
        pm_runtime_use_autosuspend(arizona->dev);
        pm_runtime_enable(arizona->dev);
index e9a33c79431bfde8ed8cec42e7d09a3d2c8a3736..be4d0ac4874c608f10922c59f1e5d3263a8b1ec0 100644 (file)
@@ -64,6 +64,12 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c,
        return ret;
 }
 
+static int bcm590xx_i2c_remove(struct i2c_client *i2c)
+{
+       mfd_remove_devices(&i2c->dev);
+       return 0;
+}
+
 static const struct of_device_id bcm590xx_of_match[] = {
        { .compatible = "brcm,bcm59056" },
        { }
@@ -83,6 +89,7 @@ static struct i2c_driver bcm590xx_i2c_driver = {
                   .of_match_table = of_match_ptr(bcm590xx_of_match),
        },
        .probe = bcm590xx_i2c_probe,
+       .remove = bcm590xx_i2c_remove,
        .id_table = bcm590xx_i2c_id,
 };
 module_i2c_driver(bcm590xx_i2c_driver);
@@ -90,4 +97,4 @@ module_i2c_driver(bcm590xx_i2c_driver);
 MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
 MODULE_DESCRIPTION("BCM590xx multi-function driver");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bcm590xx");
+MODULE_ALIAS("i2c:bcm590xx");
index 783fe2e73e1edd43344d3bb4c3b1fb09daf9cf3d..fae69b1db5b142746de137a3b45cd217ff004b59 100644 (file)
@@ -184,3 +184,6 @@ int cros_ec_resume(struct cros_ec_device *ec_dev)
 EXPORT_SYMBOL(cros_ec_resume);
 
 #endif
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ChromeOS EC core driver");
index 7694e0700d340329c5696c4ccba0417f9f93486f..b11fdd63eecdaa68b58cdefd9af1204c2bf69887 100644 (file)
@@ -1734,18 +1734,17 @@ static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
 
 static long round_armss_rate(unsigned long rate)
 {
+       struct cpufreq_frequency_table *pos;
        long freq = 0;
-       int i = 0;
 
        /* cpufreq table frequencies is in KHz. */
        rate = rate / 1000;
 
        /* Find the corresponding arm opp from the cpufreq table. */
-       while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
-               freq = db8500_cpufreq_table[i].frequency;
+       cpufreq_for_each_entry(pos, db8500_cpufreq_table) {
+               freq = pos->frequency;
                if (freq == rate)
                        break;
-               i++;
        }
 
        /* Return the last valid value, even if a match was not found. */
@@ -1886,23 +1885,21 @@ static void set_clock_rate(u8 clock, unsigned long rate)
 
 static int set_armss_rate(unsigned long rate)
 {
-       int i = 0;
+       struct cpufreq_frequency_table *pos;
 
        /* cpufreq table frequencies is in KHz. */
        rate = rate / 1000;
 
        /* Find the corresponding arm opp from the cpufreq table. */
-       while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
-               if (db8500_cpufreq_table[i].frequency == rate)
+       cpufreq_for_each_entry(pos, db8500_cpufreq_table)
+               if (pos->frequency == rate)
                        break;
-               i++;
-       }
 
-       if (db8500_cpufreq_table[i].frequency != rate)
+       if (pos->frequency != rate)
                return -EINVAL;
 
        /* Set the new arm opp. */
-       return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data);
+       return db8500_prcmu_set_arm_opp(pos->driver_data);
 }
 
 static int set_plldsi_rate(unsigned long rate)
diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c
new file mode 100644 (file)
index 0000000..1763d6d
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * Compaq iPAQ h3xxx Atmel microcontroller companion support
+ *
+ * This is an Atmel AT90LS8535 with a special flashed-in firmware that
+ * implements the special protocol used by this driver.
+ *
+ * based on previous kernel 2.4 version by Andrew Christian
+ * Author : Alessandro Gardich <gremlin@gremlin.it>
+ * Author : Dmitry Artamonow <mad_soft@inbox.ru>
+ * Author : Linus Walleij <linus.walleij@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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ipaq-micro.h>
+#include <linux/string.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <mach/hardware.h>
+
+static void ipaq_micro_trigger_tx(struct ipaq_micro *micro)
+{
+       struct ipaq_micro_txdev *tx = &micro->tx;
+       struct ipaq_micro_msg *msg = micro->msg;
+       int i, bp;
+       u8 checksum;
+       u32 val;
+
+       bp = 0;
+       tx->buf[bp++] = CHAR_SOF;
+
+       checksum = ((msg->id & 0x0f) << 4) | (msg->tx_len & 0x0f);
+       tx->buf[bp++] = checksum;
+
+       for (i = 0; i < msg->tx_len; i++) {
+               tx->buf[bp++] = msg->tx_data[i];
+               checksum += msg->tx_data[i];
+       }
+
+       tx->buf[bp++] = checksum;
+       tx->len = bp;
+       tx->index = 0;
+       print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1,
+                      tx->buf, tx->len, true);
+
+       /* Enable interrupt */
+       val = readl(micro->base + UTCR3);
+       val |= UTCR3_TIE;
+       writel(val, micro->base + UTCR3);
+}
+
+int ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg)
+{
+       unsigned long flags;
+
+       dev_dbg(micro->dev, "TX msg: %02x, %d bytes\n", msg->id, msg->tx_len);
+
+       spin_lock_irqsave(&micro->lock, flags);
+       if (micro->msg) {
+               list_add_tail(&msg->node, &micro->queue);
+               spin_unlock_irqrestore(&micro->lock, flags);
+               return 0;
+       }
+       micro->msg = msg;
+       ipaq_micro_trigger_tx(micro);
+       spin_unlock_irqrestore(&micro->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL(ipaq_micro_tx_msg);
+
+static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data)
+{
+       int i;
+
+       dev_dbg(micro->dev, "RX msg: %02x, %d bytes\n", id, len);
+
+       spin_lock(&micro->lock);
+       switch (id) {
+       case MSG_VERSION:
+       case MSG_EEPROM_READ:
+       case MSG_EEPROM_WRITE:
+       case MSG_BACKLIGHT:
+       case MSG_NOTIFY_LED:
+       case MSG_THERMAL_SENSOR:
+       case MSG_BATTERY:
+               /* Handle synchronous messages */
+               if (micro->msg && micro->msg->id == id) {
+                       struct ipaq_micro_msg *msg = micro->msg;
+
+                       memcpy(msg->rx_data, data, len);
+                       msg->rx_len = len;
+                       complete(&micro->msg->ack);
+                       if (!list_empty(&micro->queue)) {
+                               micro->msg = list_entry(micro->queue.next,
+                                                       struct ipaq_micro_msg,
+                                                       node);
+                               list_del_init(&micro->msg->node);
+                               ipaq_micro_trigger_tx(micro);
+                       } else
+                               micro->msg = NULL;
+                       dev_dbg(micro->dev, "OK RX message 0x%02x\n", id);
+               } else {
+                       dev_err(micro->dev,
+                               "out of band RX message 0x%02x\n", id);
+                       if(!micro->msg)
+                               dev_info(micro->dev, "no message queued\n");
+                       else
+                               dev_info(micro->dev, "expected message %02x\n",
+                                        micro->msg->id);
+               }
+               break;
+       case MSG_KEYBOARD:
+               if (micro->key)
+                       micro->key(micro->key_data, len, data);
+               else
+                       dev_dbg(micro->dev, "key message ignored, no handle \n");
+               break;
+       case MSG_TOUCHSCREEN:
+               if (micro->ts)
+                       micro->ts(micro->ts_data, len, data);
+               else
+                       dev_dbg(micro->dev, "touchscreen message ignored, no handle \n");
+               break;
+       default:
+               dev_err(micro->dev,
+                       "unknown msg %d [%d] ", id, len);
+               for (i = 0; i < len; ++i)
+                       pr_cont("0x%02x ", data[i]);
+               pr_cont("\n");
+       }
+       spin_unlock(&micro->lock);
+}
+
+static void micro_process_char(struct ipaq_micro *micro, u8 ch)
+{
+       struct ipaq_micro_rxdev *rx = &micro->rx;
+
+       switch (rx->state) {
+       case STATE_SOF: /* Looking for SOF */
+               if (ch == CHAR_SOF)
+                       rx->state = STATE_ID; /* Next byte is the id and len */
+               break;
+       case STATE_ID: /* Looking for id and len byte */
+               rx->id = (ch & 0xf0) >> 4 ;
+               rx->len = (ch & 0x0f);
+               rx->index = 0;
+               rx->chksum = ch;
+               rx->state = (rx->len > 0) ? STATE_DATA : STATE_CHKSUM;
+               break;
+       case STATE_DATA: /* Looking for 'len' data bytes */
+               rx->chksum += ch;
+               rx->buf[rx->index] = ch;
+               if (++rx->index == rx->len)
+                       rx->state = STATE_CHKSUM;
+               break;
+       case STATE_CHKSUM: /* Looking for the checksum */
+               if (ch == rx->chksum)
+                       micro_rx_msg(micro, rx->id, rx->len, rx->buf);
+               rx->state = STATE_SOF;
+               break;
+       }
+}
+
+static void micro_rx_chars(struct ipaq_micro *micro)
+{
+       u32 status, ch;
+
+       while ((status = readl(micro->base + UTSR1)) & UTSR1_RNE) {
+               ch = readl(micro->base + UTDR);
+               if (status & UTSR1_PRE)
+                       dev_err(micro->dev, "rx: parity error\n");
+               else if (status & UTSR1_FRE)
+                       dev_err(micro->dev, "rx: framing error\n");
+               else if (status & UTSR1_ROR)
+                       dev_err(micro->dev, "rx: overrun error\n");
+               micro_process_char(micro, ch);
+       }
+}
+
+static void ipaq_micro_get_version(struct ipaq_micro *micro)
+{
+       struct ipaq_micro_msg msg = {
+               .id = MSG_VERSION,
+       };
+
+       ipaq_micro_tx_msg_sync(micro, &msg);
+       if (msg.rx_len == 4) {
+               memcpy(micro->version, msg.rx_data, 4);
+               micro->version[4] = '\0';
+       } else if (msg.rx_len == 9) {
+               memcpy(micro->version, msg.rx_data, 4);
+               micro->version[4] = '\0';
+               /* Bytes 4-7 are "pack", byte 8 is "boot type" */
+       } else {
+               dev_err(micro->dev,
+                       "illegal version message %d bytes\n", msg.rx_len);
+       }
+}
+
+static void ipaq_micro_eeprom_read(struct ipaq_micro *micro,
+                                  u8 address, u8 len, u8 *data)
+{
+       struct ipaq_micro_msg msg = {
+               .id = MSG_EEPROM_READ,
+       };
+       u8 i;
+
+       for (i = 0; i < len; i++) {
+               msg.tx_data[0] = address + i;
+               msg.tx_data[1] = 1;
+               msg.tx_len = 2;
+               ipaq_micro_tx_msg_sync(micro, &msg);
+               memcpy(data + (i * 2), msg.rx_data, 2);
+       }
+}
+
+static char *ipaq_micro_str(u8 *wchar, u8 len)
+{
+       char retstr[256];
+       u8 i;
+
+       for (i = 0; i < len / 2; i++)
+               retstr[i] = wchar[i * 2];
+       return kstrdup(retstr, GFP_KERNEL);
+}
+
+static u16 ipaq_micro_to_u16(u8 *data)
+{
+       return data[1] << 8 | data[0];
+}
+
+static void ipaq_micro_eeprom_dump(struct ipaq_micro *micro)
+{
+       u8 dump[256];
+       char *str;
+
+       ipaq_micro_eeprom_read(micro, 0, 128, dump);
+       str = ipaq_micro_str(dump, 10);
+       if (str) {
+               dev_info(micro->dev, "HM version %s\n", str);
+               kfree(str);
+       }
+       str = ipaq_micro_str(dump+10, 40);
+       if (str) {
+               dev_info(micro->dev, "serial number: %s\n", str);
+               /* Feed the random pool with this */
+               add_device_randomness(str, strlen(str));
+               kfree(str);
+       }
+       str = ipaq_micro_str(dump+50, 20);
+       if (str) {
+               dev_info(micro->dev, "module ID: %s\n", str);
+               kfree(str);
+       }
+       str = ipaq_micro_str(dump+70, 10);
+       if (str) {
+               dev_info(micro->dev, "product revision: %s\n", str);
+               kfree(str);
+       }
+       dev_info(micro->dev, "product ID: %u\n", ipaq_micro_to_u16(dump+80));
+       dev_info(micro->dev, "frame rate: %u fps\n",
+                ipaq_micro_to_u16(dump+82));
+       dev_info(micro->dev, "page mode: %u\n", ipaq_micro_to_u16(dump+84));
+       dev_info(micro->dev, "country ID: %u\n", ipaq_micro_to_u16(dump+86));
+       dev_info(micro->dev, "color display: %s\n",
+                ipaq_micro_to_u16(dump+88) ? "yes" : "no");
+       dev_info(micro->dev, "ROM size: %u MiB\n", ipaq_micro_to_u16(dump+90));
+       dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92));
+       dev_info(micro->dev, "screen: %u x %u\n",
+                ipaq_micro_to_u16(dump+94), ipaq_micro_to_u16(dump+96));
+       print_hex_dump(KERN_DEBUG, "eeprom: ", DUMP_PREFIX_OFFSET, 16, 1,
+                      dump, 256, true);
+
+}
+
+static void micro_tx_chars(struct ipaq_micro *micro)
+{
+       struct ipaq_micro_txdev *tx = &micro->tx;
+       u32 val;
+
+       while ((tx->index < tx->len) &&
+              (readl(micro->base + UTSR1) & UTSR1_TNF)) {
+               writel(tx->buf[tx->index], micro->base + UTDR);
+               tx->index++;
+       }
+
+       /* Stop interrupts */
+       val = readl(micro->base + UTCR3);
+       val &= ~UTCR3_TIE;
+       writel(val, micro->base + UTCR3);
+}
+
+static void micro_reset_comm(struct ipaq_micro *micro)
+{
+       struct ipaq_micro_rxdev *rx = &micro->rx;
+       u32 val;
+
+       if (micro->msg)
+               complete(&micro->msg->ack);
+
+       /* Initialize Serial channel protocol frame */
+       rx->state = STATE_SOF;  /* Reset the state machine */
+
+       /* Set up interrupts */
+       writel(0x01, micro->sdlc + 0x0); /* Select UART mode */
+
+       /* Clean up CR3 */
+       writel(0x0, micro->base + UTCR3);
+
+       /* Format: 8N1 */
+       writel(UTCR0_8BitData | UTCR0_1StpBit, micro->base + UTCR0);
+
+       /* Baud rate: 115200 */
+       writel(0x0, micro->base + UTCR1);
+       writel(0x1, micro->base + UTCR2);
+
+       /* Clear SR0 */
+       writel(0xff, micro->base + UTSR0);
+
+       /* Enable RX int, disable TX int */
+       writel(UTCR3_TXE | UTCR3_RXE | UTCR3_RIE, micro->base + UTCR3);
+       val = readl(micro->base + UTCR3);
+       val &= ~UTCR3_TIE;
+       writel(val, micro->base + UTCR3);
+}
+
+static irqreturn_t micro_serial_isr(int irq, void *dev_id)
+{
+       struct ipaq_micro *micro = dev_id;
+       struct ipaq_micro_txdev *tx = &micro->tx;
+       u32 status;
+
+       status = readl(micro->base + UTSR0);
+       do {
+               if (status & (UTSR0_RID | UTSR0_RFS)) {
+                       if (status & UTSR0_RID)
+                               /* Clear the Receiver IDLE bit */
+                               writel(UTSR0_RID, micro->base + UTSR0);
+                       micro_rx_chars(micro);
+               }
+
+               /* Clear break bits */
+               if (status & (UTSR0_RBB | UTSR0_REB))
+                       writel(status & (UTSR0_RBB | UTSR0_REB),
+                              micro->base + UTSR0);
+
+               if (status & UTSR0_TFS)
+                       micro_tx_chars(micro);
+
+               status = readl(micro->base + UTSR0);
+
+       } while (((tx->index < tx->len) && (status & UTSR0_TFS)) ||
+                (status & (UTSR0_RFS | UTSR0_RID)));
+
+       return IRQ_HANDLED;
+}
+
+static struct mfd_cell micro_cells[] = {
+       { .name = "ipaq-micro-backlight", },
+       { .name = "ipaq-micro-battery", },
+       { .name = "ipaq-micro-keys", },
+       { .name = "ipaq-micro-ts", },
+       { .name = "ipaq-micro-leds", },
+};
+
+static int micro_resume(struct device *dev)
+{
+       struct ipaq_micro *micro = dev_get_drvdata(dev);
+
+       micro_reset_comm(micro);
+       mdelay(10);
+
+       return 0;
+}
+
+static int micro_probe(struct platform_device *pdev)
+{
+       struct ipaq_micro *micro;
+       struct resource *res;
+       int ret;
+       int irq;
+
+       micro = devm_kzalloc(&pdev->dev, sizeof(*micro), GFP_KERNEL);
+       if (!micro)
+               return -ENOMEM;
+
+       micro->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
+       micro->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!micro->base)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res)
+               return -EINVAL;
+
+       micro->sdlc = devm_request_and_ioremap(&pdev->dev, res);
+       if (!micro->sdlc)
+               return -ENOMEM;
+
+       micro_reset_comm(micro);
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -EINVAL;
+       ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr,
+                              IRQF_SHARED, "ipaq-micro",
+                              micro);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to grab serial port IRQ\n");
+               return ret;
+       } else
+               dev_info(&pdev->dev, "grabbed serial port IRQ\n");
+
+       spin_lock_init(&micro->lock);
+       INIT_LIST_HEAD(&micro->queue);
+       platform_set_drvdata(pdev, micro);
+
+       ret = mfd_add_devices(&pdev->dev, pdev->id, micro_cells,
+                             ARRAY_SIZE(micro_cells), NULL, 0, NULL);
+       if (ret) {
+               dev_err(&pdev->dev, "error adding MFD cells");
+               return ret;
+       }
+
+       /* Check version */
+       ipaq_micro_get_version(micro);
+       dev_info(&pdev->dev, "Atmel micro ASIC version %s\n", micro->version);
+       ipaq_micro_eeprom_dump(micro);
+
+       return 0;
+}
+
+static int micro_remove(struct platform_device *pdev)
+{
+       struct ipaq_micro *micro = platform_get_drvdata(pdev);
+       u32 val;
+
+       mfd_remove_devices(&pdev->dev);
+
+       val = readl(micro->base + UTCR3);
+       val &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */
+       val &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */
+       writel(val, micro->base + UTCR3);
+
+       return 0;
+}
+
+static const struct dev_pm_ops micro_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(NULL, micro_resume)
+};
+
+static struct platform_driver micro_device_driver = {
+       .driver   = {
+               .name   = "ipaq-h3xxx-micro",
+               .pm     = &micro_dev_pm_ops,
+       },
+       .probe    = micro_probe,
+       .remove   = micro_remove,
+       /* .shutdown = micro_suspend, // FIXME */
+};
+module_platform_driver(micro_device_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight");
index 07692604e119123a1f9b311b2611c5d0103daa78..25c5ca6797da702498fc388aba0f8915979bb6d5 100644 (file)
@@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex);
  */
 static int kempld_get_info(struct kempld_device_data *pld)
 {
+       int ret;
        struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
+       char major, minor;
+
+       ret = pdata->get_info(pld);
+       if (ret)
+               return ret;
+
+       /* The Kontron PLD firmware version string has the following format:
+        * Pwxy.zzzz
+        *   P:    Fixed
+        *   w:    PLD number    - 1 hex digit
+        *   x:    Major version - 1 alphanumerical digit (0-9A-V)
+        *   y:    Minor version - 1 alphanumerical digit (0-9A-V)
+        *   zzzz: Build number  - 4 zero padded hex digits */
 
-       return pdata->get_info(pld);
+       if (pld->info.major < 10)
+               major = pld->info.major + '0';
+       else
+               major = (pld->info.major - 10) + 'A';
+       if (pld->info.minor < 10)
+               minor = pld->info.minor + '0';
+       else
+               minor = (pld->info.minor - 10) + 'A';
+
+       ret = scnprintf(pld->info.version, sizeof(pld->info.version),
+                       "P%X%c%c.%04X", pld->info.number, major, minor,
+                       pld->info.buildnr);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 /*
@@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld)
        return pdata->register_cells(pld);
 }
 
+static const char *kempld_get_type_string(struct kempld_device_data *pld)
+{
+       const char *version_type;
+
+       switch (pld->info.type) {
+       case 0:
+               version_type = "release";
+               break;
+       case 1:
+               version_type = "debug";
+               break;
+       case 2:
+               version_type = "custom";
+               break;
+       default:
+               version_type = "unspecified";
+               break;
+       }
+
+       return version_type;
+}
+
+static ssize_t kempld_version_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
+}
+
+static ssize_t kempld_specification_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
+                      pld->info.spec_minor);
+}
+
+static ssize_t kempld_type_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
+}
+
+static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL);
+static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show,
+                  NULL);
+static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL);
+
+static struct attribute *pld_attributes[] = {
+       &dev_attr_pld_version.attr,
+       &dev_attr_pld_specification.attr,
+       &dev_attr_pld_type.attr,
+       NULL
+};
+
+static const struct attribute_group pld_attr_group = {
+       .attrs = pld_attributes,
+};
+
 static int kempld_detect_device(struct kempld_device_data *pld)
 {
-       char *version_type;
        u8 index_reg;
        int ret;
 
@@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld)
        if (ret)
                return ret;
 
-       switch (pld->info.type) {
-       case 0:
-               version_type = "release";
-               break;
-       case 1:
-               version_type = "debug";
-               break;
-       case 2:
-               version_type = "custom";
-               break;
-       default:
-               version_type = "unspecified";
-       }
+       dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
+                pld->info.version, kempld_get_type_string(pld),
+                pld->info.spec_major, pld->info.spec_minor);
+
+       ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
+       if (ret)
+               return ret;
 
-       dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number);
-       dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n",
-                version_type, pld->info.major, pld->info.minor,
-                pld->info.buildnr, pld->info.spec_major,
-                pld->info.spec_minor);
+       ret = kempld_register_cells(pld);
+       if (ret)
+               sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
 
-       return kempld_register_cells(pld);
+       return ret;
 }
 
 static int kempld_probe(struct platform_device *pdev)
@@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev)
        struct kempld_device_data *pld = platform_get_drvdata(pdev);
        struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
+       sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
+
        mfd_remove_devices(&pdev->dev);
        pdata->release_hardware_mutex(pld);
 
index 3f10ea3f45d1ae672ca5adc6e96cb9fade1662c2..7d8482ff5868829dfa03294a55a3aafb8da0b2ef 100644 (file)
@@ -488,6 +488,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_PPT] = {
                .name = "Panther Point",
                .iTCO_version = 2,
+               .gpio_version = ICH_V5_GPIO,
        },
        [LPC_LPT] = {
                .name = "Lynx Point",
index 5f13cefe8defcf73ed33e1c179de6b922f88b1fc..484d372a4892b642b0f064dd327ee7195e1ae0de 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * max14577.c - mfd core driver for the Maxim 14577
+ * max14577.c - mfd core driver for the Maxim 14577/77836
  *
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2014 Samsung Electrnoics
  * Chanwoo Choi <cw00.choi@samsung.com>
  * Krzysztof Kozlowski <k.kozlowski@samsung.com>
  *
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/of_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/max14577.h>
 #include <linux/mfd/max14577-private.h>
@@ -37,7 +38,38 @@ static struct mfd_cell max14577_devs[] = {
        { .name = "max14577-charger", },
 };
 
-static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
+static struct mfd_cell max77836_devs[] = {
+       {
+               .name = "max77836-muic",
+               .of_compatible = "maxim,max77836-muic",
+       },
+       {
+               .name = "max77836-regulator",
+               .of_compatible = "maxim,max77836-regulator",
+       },
+       {
+               .name = "max77836-charger",
+               .of_compatible = "maxim,max77836-charger",
+       },
+       {
+               .name = "max77836-battery",
+               .of_compatible = "maxim,max77836-battery",
+       },
+};
+
+static struct of_device_id max14577_dt_match[] = {
+       {
+               .compatible = "maxim,max14577",
+               .data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
+       },
+       {
+               .compatible = "maxim,max77836",
+               .data = (void *)MAXIM_DEVICE_TYPE_MAX77836,
+       },
+       {},
+};
+
+static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
@@ -48,49 +80,221 @@ static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
        return false;
 }
 
-static const struct regmap_config max14577_regmap_config = {
+static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg)
+{
+       /* Any max14577 volatile registers are also max77836 volatile. */
+       if (max14577_muic_volatile_reg(dev, reg))
+               return true;
+
+       switch (reg) {
+       case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB:
+       case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB:
+       case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L:
+       case MAX77836_PMIC_REG_INTSRC:
+       case MAX77836_PMIC_REG_TOPSYS_INT:
+       case MAX77836_PMIC_REG_TOPSYS_STAT:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+static const struct regmap_config max14577_muic_regmap_config = {
        .reg_bits       = 8,
        .val_bits       = 8,
-       .volatile_reg   = max14577_volatile_reg,
+       .volatile_reg   = max14577_muic_volatile_reg,
        .max_register   = MAX14577_REG_END,
 };
 
+static const struct regmap_config max77836_pmic_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .volatile_reg   = max77836_muic_volatile_reg,
+       .max_register   = MAX77836_PMIC_REG_END,
+};
+
 static const struct regmap_irq max14577_irqs[] = {
        /* INT1 interrupts */
-       { .reg_offset = 0, .mask = INT1_ADC_MASK, },
-       { .reg_offset = 0, .mask = INT1_ADCLOW_MASK, },
-       { .reg_offset = 0, .mask = INT1_ADCERR_MASK, },
+       { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
+       { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
+       { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
        /* INT2 interrupts */
-       { .reg_offset = 1, .mask = INT2_CHGTYP_MASK, },
-       { .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, },
-       { .reg_offset = 1, .mask = INT2_DCDTMR_MASK, },
-       { .reg_offset = 1, .mask = INT2_DBCHG_MASK, },
-       { .reg_offset = 1, .mask = INT2_VBVOLT_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
        /* INT3 interrupts */
-       { .reg_offset = 2, .mask = INT3_EOC_MASK, },
-       { .reg_offset = 2, .mask = INT3_CGMBC_MASK, },
-       { .reg_offset = 2, .mask = INT3_OVP_MASK, },
-       { .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
 };
 
 static const struct regmap_irq_chip max14577_irq_chip = {
        .name                   = "max14577",
        .status_base            = MAX14577_REG_INT1,
        .mask_base              = MAX14577_REG_INTMASK1,
-       .mask_invert            = 1,
+       .mask_invert            = true,
        .num_regs               = 3,
        .irqs                   = max14577_irqs,
        .num_irqs               = ARRAY_SIZE(max14577_irqs),
 };
 
+static const struct regmap_irq max77836_muic_irqs[] = {
+       /* INT1 interrupts */
+       { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
+       { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
+       { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
+       { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
+       /* INT2 interrupts */
+       { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
+       { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
+       { .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, },
+       /* INT3 interrupts */
+       { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
+       { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
+};
+
+static const struct regmap_irq_chip max77836_muic_irq_chip = {
+       .name                   = "max77836-muic",
+       .status_base            = MAX14577_REG_INT1,
+       .mask_base              = MAX14577_REG_INTMASK1,
+       .mask_invert            = true,
+       .num_regs               = 3,
+       .irqs                   = max77836_muic_irqs,
+       .num_irqs               = ARRAY_SIZE(max77836_muic_irqs),
+};
+
+static const struct regmap_irq max77836_pmic_irqs[] = {
+       { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, },
+       { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, },
+};
+
+static const struct regmap_irq_chip max77836_pmic_irq_chip = {
+       .name                   = "max77836-pmic",
+       .status_base            = MAX77836_PMIC_REG_TOPSYS_INT,
+       .mask_base              = MAX77836_PMIC_REG_TOPSYS_INT_MASK,
+       .mask_invert            = false,
+       .num_regs               = 1,
+       .irqs                   = max77836_pmic_irqs,
+       .num_irqs               = ARRAY_SIZE(max77836_pmic_irqs),
+};
+
+static void max14577_print_dev_type(struct max14577 *max14577)
+{
+       u8 reg_data, vendor_id, device_id;
+       int ret;
+
+       ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
+                       &reg_data);
+       if (ret) {
+               dev_err(max14577->dev,
+                       "Failed to read DEVICEID register: %d\n", ret);
+               return;
+       }
+
+       vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
+                               DEVID_VENDORID_SHIFT);
+       device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
+                               DEVID_DEVICEID_SHIFT);
+
+       dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n",
+                       max14577->dev_type, device_id, vendor_id);
+}
+
+/*
+ * Max77836 specific initialization code for driver probe.
+ * Adds new I2C dummy device, regmap and regmap IRQ chip.
+ * Unmasks Interrupt Source register.
+ *
+ * On success returns 0.
+ * On failure returns errno and reverts any changes done so far (e.g. remove
+ * I2C dummy device), except masking the INT SRC register.
+ */
+static int max77836_init(struct max14577 *max14577)
+{
+       int ret;
+       u8 intsrc_mask;
+
+       max14577->i2c_pmic = i2c_new_dummy(max14577->i2c->adapter,
+                       I2C_ADDR_PMIC);
+       if (!max14577->i2c_pmic) {
+               dev_err(max14577->dev, "Failed to register PMIC I2C device\n");
+               return -ENODEV;
+       }
+       i2c_set_clientdata(max14577->i2c_pmic, max14577);
+
+       max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic,
+                       &max77836_pmic_regmap_config);
+       if (IS_ERR(max14577->regmap_pmic)) {
+               ret = PTR_ERR(max14577->regmap_pmic);
+               dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n",
+                               ret);
+               goto err;
+       }
+
+       /* Un-mask MAX77836 Interrupt Source register */
+       ret = max14577_read_reg(max14577->regmap_pmic,
+                       MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask);
+       if (ret < 0) {
+               dev_err(max14577->dev, "Failed to read PMIC register\n");
+               goto err;
+       }
+
+       intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK);
+       intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK);
+       ret = max14577_write_reg(max14577->regmap_pmic,
+                       MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask);
+       if (ret < 0) {
+               dev_err(max14577->dev, "Failed to write PMIC register\n");
+               goto err;
+       }
+
+       ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq,
+                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED,
+                       0, &max77836_pmic_irq_chip,
+                       &max14577->irq_data_pmic);
+       if (ret != 0) {
+               dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n",
+                               max14577->irq, ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       i2c_unregister_device(max14577->i2c_pmic);
+
+       return ret;
+}
+
+/*
+ * Max77836 specific de-initialization code for driver remove.
+ */
+static void max77836_remove(struct max14577 *max14577)
+{
+       regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic);
+       i2c_unregister_device(max14577->i2c_pmic);
+}
+
 static int max14577_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
        struct max14577 *max14577;
        struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct device_node *np = i2c->dev.of_node;
-       u8 reg_data;
        int ret = 0;
+       const struct regmap_irq_chip *irq_chip;
+       struct mfd_cell *mfd_devs;
+       unsigned int mfd_devs_size;
+       int irq_flags;
 
        if (np) {
                pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
@@ -113,7 +317,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
        max14577->i2c = i2c;
        max14577->irq = i2c->irq;
 
-       max14577->regmap = devm_regmap_init_i2c(i2c, &max14577_regmap_config);
+       max14577->regmap = devm_regmap_init_i2c(i2c,
+                       &max14577_muic_regmap_config);
        if (IS_ERR(max14577->regmap)) {
                ret = PTR_ERR(max14577->regmap);
                dev_err(max14577->dev, "Failed to allocate register map: %d\n",
@@ -121,23 +326,36 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
-                       &reg_data);
-       if (ret) {
-               dev_err(max14577->dev, "Device not found on this channel: %d\n",
-                               ret);
-               return ret;
+       if (np) {
+               const struct of_device_id *of_id;
+
+               of_id = of_match_device(max14577_dt_match, &i2c->dev);
+               if (of_id)
+                       max14577->dev_type = (unsigned int)of_id->data;
+       } else {
+               max14577->dev_type = id->driver_data;
+       }
+
+       max14577_print_dev_type(max14577);
+
+       switch (max14577->dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               irq_chip = &max77836_muic_irq_chip;
+               mfd_devs = max77836_devs;
+               mfd_devs_size = ARRAY_SIZE(max77836_devs);
+               irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
+               break;
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               irq_chip = &max14577_irq_chip;
+               mfd_devs = max14577_devs;
+               mfd_devs_size = ARRAY_SIZE(max14577_devs);
+               irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+               break;
        }
-       max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
-                               DEVID_VENDORID_SHIFT);
-       max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
-                               DEVID_DEVICEID_SHIFT);
-       dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n",
-                       max14577->device_id, max14577->vendor_id);
 
        ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
-                                 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
-                                 &max14577_irq_chip,
+                                 irq_flags, 0, irq_chip,
                                  &max14577->irq_data);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
@@ -145,8 +363,15 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       ret = mfd_add_devices(max14577->dev, -1, max14577_devs,
-                       ARRAY_SIZE(max14577_devs), NULL, 0,
+       /* Max77836 specific initialization code (additional regmap) */
+       if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) {
+               ret = max77836_init(max14577);
+               if (ret < 0)
+                       goto err_max77836;
+       }
+
+       ret = mfd_add_devices(max14577->dev, -1, mfd_devs,
+                       mfd_devs_size, NULL, 0,
                        regmap_irq_get_domain(max14577->irq_data));
        if (ret < 0)
                goto err_mfd;
@@ -156,6 +381,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
        return 0;
 
 err_mfd:
+       if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
+               max77836_remove(max14577);
+err_max77836:
        regmap_del_irq_chip(max14577->irq, max14577->irq_data);
 
        return ret;
@@ -167,12 +395,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
 
        mfd_remove_devices(max14577->dev);
        regmap_del_irq_chip(max14577->irq, max14577->irq_data);
+       if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
+               max77836_remove(max14577);
 
        return 0;
 }
 
 static const struct i2c_device_id max14577_i2c_id[] = {
-       { "max14577", 0 },
+       { "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
+       { "max77836", MAXIM_DEVICE_TYPE_MAX77836, },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
@@ -215,11 +446,6 @@ static int max14577_resume(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-static struct of_device_id max14577_dt_match[] = {
-       { .compatible = "maxim,max14577", },
-       {},
-};
-
 static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
 
 static struct i2c_driver max14577_i2c_driver = {
@@ -236,6 +462,9 @@ static struct i2c_driver max14577_i2c_driver = {
 
 static int __init max14577_i2c_init(void)
 {
+       BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
+       BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);
+
        return i2c_add_driver(&max14577_i2c_driver);
 }
 subsys_initcall(max14577_i2c_init);
@@ -247,5 +476,5 @@ static void __exit max14577_i2c_exit(void)
 module_exit(max14577_i2c_exit);
 
 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver");
+MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
 MODULE_LICENSE("GPL");
index 06e64b6fcb89d66aaa7299bb1384acc26b47884b..ddabc8157eb0133abe12c1f6ef55e261006229ca 100644 (file)
@@ -660,22 +660,26 @@ int mc13xxx_common_init(struct device *dev)
        if (ret)
                return ret;
 
+       mutex_init(&mc13xxx->lock);
+
        ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
                        IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
        if (ret)
                return ret;
 
-       mutex_init(&mc13xxx->lock);
-
        if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
                mc13xxx->flags = pdata->flags;
 
        if (mc13xxx->flags & MC13XXX_USE_ADC)
                mc13xxx_add_subdevice(mc13xxx, "%s-adc");
 
-       if (mc13xxx->flags & MC13XXX_USE_CODEC)
-               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
-                                       pdata->codec, sizeof(*pdata->codec));
+       if (mc13xxx->flags & MC13XXX_USE_CODEC) {
+               if (pdata)
+                       mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+                               pdata->codec, sizeof(*pdata->codec));
+               else
+                       mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+       }
 
        if (mc13xxx->flags & MC13XXX_USE_RTC)
                mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
index b53b9d46cc4534671066ae03950fb44f25f36af9..141ea52c46e3affedc153b2c00e8640d111fb144 100644 (file)
@@ -67,7 +67,7 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
        ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
        add_timer(&ucr->sg_timer);
        usb_sg_wait(&ucr->current_sg);
-       del_timer(&ucr->sg_timer);
+       del_timer_sync(&ucr->sg_timer);
 
        if (act_len)
                *act_len = ucr->current_sg.bytes;
@@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf,
        if (ret)
                goto out_init_fail;
 
+       /* initialize USB SG transfer timer */
+       setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
+
        ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
                        ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
        if (ret)
                goto out_init_fail;
 
-       /* initialize USB SG transfer timer */
-       init_timer(&ucr->sg_timer);
-       setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
 #ifdef CONFIG_PM
        intf->needs_remote_wakeup = 1;
        usb_enable_autosuspend(usb_dev);
@@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
        dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
                        __func__, message.event);
 
+       /*
+        * Call to make sure LED is off during suspend to save more power.
+        * It is NOT a permanent state and could be turned on anytime later.
+        * Thus no need to call turn_on when resunming.
+        */
        mutex_lock(&ucr->dev_mutex);
        rtsx_usb_turn_off_led(ucr);
        mutex_unlock(&ucr->dev_mutex);
+
        return 0;
 }
 
index 1cf27521fff4f2fe4a2892d651b5d47e4721286e..09fd256abcf604d5367fdff248279ef42b6c0520 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/irq.h>
-#include <linux/mfd/samsung/rtc.h>
 #include <linux/mfd/samsung/s2mpa01.h>
 #include <linux/mfd/samsung/s2mps11.h>
 #include <linux/mfd/samsung/s2mps14.h>
@@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = {
        .cache_type = REGCACHE_FLAT,
 };
 
-static const struct regmap_config s5m_rtc_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-
-       .max_register = SEC_RTC_REG_MAX,
-};
-
-static const struct regmap_config s2mps14_rtc_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-
-       .max_register = S2MPS_RTC_REG_MAX,
-};
-
 #ifdef CONFIG_OF
 /*
  * Only the common platform data elements for s5m8767 are parsed here from the
@@ -264,8 +249,9 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
-       const struct regmap_config *regmap, *regmap_rtc;
+       const struct regmap_config *regmap;
        struct sec_pmic_dev *sec_pmic;
+       unsigned long device_type;
        int ret;
 
        sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
@@ -277,7 +263,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        sec_pmic->dev = &i2c->dev;
        sec_pmic->i2c = i2c;
        sec_pmic->irq = i2c->irq;
-       sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
+       device_type = sec_i2c_get_driver_data(i2c, id);
 
        if (sec_pmic->dev->of_node) {
                pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
@@ -285,7 +271,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                        ret = PTR_ERR(pdata);
                        return ret;
                }
-               pdata->device_type = sec_pmic->type;
+               pdata->device_type = device_type;
        }
        if (pdata) {
                sec_pmic->device_type = pdata->device_type;
@@ -298,39 +284,21 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        switch (sec_pmic->device_type) {
        case S2MPA01:
                regmap = &s2mpa01_regmap_config;
-               /*
-                * The rtc-s5m driver does not support S2MPA01 and there
-                * is no mfd_cell for S2MPA01 RTC device.
-                * However we must pass something to devm_regmap_init_i2c()
-                * so use S5M-like regmap config even though it wouldn't work.
-                */
-               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        case S2MPS11X:
                regmap = &s2mps11_regmap_config;
-               /*
-                * The rtc-s5m driver does not support S2MPS11 and there
-                * is no mfd_cell for S2MPS11 RTC device.
-                * However we must pass something to devm_regmap_init_i2c()
-                * so use S5M-like regmap config even though it wouldn't work.
-                */
-               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        case S2MPS14X:
                regmap = &s2mps14_regmap_config;
-               regmap_rtc = &s2mps14_rtc_regmap_config;
                break;
        case S5M8763X:
                regmap = &s5m8763_regmap_config;
-               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        case S5M8767X:
                regmap = &s5m8767_regmap_config;
-               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        default:
                regmap = &sec_regmap_config;
-               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        }
 
@@ -342,21 +310,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
-       if (!sec_pmic->rtc) {
-               dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
-               return -ENODEV;
-       }
-       i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
-
-       sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
-       if (IS_ERR(sec_pmic->regmap_rtc)) {
-               ret = PTR_ERR(sec_pmic->regmap_rtc);
-               dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
-                       ret);
-               goto err_regmap_rtc;
-       }
-
        if (pdata && pdata->cfg_pmic_irq)
                pdata->cfg_pmic_irq();
 
@@ -403,8 +356,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
 
 err_mfd:
        sec_irq_exit(sec_pmic);
-err_regmap_rtc:
-       i2c_unregister_device(sec_pmic->rtc);
        return ret;
 }
 
@@ -414,7 +365,6 @@ static int sec_pmic_remove(struct i2c_client *i2c)
 
        mfd_remove_devices(sec_pmic->dev);
        sec_irq_exit(sec_pmic);
-       i2c_unregister_device(sec_pmic->rtc);
        return 0;
 }
 
index 64e7913aadc6cf3fbe68389edd8ba986e7a1ec8c..654e2c1dbf7a61cc9884ed78f3006d2bf332f1be 100644 (file)
@@ -385,7 +385,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
                                  &sec_pmic->irq_data);
                break;
        default:
-               dev_err(sec_pmic->dev, "Unknown device type %d\n",
+               dev_err(sec_pmic->dev, "Unknown device type %lu\n",
                        sec_pmic->device_type);
                return -EINVAL;
        }
index ba1a25d758c12ed61d82aaea82501272fc34081a..1c3e6e2efe410812d7fd0a58b9b940be47a5ecbc 100644 (file)
 #define NUM_INT_REG 2
 #define TOTAL_NUM_REG 0x18
 
-/* interrupt status registers */
-#define TPS65090_INT_STS       0x0
-#define TPS65090_INT_STS2      0x1
-
-/* interrupt mask registers */
-#define TPS65090_INT_MSK       0x2
-#define TPS65090_INT_MSK2      0x3
-
 #define TPS65090_INT1_MASK_VAC_STATUS_CHANGE           1
 #define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE          2
 #define TPS65090_INT1_MASK_BAT_STATUS_CHANGE           3
@@ -64,11 +56,16 @@ static struct resource charger_resources[] = {
        }
 };
 
-static const struct mfd_cell tps65090s[] = {
-       {
+enum tps65090_cells {
+       PMIC = 0,
+       CHARGER = 1,
+};
+
+static struct mfd_cell tps65090s[] = {
+       [PMIC] = {
                .name = "tps65090-pmic",
        },
-       {
+       [CHARGER] = {
                .name = "tps65090-charger",
                .num_resources = ARRAY_SIZE(charger_resources),
                .resources = &charger_resources[0],
@@ -139,17 +136,26 @@ static struct regmap_irq_chip tps65090_irq_chip = {
        .irqs = tps65090_irqs,
        .num_irqs = ARRAY_SIZE(tps65090_irqs),
        .num_regs = NUM_INT_REG,
-       .status_base = TPS65090_INT_STS,
-       .mask_base = TPS65090_INT_MSK,
+       .status_base = TPS65090_REG_INTR_STS,
+       .mask_base = TPS65090_REG_INTR_MASK,
        .mask_invert = true,
 };
 
 static bool is_volatile_reg(struct device *dev, unsigned int reg)
 {
-       if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2))
-               return true;
-       else
+       /* Nearly all registers have status bits mixed in, except a few */
+       switch (reg) {
+       case TPS65090_REG_INTR_MASK:
+       case TPS65090_REG_INTR_MASK2:
+       case TPS65090_REG_CG_CTRL0:
+       case TPS65090_REG_CG_CTRL1:
+       case TPS65090_REG_CG_CTRL2:
+       case TPS65090_REG_CG_CTRL3:
+       case TPS65090_REG_CG_CTRL4:
+       case TPS65090_REG_CG_CTRL5:
                return false;
+       }
+       return true;
 }
 
 static const struct regmap_config tps65090_regmap_config = {
@@ -211,6 +217,9 @@ static int tps65090_i2c_probe(struct i2c_client *client,
                                        "IRQ init failed with err: %d\n", ret);
                        return ret;
                }
+       } else {
+               /* Don't tell children they have an IRQ that'll never fire */
+               tps65090s[CHARGER].num_resources = 0;
        }
 
        ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
index e87140bef667212af51bb6e02fd0ee06744190dc..db11b4f406116124ca86d82b1cec6d2e358c99c2 100644 (file)
 #define TWL4030_BASEADD_BACKUP         0x0014
 #define TWL4030_BASEADD_INT            0x002E
 #define TWL4030_BASEADD_PM_MASTER      0x0036
+
 #define TWL4030_BASEADD_PM_RECEIVER    0x005B
+#define TWL4030_DCDC_GLOBAL_CFG                0x06
+#define SMARTREFLEX_ENABLE             BIT(3)
+
 #define TWL4030_BASEADD_RTC            0x001C
 #define TWL4030_BASEADD_SECURED_REG    0x0000
 
@@ -1204,6 +1208,11 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
         * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
         * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
         * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
+        *
+        * Also, always enable SmartReflex bit as that's needed for omaps to
+        * to do anything over I2C4 for voltage scaling even if SmartReflex
+        * is disabled. Without the SmartReflex bit omap sys_clkreq idle
+        * signal will never trigger for retention idle.
         */
        if (twl_class_is_4030()) {
                u8 temp;
@@ -1212,6 +1221,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
                        I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
+
+               twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
+                               TWL4030_DCDC_GLOBAL_CFG);
+               temp |= SMARTREFLEX_ENABLE;
+               twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
+                                TWL4030_DCDC_GLOBAL_CFG);
        }
 
        if (node) {
index 1942b6f231dae3f193e41f618c6ec626ffc28694..58bc2be6e6a55472bc1b050fe04668cef2d4c1b4 100644 (file)
@@ -549,6 +549,7 @@ static const struct reg_default wm5110_reg_default[] = {
        { 0x000002A8, 0x1422 },    /* R680   - Mic Detect Level 3 */
        { 0x000002A9, 0x300A },    /* R681   - Mic Detect Level 4 */
        { 0x000002C3, 0x0000 },    /* R707   - Mic noise mix control 1 */
+       { 0x000002CB, 0x0000 },    /* R715   - Isolation control */
        { 0x000002D3, 0x0000 },    /* R723   - Jack detect analogue */
        { 0x00000300, 0x0000 },    /* R768   - Input Enables */
        { 0x00000308, 0x0000 },    /* R776   - Input Rate */
@@ -1580,6 +1581,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_MIC_DETECT_LEVEL_3:
        case ARIZONA_MIC_DETECT_LEVEL_4:
        case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
+       case ARIZONA_ISOLATION_CONTROL:
        case ARIZONA_JACK_DETECT_ANALOGUE:
        case ARIZONA_INPUT_ENABLES:
        case ARIZONA_INPUT_ENABLES_STATUS:
index d049d271699cac36fd1333e4b0de0c9d02f4827c..c00adfaa627940df3f1c791b0e2c8f69f370bee6 100644 (file)
@@ -718,7 +718,7 @@ int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count)
        int rc;
        struct pci_dev *pci_dev = cd->pci_dev;
 
-       rc = pci_enable_msi_block(pci_dev, count);
+       rc = pci_enable_msi_exact(pci_dev, count);
        if (rc == 0)
                cd->flags |= GENWQE_FLAG_MSI_ENABLED;
        return rc;
index acbc3f2aaaf9e3adff743de7081e1e6508b6b03c..79ba3a5bbf17cf8a6e79f03aa930a71ca8bffe8f 100644 (file)
@@ -800,6 +800,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
                        data->timeout_ns = limit_us * 1000;
                        data->timeout_clks = 0;
                }
+
+               /* assign limit value if invalid */
+               if (timeout_us == 0)
+                       data->timeout_ns = limit_us * 1000;
        }
 
        /*
@@ -2403,6 +2407,11 @@ void mmc_rescan(struct work_struct *work)
                container_of(work, struct mmc_host, detect.work);
        int i;
 
+       if (host->trigger_card_event && host->ops->card_event) {
+               host->ops->card_event(host);
+               host->trigger_card_event = false;
+       }
+
        if (host->rescan_disable)
                return;
 
index 54829c0ed0002fcc08f193b6af6112eabd00699d..509229b48b55c3584e18d9838f67cb8b5d944ff6 100644 (file)
@@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
        case MMC_TIMING_UHS_DDR50:
                str = "sd uhs DDR50";
                break;
+       case MMC_TIMING_MMC_DDR52:
+               str = "mmc DDR52";
+               break;
        case MMC_TIMING_MMC_HS200:
                str = "mmc high-speed SDR200";
                break;
index 1ab5f3a0af5b734a1829e732fe91b5bef8f24d2b..fbcf93d818585761bc68507b68297a7d2095ca9f 100644 (file)
@@ -694,18 +694,10 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_rel_sectors.attr,
        NULL,
 };
-
-static struct attribute_group mmc_std_attr_group = {
-       .attrs = mmc_std_attrs,
-};
-
-static const struct attribute_group *mmc_attr_groups[] = {
-       &mmc_std_attr_group,
-       NULL,
-};
+ATTRIBUTE_GROUPS(mmc_std);
 
 static struct device_type mmc_type = {
-       .groups = mmc_attr_groups,
+       .groups = mmc_std_groups,
 };
 
 /*
@@ -1264,7 +1256,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                        goto err;
                        }
                        mmc_card_set_ddr_mode(card);
-                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+                       mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
                        mmc_set_bus_width(card->host, bus_width);
                }
        }
index 2dd359d2242fa811efae1a03d02ca9d9dfba77ca..aef515755e5bf94c2da03bab5b3f28cb3f38d0f9 100644 (file)
@@ -707,18 +707,10 @@ static struct attribute *sd_std_attrs[] = {
        &dev_attr_serial.attr,
        NULL,
 };
-
-static struct attribute_group sd_std_attr_group = {
-       .attrs = sd_std_attrs,
-};
-
-static const struct attribute_group *sd_attr_groups[] = {
-       &sd_std_attr_group,
-       NULL,
-};
+ATTRIBUTE_GROUPS(sd_std);
 
 struct device_type sd_type = {
-       .groups = sd_attr_groups,
+       .groups = sd_std_groups,
 };
 
 /*
index 4d721c6e2af01026ea967dbd54bdaf17c8648aee..9933e426bc3696d9656b11ab407e23990e1f9500 100644 (file)
@@ -943,40 +943,21 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
  */
 static int mmc_sdio_suspend(struct mmc_host *host)
 {
-       int i, err = 0;
-
-       for (i = 0; i < host->card->sdio_funcs; i++) {
-               struct sdio_func *func = host->card->sdio_func[i];
-               if (func && sdio_func_present(func) && func->dev.driver) {
-                       const struct dev_pm_ops *pmops = func->dev.driver->pm;
-                       err = pmops->suspend(&func->dev);
-                       if (err)
-                               break;
-               }
-       }
-       while (err && --i >= 0) {
-               struct sdio_func *func = host->card->sdio_func[i];
-               if (func && sdio_func_present(func) && func->dev.driver) {
-                       const struct dev_pm_ops *pmops = func->dev.driver->pm;
-                       pmops->resume(&func->dev);
-               }
-       }
-
-       if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+       if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                mmc_claim_host(host);
                sdio_disable_wide(host->card);
                mmc_release_host(host);
        }
 
-       if (!err && !mmc_card_keep_power(host))
+       if (!mmc_card_keep_power(host))
                mmc_power_off(host);
 
-       return err;
+       return 0;
 }
 
 static int mmc_sdio_resume(struct mmc_host *host)
 {
-       int i, err = 0;
+       int err = 0;
 
        BUG_ON(!host);
        BUG_ON(!host->card);
@@ -1019,24 +1000,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
                wake_up_process(host->sdio_irq_thread);
        mmc_release_host(host);
 
-       /*
-        * If the card looked to be the same as before suspending, then
-        * we proceed to resume all card functions.  If one of them returns
-        * an error then we simply return that error to the core and the
-        * card will be redetected as new.  It is the responsibility of
-        * the function driver to perform further tests with the extra
-        * knowledge it has of the card to confirm the card is indeed the
-        * same as before suspending (same MAC address for network cards,
-        * etc.) and return an error otherwise.
-        */
-       for (i = 0; !err && i < host->card->sdio_funcs; i++) {
-               struct sdio_func *func = host->card->sdio_func[i];
-               if (func && sdio_func_present(func) && func->dev.driver) {
-                       const struct dev_pm_ops *pmops = func->dev.driver->pm;
-                       err = pmops->resume(&func->dev);
-               }
-       }
-
        host->pm_flags &= ~MMC_PM_KEEP_POWER;
        return err;
 }
index 92d1ba8e8153ab9849ab51037804747cd37df7f1..4fa8fef9147f75ec4e9ff974957093bb28f0ec6a 100644 (file)
@@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev)
 
 #ifdef CONFIG_PM
 
-#ifdef CONFIG_PM_SLEEP
-static int pm_no_operation(struct device *dev)
-{
-       /*
-        * Prevent the PM core from calling SDIO device drivers' suspend
-        * callback routines, which it is not supposed to do, by using this
-        * empty function as the bus type suspend callaback for SDIO.
-        */
-       return 0;
-}
-#endif
-
 static const struct dev_pm_ops sdio_bus_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
index f7650b899e3d426fbce08e8b636784adf0d0cdf0..5f89cb83d5f00008aa3c98f550f9ff962c0306c0 100644 (file)
@@ -32,9 +32,7 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
        /* Schedule a card detection after a debounce timeout */
        struct mmc_host *host = dev_id;
 
-       if (host->ops->card_event)
-               host->ops->card_event(host);
-
+       host->trigger_card_event = true;
        mmc_detect_change(host, msecs_to_jiffies(200));
 
        return IRQ_HANDLED;
index 8aaf8c1f3f63a398003237828eef9bef8b753e81..b675882307e4f85e5fb8ebcfde84bf21c0363be2 100644 (file)
@@ -694,3 +694,10 @@ config MMC_REALTEK_PCI
        help
          Say Y here to include driver code to support SD/MMC card interface
          of Realtek PCI-E card reader
+
+config MMC_REALTEK_USB
+       tristate "Realtek USB SD/MMC Card Interface Driver"
+       depends on MFD_RTSX_USB
+       help
+         Say Y here to include driver code to support SD/MMC card interface
+         of Realtek RTS5129/39 series card reader
index 0c8aa5e1e304b55270613d2cb288448502467ff2..3eb48b656f2514541f25ae5dc8aa7de759988319 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_MMC_USHC)                += ushc.o
 obj-$(CONFIG_MMC_WMT)          += wmt-sdmmc.o
 
 obj-$(CONFIG_MMC_REALTEK_PCI)  += rtsx_pci_sdmmc.o
+obj-$(CONFIG_MMC_REALTEK_USB)  += rtsx_usb_sdmmc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)          += sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)                += sdhci-cns3xxx.o
index 3423c5ed50c7a0ec918af7c7adcba7b2e5d2baed..0fbc53ac7eae8fb27f60b12575be4cabbe759c15 100644 (file)
@@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
        unsigned long actual;
        u8 div = priv->ciu_div + 1;
 
-       if (ios->timing == MMC_TIMING_UHS_DDR50) {
+       if (ios->timing == MMC_TIMING_MMC_DDR52) {
                mci_writel(host, CLKSEL, priv->ddr_timing);
                /* Should be double rate for DDR mode */
                if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
 
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
-       MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
-               MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+       MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
        MMC_CAP_CMD23,
        MMC_CAP_CMD23,
        MMC_CAP_CMD23,
@@ -426,7 +425,7 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
        return dw_mci_pltfm_register(pdev, drv_data);
 }
 
-const struct dev_pm_ops dw_mci_exynos_pmops = {
+static const struct dev_pm_ops dw_mci_exynos_pmops = {
        SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume)
        .resume_noirq = dw_mci_exynos_resume_noirq,
        .thaw_noirq = dw_mci_exynos_resume_noirq,
index cced599d5aebe22aef357fd427a6aa03d7edaa79..d40991299218ba22ae749d8e557a1c168cdb3334 100644 (file)
@@ -235,12 +235,6 @@ err:
 }
 #endif /* defined(CONFIG_DEBUG_FS) */
 
-static void dw_mci_set_timeout(struct dw_mci *host)
-{
-       /* timeout (maximum) */
-       mci_writel(host, TMOUT, 0xffffffff);
-}
-
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
@@ -257,9 +251,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
            (cmd->opcode == SD_IO_RW_DIRECT &&
             ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
                cmdr |= SDMMC_CMD_STOP;
-       else
-               if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
-                       cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
+       else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
+               cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
 
        if (cmd->flags & MMC_RSP_PRESENT) {
                /* We expect a response, so set this bit */
@@ -850,8 +843,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
        u32 cmdflags;
 
        mrq = slot->mrq;
-       if (host->pdata->select_slot)
-               host->pdata->select_slot(slot->id);
 
        host->cur_slot = slot;
        host->mrq = mrq;
@@ -864,7 +855,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
 
        data = cmd->data;
        if (data) {
-               dw_mci_set_timeout(host);
+               mci_writel(host, TMOUT, 0xFFFFFFFF);
                mci_writel(host, BYTCNT, data->blksz*data->blocks);
                mci_writel(host, BLKSIZ, data->blksz);
        }
@@ -962,7 +953,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        regs = mci_readl(slot->host, UHS_REG);
 
        /* DDR mode set */
-       if (ios->timing == MMC_TIMING_UHS_DDR50)
+       if (ios->timing == MMC_TIMING_MMC_DDR52)
                regs |= ((0x1 << slot->id) << 16);
        else
                regs &= ~((0x1 << slot->id) << 16);
@@ -985,17 +976,11 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
-               /* Power up slot */
-               if (slot->host->pdata->setpower)
-                       slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
                regs = mci_readl(slot->host, PWREN);
                regs |= (1 << slot->id);
                mci_writel(slot->host, PWREN, regs);
                break;
        case MMC_POWER_OFF:
-               /* Power down slot */
-               if (slot->host->pdata->setpower)
-                       slot->host->pdata->setpower(slot->id, 0);
                regs = mci_readl(slot->host, PWREN);
                regs &= ~(1 << slot->id);
                mci_writel(slot->host, PWREN, regs);
@@ -1009,15 +994,13 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
 {
        int read_only;
        struct dw_mci_slot *slot = mmc_priv(mmc);
-       struct dw_mci_board *brd = slot->host->pdata;
+       int gpio_ro = mmc_gpio_get_ro(mmc);
 
        /* Use platform get_ro function, else try on board write protect */
        if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
                read_only = 0;
-       else if (brd->get_ro)
-               read_only = brd->get_ro(slot->id);
-       else if (gpio_is_valid(slot->wp_gpio))
-               read_only = gpio_get_value(slot->wp_gpio);
+       else if (!IS_ERR_VALUE(gpio_ro))
+               read_only = gpio_ro;
        else
                read_only =
                        mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
@@ -1039,8 +1022,6 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
        /* Use platform get_cd function, else try onboard card detect */
        if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
                present = 1;
-       else if (brd->get_cd)
-               present = !brd->get_cd(slot->id);
        else if (!IS_ERR_VALUE(gpio_cd))
                present = gpio_cd;
        else
@@ -2045,86 +2026,15 @@ static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
 
        return quirks;
 }
-
-/* find out bus-width for a given slot */
-static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
-{
-       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
-       u32 bus_wd = 1;
-
-       if (!np)
-               return 1;
-
-       if (of_property_read_u32(np, "bus-width", &bus_wd))
-               dev_err(dev, "bus-width property not found, assuming width"
-                              " as 1\n");
-       return bus_wd;
-}
-
-/* find the write protect gpio for a given slot; or -1 if none specified */
-static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
-{
-       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
-       int gpio;
-
-       if (!np)
-               return -EINVAL;
-
-       gpio = of_get_named_gpio(np, "wp-gpios", 0);
-
-       /* Having a missing entry is valid; return silently */
-       if (!gpio_is_valid(gpio))
-               return -EINVAL;
-
-       if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
-               dev_warn(dev, "gpio [%d] request failed\n", gpio);
-               return -EINVAL;
-       }
-
-       return gpio;
-}
-
-/* find the cd gpio for a given slot */
-static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
-                                       struct mmc_host *mmc)
-{
-       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
-       int gpio;
-
-       if (!np)
-               return;
-
-       gpio = of_get_named_gpio(np, "cd-gpios", 0);
-
-       /* Having a missing entry is valid; return silently */
-       if (!gpio_is_valid(gpio))
-               return;
-
-       if (mmc_gpio_request_cd(mmc, gpio, 0))
-               dev_warn(dev, "gpio [%d] request failed\n", gpio);
-}
 #else /* CONFIG_OF */
 static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
 {
        return 0;
 }
-static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
-{
-       return 1;
-}
 static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
 {
        return NULL;
 }
-static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
-{
-       return -EINVAL;
-}
-static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
-                                       struct mmc_host *mmc)
-{
-       return;
-}
 #endif /* CONFIG_OF */
 
 static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@@ -2134,7 +2044,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        const struct dw_mci_drv_data *drv_data = host->drv_data;
        int ctrl_id, ret;
        u32 freq[2];
-       u8 bus_width;
 
        mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
        if (!mmc)
@@ -2158,17 +2067,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                mmc->f_max = freq[1];
        }
 
-       if (host->pdata->get_ocr)
-               mmc->ocr_avail = host->pdata->get_ocr(id);
-       else
-               mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-
-       /*
-        * Start with slot power disabled, it will be enabled when a card
-        * is detected.
-        */
-       if (host->pdata->setpower)
-               host->pdata->setpower(id, 0);
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
@@ -2189,19 +2088,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->caps2)
                mmc->caps2 = host->pdata->caps2;
 
-       if (host->pdata->get_bus_wd)
-               bus_width = host->pdata->get_bus_wd(slot->id);
-       else if (host->dev->of_node)
-               bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
-       else
-               bus_width = 1;
-
-       switch (bus_width) {
-       case 8:
-               mmc->caps |= MMC_CAP_8_BIT_DATA;
-       case 4:
-               mmc->caps |= MMC_CAP_4_BIT_DATA;
-       }
+       mmc_of_parse(mmc);
 
        if (host->pdata->blk_settings) {
                mmc->max_segs = host->pdata->blk_settings->max_segs;
@@ -2226,8 +2113,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 #endif /* CONFIG_MMC_DW_IDMAC */
        }
 
-       slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
-       dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
+       if (dw_mci_get_cd(mmc))
+               set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+       else
+               clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
        ret = mmc_add_host(mmc);
        if (ret)
@@ -2249,10 +2138,6 @@ err_setup_bus:
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 {
-       /* Shutdown detect IRQ */
-       if (slot->host->pdata->exit)
-               slot->host->pdata->exit(id);
-
        /* Debugfs stuff is cleaned up by mmc core */
        mmc_remove_host(slot->mmc);
        slot->host->slot[id] = NULL;
@@ -2399,24 +2284,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
                        return ERR_PTR(ret);
        }
 
-       if (of_find_property(np, "keep-power-in-suspend", NULL))
-               pdata->pm_caps |= MMC_PM_KEEP_POWER;
-
-       if (of_find_property(np, "enable-sdio-wakeup", NULL))
-               pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
-
        if (of_find_property(np, "supports-highspeed", NULL))
                pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
-       if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL))
-               pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
-
-       if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL))
-               pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
-
-       if (of_get_property(np, "cd-inverted", NULL))
-               pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
-
        return pdata;
 }
 
@@ -2442,9 +2312,9 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
-       if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
+       if (host->pdata->num_slots > 1) {
                dev_err(host->dev,
-                       "Platform data must supply select_slot function\n");
+                       "Platform data must supply num_slots.\n");
                return -ENODEV;
        }
 
@@ -2474,12 +2344,19 @@ int dw_mci_probe(struct dw_mci *host)
                        ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
                        if (ret)
                                dev_warn(host->dev,
-                                        "Unable to set bus rate to %ul\n",
+                                        "Unable to set bus rate to %uHz\n",
                                         host->pdata->bus_hz);
                }
                host->bus_hz = clk_get_rate(host->ciu_clk);
        }
 
+       if (!host->bus_hz) {
+               dev_err(host->dev,
+                       "Platform data must supply bus speed\n");
+               ret = -ENODEV;
+               goto err_clk_ciu;
+       }
+
        if (drv_data && drv_data->init) {
                ret = drv_data->init(host);
                if (ret) {
@@ -2516,13 +2393,6 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
-       if (!host->bus_hz) {
-               dev_err(host->dev,
-                       "Platform data must supply bus speed\n");
-               ret = -ENODEV;
-               goto err_regulator;
-       }
-
        host->quirks = host->pdata->quirks;
 
        spin_lock_init(&host->lock);
@@ -2666,8 +2536,6 @@ err_workqueue:
 err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
-
-err_regulator:
        if (host->vmmc)
                regulator_disable(host->vmmc);
 
index 68349779c39614cd397723c86f810651b8e93754..738fa241d05882258958107348a75b511c76fc08 100644 (file)
@@ -195,7 +195,6 @@ extern int dw_mci_resume(struct dw_mci *host);
  * @mmc: The mmc_host representing this slot.
  * @host: The MMC controller this slot is using.
  * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
- * @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
  * @ctype: Card type for this slot.
  * @mrq: mmc_request currently being processed or waiting to be
  *     processed, or NULL when the slot is idle.
@@ -214,7 +213,6 @@ struct dw_mci_slot {
        struct dw_mci           *host;
 
        int                     quirks;
-       int                     wp_gpio;
 
        u32                     ctype;
 
index 771c60ab4a320a3edc222b108c49d14a8e0076b1..7e853932393bf00a0131d1a93206fc0c57ea5daa 100644 (file)
@@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
        if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
                clk |= MCI_ST_8BIT_BUS;
 
-       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+           host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
                clk |= MCI_ST_UX500_NEG_EDGE;
 
        mmci_write_clkreg(host, clk);
@@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                        mmci_write_clkreg(host, clk);
                }
 
-       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+           host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
                datactrl |= MCI_ST_DPSM_DDRMODE;
 
        /*
index f7199c83f5cf8e85c49ed54b575502d0187fc8c3..86401c09e35723fb8d8ba830bfc60d8808ca4bd8 100644 (file)
@@ -124,9 +124,8 @@ enum mxcmci_type {
 
 struct mxcmci_host {
        struct mmc_host         *mmc;
-       struct resource         *res;
        void __iomem            *base;
-       int                     irq;
+       dma_addr_t              phys_base;
        int                     detect_irq;
        struct dma_chan         *dma;
        struct dma_async_tx_descriptor *desc;
@@ -241,33 +240,26 @@ static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg)
 
 static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
 
-static inline void mxcmci_init_ocr(struct mxcmci_host *host)
+static void mxcmci_init_ocr(struct mxcmci_host *host)
 {
-       host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
-
+       host->vcc = devm_regulator_get(mmc_dev(host->mmc), "vmmc");
        if (IS_ERR(host->vcc)) {
-               host->vcc = NULL;
+               if (host->pdata && host->pdata->ocr_avail)
+                       host->mmc->ocr_avail = host->pdata->ocr_avail;
+               else
+                       host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
        } else {
                host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
                if (host->pdata && host->pdata->ocr_avail)
                        dev_warn(mmc_dev(host->mmc),
                                "pdata->ocr_avail will not be used\n");
        }
-
-       if (host->vcc == NULL) {
-               /* fall-back to platform data */
-               if (host->pdata && host->pdata->ocr_avail)
-                       host->mmc->ocr_avail = host->pdata->ocr_avail;
-               else
-                       host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       }
 }
 
-static inline void mxcmci_set_power(struct mxcmci_host *host,
-                                   unsigned char power_mode,
-                                   unsigned int vdd)
+static void mxcmci_set_power(struct mxcmci_host *host, unsigned char power_mode,
+                            unsigned int vdd)
 {
-       if (host->vcc) {
+       if (!IS_ERR(host->vcc)) {
                if (power_mode == MMC_POWER_UP)
                        mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
                else if (power_mode == MMC_POWER_OFF)
@@ -299,7 +291,6 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 
        mxcmci_writew(host, 0xff, MMC_REG_RES_TO);
 }
-static int mxcmci_setup_dma(struct mmc_host *mmc);
 
 #if IS_ENABLED(CONFIG_PPC_MPC512x)
 static inline void buffer_swap32(u32 *buf, int len)
@@ -868,8 +859,8 @@ static int mxcmci_setup_dma(struct mmc_host *mmc)
        struct mxcmci_host *host = mmc_priv(mmc);
        struct dma_slave_config *config = &host->dma_slave_config;
 
-       config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
-       config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
+       config->dst_addr = host->phys_base + MMC_REG_BUFFER_ACCESS;
+       config->src_addr = host->phys_base + MMC_REG_BUFFER_ACCESS;
        config->dst_addr_width = 4;
        config->src_addr_width = 4;
        config->dst_maxburst = host->burstlen;
@@ -1040,8 +1031,8 @@ static const struct mmc_host_ops mxcmci_ops = {
 static int mxcmci_probe(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
-       struct mxcmci_host *host = NULL;
-       struct resource *iores, *r;
+       struct mxcmci_host *host;
+       struct resource *res;
        int ret = 0, irq;
        bool dat3_card_detect = false;
        dma_cap_mask_t mask;
@@ -1052,21 +1043,25 @@ static int mxcmci_probe(struct platform_device *pdev)
 
        of_id = of_match_device(mxcmci_of_match, &pdev->dev);
 
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!iores || irq < 0)
+       if (irq < 0)
                return -EINVAL;
 
-       r = request_mem_region(iores->start, resource_size(iores), pdev->name);
-       if (!r)
-               return -EBUSY;
+       mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       host = mmc_priv(mmc);
 
-       mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               goto out_release_mem;
+       host->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(host->base)) {
+               ret = PTR_ERR(host->base);
+               goto out_free;
        }
 
+       host->phys_base = res->start;
+
        ret = mmc_of_parse(mmc);
        if (ret)
                goto out_free;
@@ -1084,13 +1079,6 @@ static int mxcmci_probe(struct platform_device *pdev)
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
 
-       host = mmc_priv(mmc);
-       host->base = ioremap(r->start, resource_size(r));
-       if (!host->base) {
-               ret = -ENOMEM;
-               goto out_free;
-       }
-
        if (of_id) {
                const struct platform_device_id *id_entry = of_id->data;
                host->devtype = id_entry->driver_data;
@@ -1120,19 +1108,16 @@ static int mxcmci_probe(struct platform_device *pdev)
        else
                host->default_irq_mask = 0;
 
-       host->res = r;
-       host->irq = irq;
-
        host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(host->clk_ipg)) {
                ret = PTR_ERR(host->clk_ipg);
-               goto out_iounmap;
+               goto out_free;
        }
 
        host->clk_per = devm_clk_get(&pdev->dev, "per");
        if (IS_ERR(host->clk_per)) {
                ret = PTR_ERR(host->clk_per);
-               goto out_iounmap;
+               goto out_free;
        }
 
        clk_prepare_enable(host->clk_per);
@@ -1159,9 +1144,9 @@ static int mxcmci_probe(struct platform_device *pdev)
        if (!host->pdata) {
                host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx");
        } else {
-               r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (r) {
-                       host->dmareq = r->start;
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (res) {
+                       host->dmareq = res->start;
                        host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
                        host->dma_data.priority = DMA_PRIO_LOW;
                        host->dma_data.dma_request = host->dmareq;
@@ -1178,7 +1163,8 @@ static int mxcmci_probe(struct platform_device *pdev)
 
        INIT_WORK(&host->datawork, mxcmci_datawork);
 
-       ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host);
+       ret = devm_request_irq(&pdev->dev, irq, mxcmci_irq, 0,
+                              dev_name(&pdev->dev), host);
        if (ret)
                goto out_free_dma;
 
@@ -1188,7 +1174,7 @@ static int mxcmci_probe(struct platform_device *pdev)
                ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq,
                                host->mmc);
                if (ret)
-                       goto out_free_irq;
+                       goto out_free_dma;
        }
 
        init_timer(&host->watchdog);
@@ -1199,20 +1185,17 @@ static int mxcmci_probe(struct platform_device *pdev)
 
        return 0;
 
-out_free_irq:
-       free_irq(host->irq, host);
 out_free_dma:
        if (host->dma)
                dma_release_channel(host->dma);
+
 out_clk_put:
        clk_disable_unprepare(host->clk_per);
        clk_disable_unprepare(host->clk_ipg);
-out_iounmap:
-       iounmap(host->base);
+
 out_free:
        mmc_free_host(mmc);
-out_release_mem:
-       release_mem_region(iores->start, resource_size(iores));
+
        return ret;
 }
 
@@ -1223,30 +1206,21 @@ static int mxcmci_remove(struct platform_device *pdev)
 
        mmc_remove_host(mmc);
 
-       if (host->vcc)
-               regulator_put(host->vcc);
-
        if (host->pdata && host->pdata->exit)
                host->pdata->exit(&pdev->dev, mmc);
 
-       free_irq(host->irq, host);
-       iounmap(host->base);
-
        if (host->dma)
                dma_release_channel(host->dma);
 
        clk_disable_unprepare(host->clk_per);
        clk_disable_unprepare(host->clk_ipg);
 
-       release_mem_region(host->res->start, resource_size(host->res));
-
        mmc_free_host(mmc);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int mxcmci_suspend(struct device *dev)
+static int __maybe_unused mxcmci_suspend(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct mxcmci_host *host = mmc_priv(mmc);
@@ -1256,7 +1230,7 @@ static int mxcmci_suspend(struct device *dev)
        return 0;
 }
 
-static int mxcmci_resume(struct device *dev)
+static int __maybe_unused mxcmci_resume(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct mxcmci_host *host = mmc_priv(mmc);
@@ -1266,11 +1240,7 @@ static int mxcmci_resume(struct device *dev)
        return 0;
 }
 
-static const struct dev_pm_ops mxcmci_pm_ops = {
-       .suspend        = mxcmci_suspend,
-       .resume         = mxcmci_resume,
-};
-#endif
+static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
 
 static struct platform_driver mxcmci_driver = {
        .probe          = mxcmci_probe,
@@ -1279,9 +1249,7 @@ static struct platform_driver mxcmci_driver = {
        .driver         = {
                .name           = DRIVER_NAME,
                .owner          = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm     = &mxcmci_pm_ops,
-#endif
                .of_match_table = mxcmci_of_match,
        }
 };
index e91ee21549d03ad22c2bcf2287f61074cc3d889b..b4de63bf10fdfde09e374f90e06923616352e0c2 100644 (file)
@@ -582,7 +582,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
         *      - MMC/SD clock coming out of controller > 25MHz
         */
        if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
-           (ios->timing != MMC_TIMING_UHS_DDR50) &&
+           (ios->timing != MMC_TIMING_MMC_DDR52) &&
            ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
                regval = OMAP_HSMMC_READ(host->base, HCTL);
                if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@@ -602,7 +602,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
        u32 con;
 
        con = OMAP_HSMMC_READ(host->base, CON);
-       if (ios->timing == MMC_TIMING_UHS_DDR50)
+       if (ios->timing == MMC_TIMING_MMC_DDR52)
                con |= DDR;     /* configure in DDR mode */
        else
                con &= ~DDR;
index 5fb994f9a653570d75f2b3deb6aab32129d17503..09340b9429ec97c28d5bf8d0cbda35c1964ec149 100644 (file)
@@ -81,25 +81,24 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host)
 }
 
 #ifdef DEBUG
+static inline void sd_print_reg(struct realtek_pci_sdmmc *host, u16 reg)
+{
+       u8 val = 0;
+
+       if (rtsx_pci_read_register(host->pcr, reg, &val) < 0)
+               dev_dbg(sdmmc_dev(host), "read 0x%04x failed\n", reg);
+       else
+               dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", reg, val);
+}
+
 static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
 {
-       struct rtsx_pcr *pcr = host->pcr;
        u16 i;
-       u8 *ptr;
-
-       /* Print SD host internal registers */
-       rtsx_pci_init_cmd(pcr);
-       for (i = 0xFDA0; i <= 0xFDAE; i++)
-               rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
-       for (i = 0xFD52; i <= 0xFD69; i++)
-               rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
-       rtsx_pci_send_cmd(pcr, 100);
 
-       ptr = rtsx_pci_get_cmd_data(pcr);
        for (i = 0xFDA0; i <= 0xFDAE; i++)
-               dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
+               sd_print_reg(host, i);
        for (i = 0xFD52; i <= 0xFD69; i++)
-               dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
+               sd_print_reg(host, i);
 }
 #else
 #define sd_print_debug_regs(host)
@@ -125,19 +124,27 @@ static void sd_request_timeout(unsigned long host_addr)
        spin_lock_irqsave(&host->lock, flags);
 
        if (!host->mrq) {
-               dev_err(sdmmc_dev(host), "error: no request exist\n");
-               goto out;
+               dev_err(sdmmc_dev(host), "error: request not exist\n");
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
        }
 
-       if (host->cmd)
+       if (host->cmd && host->data)
+               dev_err(sdmmc_dev(host), "error: cmd and data conflict\n");
+
+       if (host->cmd) {
                host->cmd->error = -ETIMEDOUT;
-       if (host->data)
-               host->data->error = -ETIMEDOUT;
+               dev_dbg(sdmmc_dev(host), "timeout for cmd %d\n",
+                       host->cmd->opcode);
+               tasklet_schedule(&host->cmd_tasklet);
+       }
 
-       dev_dbg(sdmmc_dev(host), "timeout for request\n");
+       if (host->data) {
+               host->data->error = -ETIMEDOUT;
+               dev_dbg(sdmmc_dev(host), "timeout for data transfer\n");
+               tasklet_schedule(&host->data_tasklet);
+       }
 
-out:
-       tasklet_schedule(&host->finish_tasklet);
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -157,7 +164,8 @@ static void sd_finish_request(unsigned long host_addr)
        mrq = host->mrq;
        if (!mrq) {
                dev_err(sdmmc_dev(host), "error: no request need finish\n");
-               goto out;
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
        }
 
        cmd = mrq->cmd;
@@ -167,11 +175,6 @@ static void sd_finish_request(unsigned long host_addr)
                (mrq->stop && mrq->stop->error) ||
                (cmd && cmd->error) || (data && data->error);
 
-       if (any_error) {
-               rtsx_pci_stop_cmd(pcr);
-               sd_clear_error(host);
-       }
-
        if (data) {
                if (any_error)
                        data->bytes_xfered = 0;
@@ -188,7 +191,6 @@ static void sd_finish_request(unsigned long host_addr)
        host->cmd = NULL;
        host->data = NULL;
 
-out:
        spin_unlock_irqrestore(&host->lock, flags);
        mutex_unlock(&pcr->pcr_mutex);
        mmc_request_done(host->mmc, mrq);
@@ -346,6 +348,9 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
        case MMC_RSP_R1:
                rsp_type = SD_RSP_TYPE_R1;
                break;
+       case MMC_RSP_R1 & ~MMC_RSP_CRC:
+               rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
+               break;
        case MMC_RSP_R1B:
                rsp_type = SD_RSP_TYPE_R1b;
                break;
@@ -370,8 +375,11 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
        if (cmd->opcode == SD_SWITCH_VOLTAGE) {
                err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
                                0xFF, SD_CLK_TOGGLE_EN);
-               if (err < 0)
+               if (err < 0) {
+                       rtsx_pci_write_register(pcr, SD_BUS_STAT,
+                               SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
                        goto out;
+               }
        }
 
        rtsx_pci_init_cmd(pcr);
@@ -433,7 +441,8 @@ static void sd_get_rsp(unsigned long host_addr)
 
        if (!cmd) {
                dev_err(sdmmc_dev(host), "error: cmd not exist\n");
-               goto out;
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
        }
 
        spin_lock(&pcr->lock);
@@ -443,16 +452,18 @@ static void sd_get_rsp(unsigned long host_addr)
                err = -EINVAL;
        spin_unlock(&pcr->lock);
 
-       if (err < 0)
+       if (err < 0) {
+               rtsx_pci_stop_cmd(host->pcr);
+               sd_print_debug_regs(host);
+               sd_clear_error(host);
                goto out;
+       }
 
        rsp_type = host->rsp_type;
        stat_idx = host->rsp_len;
 
-       if (rsp_type == SD_RSP_TYPE_R0) {
-               err = 0;
+       if (rsp_type == SD_RSP_TYPE_R0)
                goto out;
-       }
 
        /* Eliminate returned value of CHECK_REG_CMD */
        ptr = rtsx_pci_get_cmd_data(pcr) + 1;
@@ -495,14 +506,19 @@ static void sd_get_rsp(unsigned long host_addr)
                goto out;
 
        if (cmd->data) {
-               sd_start_multi_rw(host, host->mrq);
+               err = sd_start_multi_rw(host, host->mrq);
+               if (err) {
+                       cmd->data->error = err;
+                       dev_err(sdmmc_dev(host),
+                               "error: start data transfer failed\n");
+                       tasklet_schedule(&host->data_tasklet);
+               }
                spin_unlock_irqrestore(&host->lock, flags);
                return;
        }
 
 out:
        cmd->error = err;
-
        tasklet_schedule(&host->finish_tasklet);
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -522,7 +538,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
                data->host_cookie = 0;
        }
 
-       if (next || (!next && data->host_cookie != host->next_data.cookie))
+       if (next || data->host_cookie != host->next_data.cookie)
                sg_count = rtsx_pci_dma_map_sg(pcr,
                                data->sg, data->sg_len, read);
        else
@@ -577,7 +593,6 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
        int uhs = mmc_card_uhs(card);
        int read = data->flags & MMC_DATA_READ;
        u8 cfg2, trans_mode;
-       int err;
        size_t data_len = data->blksz * data->blocks;
 
        if (host->data)
@@ -638,12 +653,7 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
        mod_timer(&host->timer, jiffies + 10 * HZ);
        rtsx_pci_send_cmd_no_wait(pcr);
 
-       err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read);
-       if (err < 0) {
-               data->error = err;
-               tasklet_schedule(&host->finish_tasklet);
-       }
-       return 0;
+       return rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read);
 }
 
 static void sd_finish_multi_rw(unsigned long host_addr)
@@ -657,8 +667,9 @@ static void sd_finish_multi_rw(unsigned long host_addr)
        spin_lock_irqsave(&host->lock, flags);
 
        if (!host->data) {
-               dev_err(sdmmc_dev(host), "error: no data exist\n");
-               goto out;
+               dev_err(sdmmc_dev(host), "error: data not exist\n");
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
        }
 
        data = host->data;
@@ -669,19 +680,22 @@ static void sd_finish_multi_rw(unsigned long host_addr)
        else if (pcr->trans_result != TRANS_RESULT_OK)
                err = -EINVAL;
 
-       if (err < 0) {
+       if (err < 0)
                data->error = err;
-               goto out;
+
+       if (data->error) {
+               rtsx_pci_stop_cmd(host->pcr);
+               sd_print_debug_regs(host);
+               sd_clear_error(host);
+               dev_dbg(sdmmc_dev(host), "data transfer failed %d\n",
+                       data->error);
        }
 
-       if (!host->mrq->sbc && data->stop) {
+       if (!host->mrq->sbc && data->stop)
                sd_send_cmd(host, data->stop);
-               spin_unlock_irqrestore(&host->lock, flags);
-               return;
-       }
+       else
+               tasklet_schedule(&host->finish_tasklet);
 
-out:
-       tasklet_schedule(&host->finish_tasklet);
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -1075,6 +1089,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
                break;
 
+       case MMC_TIMING_MMC_DDR52:
        case MMC_TIMING_UHS_DDR50:
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
                                0x0C | SD_ASYNC_FIFO_NOT_RST,
@@ -1155,6 +1170,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                host->vpclk = true;
                host->double_clk = false;
                break;
+       case MMC_TIMING_MMC_DDR52:
        case MMC_TIMING_UHS_DDR50:
        case MMC_TIMING_UHS_SDR25:
                host->ssc_depth = RTSX_SSC_DEPTH_1M;
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
new file mode 100644 (file)
index 0000000..e11fafa
--- /dev/null
@@ -0,0 +1,1455 @@
+/* Realtek USB SD/MMC Card Interface driver
+ *
+ * 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 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/card.h>
+#include <linux/scatterlist.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/mfd/rtsx_usb.h>
+#include <asm/unaligned.h>
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#define RTSX_USB_USE_LEDS_CLASS
+#endif
+
+struct rtsx_usb_sdmmc {
+       struct platform_device  *pdev;
+       struct rtsx_ucr *ucr;
+       struct mmc_host         *mmc;
+       struct mmc_request      *mrq;
+
+       struct mutex            host_mutex;
+
+       u8                      ssc_depth;
+       unsigned int            clock;
+       bool                    vpclk;
+       bool                    double_clk;
+       bool                    host_removal;
+       bool                    card_exist;
+       bool                    initial_mode;
+       bool                    ddr_mode;
+
+       unsigned char           power_mode;
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+       struct led_classdev     led;
+       char                    led_name[32];
+       struct work_struct      led_work;
+#endif
+};
+
+static inline struct device *sdmmc_dev(struct rtsx_usb_sdmmc *host)
+{
+       return &(host->pdev->dev);
+}
+
+static inline void sd_clear_error(struct rtsx_usb_sdmmc *host)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       rtsx_usb_ep0_write_register(ucr, CARD_STOP,
+                                 SD_STOP | SD_CLR_ERR,
+                                 SD_STOP | SD_CLR_ERR);
+
+       rtsx_usb_clear_dma_err(ucr);
+       rtsx_usb_clear_fsm_err(ucr);
+}
+
+#ifdef DEBUG
+static void sd_print_debug_regs(struct rtsx_usb_sdmmc *host)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       u8 val = 0;
+
+       rtsx_usb_ep0_read_register(ucr, SD_STAT1, &val);
+       dev_dbg(sdmmc_dev(host), "SD_STAT1: 0x%x\n", val);
+       rtsx_usb_ep0_read_register(ucr, SD_STAT2, &val);
+       dev_dbg(sdmmc_dev(host), "SD_STAT2: 0x%x\n", val);
+       rtsx_usb_ep0_read_register(ucr, SD_BUS_STAT, &val);
+       dev_dbg(sdmmc_dev(host), "SD_BUS_STAT: 0x%x\n", val);
+}
+#else
+#define sd_print_debug_regs(host)
+#endif /* DEBUG */
+
+static int sd_read_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd,
+              u16 byte_cnt, u8 *buf, int buf_len, int timeout)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+       u8 trans_mode;
+
+       if (!buf)
+               buf_len = 0;
+
+       rtsx_usb_init_cmd(ucr);
+       if (cmd != NULL) {
+               dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__
+                               , cmd->opcode);
+               if (cmd->opcode == MMC_SEND_TUNING_BLOCK)
+                       trans_mode = SD_TM_AUTO_TUNING;
+               else
+                       trans_mode = SD_TM_NORMAL_READ;
+
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD1, 0xFF, (u8)(cmd->arg >> 24));
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD2, 0xFF, (u8)(cmd->arg >> 16));
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD3, 0xFF, (u8)(cmd->arg >> 8));
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD4, 0xFF, (u8)cmd->arg);
+       } else {
+               trans_mode = SD_TM_AUTO_READ_3;
+       }
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H,
+                       0xFF, (u8)(byte_cnt >> 8));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF,
+                       SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+                       SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
+       if (trans_mode != SD_TM_AUTO_TUNING)
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
+                       0xFF, trans_mode | SD_TRANSFER_START);
+       rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
+                       SD_TRANSFER_END, SD_TRANSFER_END);
+
+       if (cmd != NULL) {
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0);
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0);
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0);
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0);
+       }
+
+       err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout);
+       if (err) {
+               dev_dbg(sdmmc_dev(host),
+                       "rtsx_usb_send_cmd failed (err = %d)\n", err);
+               return err;
+       }
+
+       err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout);
+       if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
+               sd_print_debug_regs(host);
+
+               if (!err) {
+                       dev_dbg(sdmmc_dev(host),
+                               "Transfer failed (SD_TRANSFER = %02x)\n",
+                               ucr->rsp_buf[0]);
+                       err = -EIO;
+               } else {
+                       dev_dbg(sdmmc_dev(host),
+                               "rtsx_usb_get_rsp failed (err = %d)\n", err);
+               }
+
+               return err;
+       }
+
+       if (cmd != NULL) {
+               cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1);
+               dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
+                               cmd->resp[0]);
+       }
+
+       if (buf && buf_len) {
+               /* 2-byte aligned part */
+               err = rtsx_usb_read_ppbuf(ucr, buf, byte_cnt - (byte_cnt % 2));
+               if (err) {
+                       dev_dbg(sdmmc_dev(host),
+                               "rtsx_usb_read_ppbuf failed (err = %d)\n", err);
+                       return err;
+               }
+
+               /* unaligned byte */
+               if (byte_cnt % 2)
+                       return rtsx_usb_read_register(ucr,
+                                       PPBUF_BASE2 + byte_cnt,
+                                       buf + byte_cnt - 1);
+       }
+
+       return 0;
+}
+
+static int sd_write_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd,
+               u16 byte_cnt, u8 *buf, int buf_len, int timeout)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+       u8 trans_mode;
+
+       if (!buf)
+               buf_len = 0;
+
+       if (buf && buf_len) {
+               err = rtsx_usb_write_ppbuf(ucr, buf, buf_len);
+               if (err) {
+                       dev_dbg(sdmmc_dev(host),
+                               "rtsx_usb_write_ppbuf failed (err = %d)\n",
+                               err);
+                       return err;
+               }
+       }
+
+       trans_mode = (cmd != NULL) ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3;
+       rtsx_usb_init_cmd(ucr);
+
+       if (cmd != NULL) {
+               dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__,
+                               cmd->opcode);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD1, 0xFF, (u8)(cmd->arg >> 24));
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD2, 0xFF, (u8)(cmd->arg >> 16));
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD3, 0xFF, (u8)(cmd->arg >> 8));
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CMD4, 0xFF, (u8)cmd->arg);
+       }
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H,
+                       0xFF, (u8)(byte_cnt >> 8));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF,
+               SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+               SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                       CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
+                       trans_mode | SD_TRANSFER_START);
+       rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
+                       SD_TRANSFER_END, SD_TRANSFER_END);
+
+       if (cmd != NULL) {
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0);
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0);
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0);
+               rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0);
+       }
+
+       err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout);
+       if (err) {
+               dev_dbg(sdmmc_dev(host),
+                       "rtsx_usb_send_cmd failed (err = %d)\n", err);
+               return err;
+       }
+
+       err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout);
+       if (err) {
+               sd_print_debug_regs(host);
+               dev_dbg(sdmmc_dev(host),
+                       "rtsx_usb_get_rsp failed (err = %d)\n", err);
+               return err;
+       }
+
+       if (cmd != NULL) {
+               cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1);
+               dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
+                               cmd->resp[0]);
+       }
+
+       return 0;
+}
+
+static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
+               struct mmc_command *cmd)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       u8 cmd_idx = (u8)cmd->opcode;
+       u32 arg = cmd->arg;
+       int err = 0;
+       int timeout = 100;
+       int i;
+       u8 *ptr;
+       int stat_idx = 0;
+       int len = 2;
+       u8 rsp_type;
+
+       dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
+                       __func__, cmd_idx, arg);
+
+       /* Response type:
+        * R0
+        * R1, R5, R6, R7
+        * R1b
+        * R2
+        * R3, R4
+        */
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               rsp_type = SD_RSP_TYPE_R0;
+               break;
+       case MMC_RSP_R1:
+               rsp_type = SD_RSP_TYPE_R1;
+               break;
+       case MMC_RSP_R1 & ~MMC_RSP_CRC:
+               rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
+               break;
+       case MMC_RSP_R1B:
+               rsp_type = SD_RSP_TYPE_R1b;
+               break;
+       case MMC_RSP_R2:
+               rsp_type = SD_RSP_TYPE_R2;
+               break;
+       case MMC_RSP_R3:
+               rsp_type = SD_RSP_TYPE_R3;
+               break;
+       default:
+               dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (rsp_type == SD_RSP_TYPE_R1b)
+               timeout = 3000;
+
+       if (cmd->opcode == SD_SWITCH_VOLTAGE) {
+               err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
+                               SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
+                               SD_CLK_TOGGLE_EN);
+               if (err)
+                       goto out;
+       }
+
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
+                       0x01, PINGPONG_BUFFER);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
+                       0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START);
+       rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
+                    SD_TRANSFER_END | SD_STAT_IDLE,
+                    SD_TRANSFER_END | SD_STAT_IDLE);
+
+       if (rsp_type == SD_RSP_TYPE_R2) {
+               /* Read data from ping-pong buffer */
+               for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
+                       rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
+               stat_idx = 16;
+       } else if (rsp_type != SD_RSP_TYPE_R0) {
+               /* Read data from SD_CMDx registers */
+               for (i = SD_CMD0; i <= SD_CMD4; i++)
+                       rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
+               stat_idx = 5;
+       }
+       len += stat_idx;
+
+       rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_STAT1, 0, 0);
+
+       err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
+       if (err) {
+               dev_dbg(sdmmc_dev(host),
+                       "rtsx_usb_send_cmd error (err = %d)\n", err);
+               goto out;
+       }
+
+       err = rtsx_usb_get_rsp(ucr, len, timeout);
+       if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
+               sd_print_debug_regs(host);
+               sd_clear_error(host);
+
+               if (!err) {
+                       dev_dbg(sdmmc_dev(host),
+                               "Transfer failed (SD_TRANSFER = %02x)\n",
+                                       ucr->rsp_buf[0]);
+                       err = -EIO;
+               } else {
+                       dev_dbg(sdmmc_dev(host),
+                               "rtsx_usb_get_rsp failed (err = %d)\n", err);
+               }
+
+               goto out;
+       }
+
+       if (rsp_type == SD_RSP_TYPE_R0) {
+               err = 0;
+               goto out;
+       }
+
+       /* Skip result of CHECK_REG_CMD */
+       ptr = ucr->rsp_buf + 1;
+
+       /* Check (Start,Transmission) bit of Response */
+       if ((ptr[0] & 0xC0) != 0) {
+               err = -EILSEQ;
+               dev_dbg(sdmmc_dev(host), "Invalid response bit\n");
+               goto out;
+       }
+
+       /* Check CRC7 */
+       if (!(rsp_type & SD_NO_CHECK_CRC7)) {
+               if (ptr[stat_idx] & SD_CRC7_ERR) {
+                       err = -EILSEQ;
+                       dev_dbg(sdmmc_dev(host), "CRC7 error\n");
+                       goto out;
+               }
+       }
+
+       if (rsp_type == SD_RSP_TYPE_R2) {
+               for (i = 0; i < 4; i++) {
+                       cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4);
+                       dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n",
+                                       i, cmd->resp[i]);
+               }
+       } else {
+               cmd->resp[0] = get_unaligned_be32(ptr + 1);
+               dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
+                               cmd->resp[0]);
+       }
+
+out:
+       cmd->error = err;
+}
+
+static int sd_rw_multi(struct rtsx_usb_sdmmc *host, struct mmc_request *mrq)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       struct mmc_data *data = mrq->data;
+       int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
+       u8 cfg2, trans_mode;
+       int err;
+       u8 flag;
+       size_t data_len = data->blksz * data->blocks;
+       unsigned int pipe;
+
+       if (read) {
+               dev_dbg(sdmmc_dev(host), "%s: read %zu bytes\n",
+                               __func__, data_len);
+               cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+                       SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
+               trans_mode = SD_TM_AUTO_READ_3;
+       } else {
+               dev_dbg(sdmmc_dev(host), "%s: write %zu bytes\n",
+                               __func__, data_len);
+               cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+                       SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
+               trans_mode = SD_TM_AUTO_WRITE_3;
+       }
+
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L,
+                       0xFF, (u8)data->blocks);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H,
+                       0xFF, (u8)(data->blocks >> 8));
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
+                       0x01, RING_BUFFER);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3,
+                       0xFF, (u8)(data_len >> 24));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2,
+                       0xFF, (u8)(data_len >> 16));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1,
+                       0xFF, (u8)(data_len >> 8));
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0,
+                       0xFF, (u8)data_len);
+       if (read) {
+               flag = MODE_CDIR;
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
+                               0x03 | DMA_PACK_SIZE_MASK,
+                               DMA_DIR_FROM_CARD | DMA_EN | DMA_512);
+       } else {
+               flag = MODE_CDOR;
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
+                               0x03 | DMA_PACK_SIZE_MASK,
+                               DMA_DIR_TO_CARD | DMA_EN | DMA_512);
+       }
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
+                       trans_mode | SD_TRANSFER_START);
+       rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
+                       SD_TRANSFER_END, SD_TRANSFER_END);
+
+       err = rtsx_usb_send_cmd(ucr, flag, 100);
+       if (err)
+               return err;
+
+       if (read)
+               pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN);
+       else
+               pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT);
+
+       err = rtsx_usb_transfer_data(ucr, pipe, data->sg, data_len,
+                       data->sg_len,  NULL, 10000);
+       if (err) {
+               dev_dbg(sdmmc_dev(host), "rtsx_usb_transfer_data error %d\n"
+                               , err);
+               sd_clear_error(host);
+               return err;
+       }
+
+       return rtsx_usb_get_rsp(ucr, 1, 2000);
+}
+
+static inline void sd_enable_initial_mode(struct rtsx_usb_sdmmc *host)
+{
+       rtsx_usb_write_register(host->ucr, SD_CFG1,
+                       SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128);
+}
+
+static inline void sd_disable_initial_mode(struct rtsx_usb_sdmmc *host)
+{
+       rtsx_usb_write_register(host->ucr, SD_CFG1,
+                       SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
+}
+
+static void sd_normal_rw(struct rtsx_usb_sdmmc *host,
+               struct mmc_request *mrq)
+{
+       struct mmc_command *cmd = mrq->cmd;
+       struct mmc_data *data = mrq->data;
+       u8 *buf;
+
+       buf = kzalloc(data->blksz, GFP_NOIO);
+       if (!buf) {
+               cmd->error = -ENOMEM;
+               return;
+       }
+
+       if (data->flags & MMC_DATA_READ) {
+               if (host->initial_mode)
+                       sd_disable_initial_mode(host);
+
+               cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf,
+                               data->blksz, 200);
+
+               if (host->initial_mode)
+                       sd_enable_initial_mode(host);
+
+               sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz);
+       } else {
+               sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz);
+
+               cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf,
+                               data->blksz, 200);
+       }
+
+       kfree(buf);
+}
+
+static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+
+       dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n",
+                       __func__, tx ? "TX" : "RX", sample_point);
+
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
+
+       if (tx)
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+                               0x0F, sample_point);
+       else
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK1_CTL,
+                               0x0F, sample_point);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+                       PHASE_NOT_RESET, PHASE_NOT_RESET);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0);
+
+       err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static inline u32 get_phase_point(u32 phase_map, unsigned int idx)
+{
+       idx &= MAX_PHASE;
+       return phase_map & (1 << idx);
+}
+
+static int get_phase_len(u32 phase_map, unsigned int idx)
+{
+       int i;
+
+       for (i = 0; i < MAX_PHASE + 1; i++) {
+               if (get_phase_point(phase_map, idx + i) == 0)
+                       return i;
+       }
+       return MAX_PHASE + 1;
+}
+
+static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map)
+{
+       int start = 0, len = 0;
+       int start_final = 0, len_final = 0;
+       u8 final_phase = 0xFF;
+
+       if (phase_map == 0) {
+               dev_dbg(sdmmc_dev(host), "Phase: [map:%x]\n", phase_map);
+               return final_phase;
+       }
+
+       while (start < MAX_PHASE + 1) {
+               len = get_phase_len(phase_map, start);
+               if (len_final < len) {
+                       start_final = start;
+                       len_final = len;
+               }
+               start += len ? len : 1;
+       }
+
+       final_phase = (start_final + len_final / 2) & MAX_PHASE;
+       dev_dbg(sdmmc_dev(host), "Phase: [map:%x] [maxlen:%d] [final:%d]\n",
+               phase_map, len_final, final_phase);
+
+       return final_phase;
+}
+
+static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host)
+{
+       int err, i;
+       u8 val = 0;
+
+       for (i = 0; i < 100; i++) {
+               err = rtsx_usb_ep0_read_register(host->ucr,
+                               SD_DATA_STATE, &val);
+               if (val & SD_DATA_IDLE)
+                       return;
+
+               usleep_range(100, 1000);
+       }
+}
+
+static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host,
+               u8 opcode, u8 sample_point)
+{
+       int err;
+       struct mmc_command cmd = {0};
+
+       err = sd_change_phase(host, sample_point, 0);
+       if (err)
+               return err;
+
+       cmd.opcode = MMC_SEND_TUNING_BLOCK;
+       err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100);
+       if (err) {
+               /* Wait till SD DATA IDLE */
+               sd_wait_data_idle(host);
+               sd_clear_error(host);
+               return err;
+       }
+
+       return 0;
+}
+
+static void sd_tuning_phase(struct rtsx_usb_sdmmc *host,
+               u8 opcode, u16 *phase_map)
+{
+       int err, i;
+       u16 raw_phase_map = 0;
+
+       for (i = MAX_PHASE; i >= 0; i--) {
+               err = sd_tuning_rx_cmd(host, opcode, (u8)i);
+               if (!err)
+                       raw_phase_map |= 1 << i;
+       }
+
+       if (phase_map)
+               *phase_map = raw_phase_map;
+}
+
+static int sd_tuning_rx(struct rtsx_usb_sdmmc *host, u8 opcode)
+{
+       int err, i;
+       u16 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map;
+       u8 final_phase;
+
+       /* setting fixed default TX phase */
+       err = sd_change_phase(host, 0x01, 1);
+       if (err) {
+               dev_dbg(sdmmc_dev(host), "TX phase setting failed\n");
+               return err;
+       }
+
+       /* tuning RX phase */
+       for (i = 0; i < RX_TUNING_CNT; i++) {
+               sd_tuning_phase(host, opcode, &(raw_phase_map[i]));
+
+               if (raw_phase_map[i] == 0)
+                       break;
+       }
+
+       phase_map = 0xFFFF;
+       for (i = 0; i < RX_TUNING_CNT; i++) {
+               dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%04x\n",
+                               i, raw_phase_map[i]);
+               phase_map &= raw_phase_map[i];
+       }
+       dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%04x\n", phase_map);
+
+       if (phase_map) {
+               final_phase = sd_search_final_phase(host, phase_map);
+               if (final_phase == 0xFF)
+                       return -EINVAL;
+
+               err = sd_change_phase(host, final_phase, 0);
+               if (err)
+                       return err;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int sdmmc_get_ro(struct mmc_host *mmc)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+       u16 val;
+
+       if (host->host_removal)
+               return -ENOMEDIUM;
+
+       mutex_lock(&ucr->dev_mutex);
+
+       /* Check SD card detect */
+       err = rtsx_usb_get_card_status(ucr, &val);
+
+       mutex_unlock(&ucr->dev_mutex);
+
+
+       /* Treat failed detection as non-ro */
+       if (err)
+               return 0;
+
+       if (val & SD_WP)
+               return 1;
+
+       return 0;
+}
+
+static int sdmmc_get_cd(struct mmc_host *mmc)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+       u16 val;
+
+       if (host->host_removal)
+               return -ENOMEDIUM;
+
+       mutex_lock(&ucr->dev_mutex);
+
+       /* Check SD card detect */
+       err = rtsx_usb_get_card_status(ucr, &val);
+
+       mutex_unlock(&ucr->dev_mutex);
+
+       /* Treat failed detection as non-exist */
+       if (err)
+               goto no_card;
+
+       if (val & SD_CD) {
+               host->card_exist = true;
+               return 1;
+       }
+
+no_card:
+       host->card_exist = false;
+       return 0;
+}
+
+static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+       struct mmc_command *cmd = mrq->cmd;
+       struct mmc_data *data = mrq->data;
+       unsigned int data_size = 0;
+
+       dev_dbg(sdmmc_dev(host), "%s\n", __func__);
+
+       if (host->host_removal) {
+               cmd->error = -ENOMEDIUM;
+               goto finish;
+       }
+
+       if ((!host->card_exist)) {
+               cmd->error = -ENOMEDIUM;
+               goto finish_detect_card;
+       }
+
+       /*
+        * Reject SDIO CMDs to speed up card identification
+        * since unsupported
+        */
+       if (cmd->opcode == SD_IO_SEND_OP_COND ||
+           cmd->opcode == SD_IO_RW_DIRECT ||
+           cmd->opcode == SD_IO_RW_EXTENDED) {
+               cmd->error = -EINVAL;
+               goto finish;
+       }
+
+       mutex_lock(&ucr->dev_mutex);
+
+       mutex_lock(&host->host_mutex);
+       host->mrq = mrq;
+       mutex_unlock(&host->host_mutex);
+
+       if (mrq->data)
+               data_size = data->blocks * data->blksz;
+
+       if (!data_size) {
+               sd_send_cmd_get_rsp(host, cmd);
+       } else if ((!(data_size % 512) && cmd->opcode != MMC_SEND_EXT_CSD) ||
+                  mmc_op_multi(cmd->opcode)) {
+               sd_send_cmd_get_rsp(host, cmd);
+
+               if (!cmd->error) {
+                       sd_rw_multi(host, mrq);
+
+                       if (mmc_op_multi(cmd->opcode) && mrq->stop) {
+                               sd_send_cmd_get_rsp(host, mrq->stop);
+                               rtsx_usb_write_register(ucr, MC_FIFO_CTL,
+                                               FIFO_FLUSH, FIFO_FLUSH);
+                       }
+               }
+       } else {
+               sd_normal_rw(host, mrq);
+       }
+
+       if (mrq->data) {
+               if (cmd->error || data->error)
+                       data->bytes_xfered = 0;
+               else
+                       data->bytes_xfered = data->blocks * data->blksz;
+       }
+
+       mutex_unlock(&ucr->dev_mutex);
+
+finish_detect_card:
+       if (cmd->error) {
+               /*
+                * detect card when fail to update card existence state and
+                * speed up card removal when retry
+                */
+               sdmmc_get_cd(mmc);
+               dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
+       }
+
+finish:
+       mutex_lock(&host->host_mutex);
+       host->mrq = NULL;
+       mutex_unlock(&host->host_mutex);
+
+       mmc_request_done(mmc, mrq);
+}
+
+static int sd_set_bus_width(struct rtsx_usb_sdmmc *host,
+               unsigned char bus_width)
+{
+       int err = 0;
+       u8 width[] = {
+               [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT,
+               [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT,
+               [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT,
+       };
+
+       if (bus_width <= MMC_BUS_WIDTH_8)
+               err = rtsx_usb_write_register(host->ucr, SD_CFG1,
+                               0x03, width[bus_width]);
+
+       return err;
+}
+
+static int sd_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
+
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+static int sd_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
+
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+static int sd_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xAA);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0xAA);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA9);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
+
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+static int sd_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xA5);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x9A);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA5);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x9A);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x65);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x5A);
+
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+static int sd_power_on(struct rtsx_usb_sdmmc *host)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+
+       dev_dbg(sdmmc_dev(host), "%s\n", __func__);
+       rtsx_usb_init_cmd(ucr);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE,
+                       CARD_SHARE_MASK, CARD_SHARE_SD);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN,
+                       SD_CLK_EN, SD_CLK_EN);
+       err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+       if (err)
+               return err;
+
+       if (CHECK_PKG(ucr, LQFP48))
+               err = sd_pull_ctl_enable_lqfp48(ucr);
+       else
+               err = sd_pull_ctl_enable_qfn24(ucr);
+       if (err)
+               return err;
+
+       err = rtsx_usb_write_register(ucr, CARD_PWR_CTL,
+                       POWER_MASK, PARTIAL_POWER_ON);
+       if (err)
+               return err;
+
+       usleep_range(800, 1000);
+
+       rtsx_usb_init_cmd(ucr);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+                       POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
+                       SD_OUTPUT_EN, SD_OUTPUT_EN);
+
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+static int sd_power_off(struct rtsx_usb_sdmmc *host)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+
+       dev_dbg(sdmmc_dev(host), "%s\n", __func__);
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+                       POWER_MASK, POWER_OFF);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+                       POWER_MASK|LDO3318_PWR_MASK, POWER_OFF|LDO_SUSPEND);
+
+       err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+       if (err)
+               return err;
+
+       if (CHECK_PKG(ucr, LQFP48))
+                       return sd_pull_ctl_disable_lqfp48(ucr);
+       return sd_pull_ctl_disable_qfn24(ucr);
+}
+
+static int sd_set_power_mode(struct rtsx_usb_sdmmc *host,
+               unsigned char power_mode)
+{
+       int err;
+
+       if (power_mode != MMC_POWER_OFF)
+               power_mode = MMC_POWER_ON;
+
+       if (power_mode == host->power_mode)
+               return 0;
+
+       if (power_mode == MMC_POWER_OFF) {
+               err = sd_power_off(host);
+               pm_runtime_put(sdmmc_dev(host));
+       } else {
+               pm_runtime_get_sync(sdmmc_dev(host));
+               err = sd_power_on(host);
+       }
+
+       if (!err)
+               host->power_mode = power_mode;
+
+       return err;
+}
+
+static int sd_set_timing(struct rtsx_usb_sdmmc *host,
+               unsigned char timing, bool *ddr_mode)
+{
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+
+       *ddr_mode = false;
+
+       rtsx_usb_init_cmd(ucr);
+
+       switch (timing) {
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_UHS_SDR50:
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
+                               0x0C | SD_ASYNC_FIFO_RST,
+                               SD_30_MODE | SD_ASYNC_FIFO_RST);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
+                               CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
+               break;
+
+       case MMC_TIMING_UHS_DDR50:
+               *ddr_mode = true;
+
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
+                               0x0C | SD_ASYNC_FIFO_RST,
+                               SD_DDR_MODE | SD_ASYNC_FIFO_RST);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
+                               CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
+                               DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
+                               DDR_VAR_RX_DAT | DDR_VAR_RX_CMD,
+                               DDR_VAR_RX_DAT | DDR_VAR_RX_CMD);
+               break;
+
+       case MMC_TIMING_MMC_HS:
+       case MMC_TIMING_SD_HS:
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
+                               0x0C, SD_20_MODE);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
+                               CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
+                               SD20_TX_SEL_MASK, SD20_TX_14_AHEAD);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
+                               SD20_RX_SEL_MASK, SD20_RX_14_DELAY);
+               break;
+
+       default:
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_CFG1, 0x0C, SD_20_MODE);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
+                               CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               SD_PUSH_POINT_CTL, 0xFF, 0);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
+                               SD20_RX_SEL_MASK, SD20_RX_POS_EDGE);
+               break;
+       }
+
+       err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+
+       return err;
+}
+
+static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+
+       dev_dbg(sdmmc_dev(host), "%s\n", __func__);
+       mutex_lock(&ucr->dev_mutex);
+
+       if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) {
+               mutex_unlock(&ucr->dev_mutex);
+               return;
+       }
+
+       sd_set_power_mode(host, ios->power_mode);
+       sd_set_bus_width(host, ios->bus_width);
+       sd_set_timing(host, ios->timing, &host->ddr_mode);
+
+       host->vpclk = false;
+       host->double_clk = true;
+
+       switch (ios->timing) {
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_UHS_SDR50:
+               host->ssc_depth = SSC_DEPTH_2M;
+               host->vpclk = true;
+               host->double_clk = false;
+               break;
+       case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_UHS_SDR25:
+               host->ssc_depth = SSC_DEPTH_1M;
+               break;
+       default:
+               host->ssc_depth = SSC_DEPTH_512K;
+               break;
+       }
+
+       host->initial_mode = (ios->clock <= 1000000) ? true : false;
+       host->clock = ios->clock;
+
+       rtsx_usb_switch_clock(host->ucr, host->clock, host->ssc_depth,
+                       host->initial_mode, host->double_clk, host->vpclk);
+
+       mutex_unlock(&ucr->dev_mutex);
+       dev_dbg(sdmmc_dev(host), "%s end\n", __func__);
+}
+
+static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+       int err = 0;
+
+       dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n",
+                       __func__, ios->signal_voltage);
+
+       if (host->host_removal)
+               return -ENOMEDIUM;
+
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120)
+               return -EPERM;
+
+       mutex_lock(&ucr->dev_mutex);
+
+       err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD);
+       if (err) {
+               mutex_unlock(&ucr->dev_mutex);
+               return err;
+       }
+
+       /* Let mmc core do the busy checking, simply stop the forced-toggle
+        * clock(while issuing CMD11) and switch voltage.
+        */
+       rtsx_usb_init_cmd(ucr);
+
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL,
+                               SD_IO_USING_1V8, SD_IO_USING_3V3);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG,
+                               TUNE_SD18_MASK, TUNE_SD18_3V3);
+       } else {
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BUS_STAT,
+                               SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
+                               SD_CLK_FORCE_STOP);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL,
+                               SD_IO_USING_1V8, SD_IO_USING_1V8);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG,
+                               TUNE_SD18_MASK, TUNE_SD18_1V8);
+       }
+
+       err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+       mutex_unlock(&ucr->dev_mutex);
+
+       return err;
+}
+
+static int sdmmc_card_busy(struct mmc_host *mmc)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+       int err;
+       u8 stat;
+       u8 mask = SD_DAT3_STATUS | SD_DAT2_STATUS | SD_DAT1_STATUS
+               | SD_DAT0_STATUS;
+
+       dev_dbg(sdmmc_dev(host), "%s\n", __func__);
+
+       mutex_lock(&ucr->dev_mutex);
+
+       err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
+                       SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
+                       SD_CLK_TOGGLE_EN);
+       if (err)
+               goto out;
+
+       mdelay(1);
+
+       err = rtsx_usb_read_register(ucr, SD_BUS_STAT, &stat);
+       if (err)
+               goto out;
+
+       err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
+                       SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
+out:
+       mutex_unlock(&ucr->dev_mutex);
+
+       if (err)
+               return err;
+
+       /* check if any pin between dat[0:3] is low */
+       if ((stat & mask) != mask)
+               return 1;
+       else
+               return 0;
+}
+
+static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+       struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_ucr *ucr = host->ucr;
+       int err = 0;
+
+       if (host->host_removal)
+               return -ENOMEDIUM;
+
+       mutex_lock(&ucr->dev_mutex);
+
+       if (!host->ddr_mode)
+               err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK);
+
+       mutex_unlock(&ucr->dev_mutex);
+
+       return err;
+}
+
+static const struct mmc_host_ops rtsx_usb_sdmmc_ops = {
+       .request = sdmmc_request,
+       .set_ios = sdmmc_set_ios,
+       .get_ro = sdmmc_get_ro,
+       .get_cd = sdmmc_get_cd,
+       .start_signal_voltage_switch = sdmmc_switch_voltage,
+       .card_busy = sdmmc_card_busy,
+       .execute_tuning = sdmmc_execute_tuning,
+};
+
+#ifdef RTSX_USB_USE_LEDS_CLASS
+static void rtsx_usb_led_control(struct led_classdev *led,
+       enum led_brightness brightness)
+{
+       struct rtsx_usb_sdmmc *host = container_of(led,
+                       struct rtsx_usb_sdmmc, led);
+
+       if (host->host_removal)
+               return;
+
+       host->led.brightness = brightness;
+       schedule_work(&host->led_work);
+}
+
+static void rtsx_usb_update_led(struct work_struct *work)
+{
+       struct rtsx_usb_sdmmc *host =
+               container_of(work, struct rtsx_usb_sdmmc, led_work);
+       struct rtsx_ucr *ucr = host->ucr;
+
+       mutex_lock(&ucr->dev_mutex);
+
+       if (host->led.brightness == LED_OFF)
+               rtsx_usb_turn_off_led(ucr);
+       else
+               rtsx_usb_turn_on_led(ucr);
+
+       mutex_unlock(&ucr->dev_mutex);
+}
+#endif
+
+static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       mmc->f_min = 250000;
+       mmc->f_max = 208000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
+               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
+               MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
+               MMC_CAP_NEEDS_POLL;
+
+       mmc->max_current_330 = 400;
+       mmc->max_current_180 = 800;
+       mmc->ops = &rtsx_usb_sdmmc_ops;
+       mmc->max_segs = 256;
+       mmc->max_seg_size = 65536;
+       mmc->max_blk_size = 512;
+       mmc->max_blk_count = 65535;
+       mmc->max_req_size = 524288;
+
+       host->power_mode = MMC_POWER_OFF;
+}
+
+static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
+{
+       struct mmc_host *mmc;
+       struct rtsx_usb_sdmmc *host;
+       struct rtsx_ucr *ucr;
+#ifdef RTSX_USB_USE_LEDS_CLASS
+       int err;
+#endif
+
+       ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
+       if (!ucr)
+               return -ENXIO;
+
+       dev_dbg(&(pdev->dev), ": Realtek USB SD/MMC controller found\n");
+
+       mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       host = mmc_priv(mmc);
+       host->ucr = ucr;
+       host->mmc = mmc;
+       host->pdev = pdev;
+       platform_set_drvdata(pdev, host);
+
+       mutex_init(&host->host_mutex);
+       rtsx_usb_init_host(host);
+       pm_runtime_enable(&pdev->dev);
+
+#ifdef RTSX_USB_USE_LEDS_CLASS
+       snprintf(host->led_name, sizeof(host->led_name),
+               "%s::", mmc_hostname(mmc));
+       host->led.name = host->led_name;
+       host->led.brightness = LED_OFF;
+       host->led.default_trigger = mmc_hostname(mmc);
+       host->led.brightness_set = rtsx_usb_led_control;
+
+       err = led_classdev_register(mmc_dev(mmc), &host->led);
+       if (err)
+               dev_err(&(pdev->dev),
+                               "Failed to register LED device: %d\n", err);
+       INIT_WORK(&host->led_work, rtsx_usb_update_led);
+
+#endif
+       mmc_add_host(mmc);
+
+       return 0;
+}
+
+static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
+{
+       struct rtsx_usb_sdmmc *host = platform_get_drvdata(pdev);
+       struct mmc_host *mmc;
+
+       if (!host)
+               return 0;
+
+       mmc = host->mmc;
+       host->host_removal = true;
+
+       mutex_lock(&host->host_mutex);
+       if (host->mrq) {
+               dev_dbg(&(pdev->dev),
+                       "%s: Controller removed during transfer\n",
+                       mmc_hostname(mmc));
+               host->mrq->cmd->error = -ENOMEDIUM;
+               if (host->mrq->stop)
+                       host->mrq->stop->error = -ENOMEDIUM;
+               mmc_request_done(mmc, host->mrq);
+       }
+       mutex_unlock(&host->host_mutex);
+
+       mmc_remove_host(mmc);
+
+#ifdef RTSX_USB_USE_LEDS_CLASS
+       cancel_work_sync(&host->led_work);
+       led_classdev_unregister(&host->led);
+#endif
+
+       mmc_free_host(mmc);
+       pm_runtime_disable(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+
+       dev_dbg(&(pdev->dev),
+               ": Realtek USB SD/MMC module has been removed\n");
+
+       return 0;
+}
+
+static struct platform_device_id rtsx_usb_sdmmc_ids[] = {
+       {
+               .name = "rtsx_usb_sdmmc",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids);
+
+static struct platform_driver rtsx_usb_sdmmc_driver = {
+       .probe          = rtsx_usb_sdmmc_drv_probe,
+       .remove         = rtsx_usb_sdmmc_drv_remove,
+       .id_table       = rtsx_usb_sdmmc_ids,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "rtsx_usb_sdmmc",
+       },
+};
+module_platform_driver(rtsx_usb_sdmmc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
+MODULE_DESCRIPTION("Realtek USB SD/MMC Card Host Driver");
index d61eb5a708331d54ad9c4ea948bf7cbb4533d8da..c12301e90d167460a8bb1387a146f85d52353c90 100644 (file)
@@ -33,9 +33,6 @@
 
 #define MAX_BUS_CLK    (4)
 
-/* Number of gpio's used is max data bus width + command and clock lines */
-#define NUM_GPIOS(x)   (x + 2)
-
 /**
  * struct sdhci_s3c - S3C SDHCI instance
  * @host: The SDHCI host created
index 9a79fc4b60ca82bb7319fa34a3ae2d79d093833e..a31f06dadf6fff874a32d0ad2b20c02d8b01095b 100644 (file)
@@ -1510,6 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
                /* In case of UHS-I modes, set High Speed Enable */
                if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+                   (ios->timing == MMC_TIMING_MMC_DDR52) ||
                    (ios->timing == MMC_TIMING_UHS_SDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR104) ||
                    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1570,7 +1571,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
                        else if (ios->timing == MMC_TIMING_UHS_SDR50)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-                       else if (ios->timing == MMC_TIMING_UHS_DDR50)
+                       else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
+                                (ios->timing == MMC_TIMING_MMC_DDR52))
                                ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
                        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
                }
index 54730f4aac87f0143ca08a5ca740634376fc4871..656fbba4c4223f275dffba85ebbc29ffb4574174 100644 (file)
@@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                        break;
                }
                switch (host->timing) {
-               case MMC_TIMING_UHS_DDR50:
+               case MMC_TIMING_MMC_DDR52:
                        /*
                         * MMC core will only set this timing, if the host
-                        * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
-                        * implementations with this capability, e.g. sh73a0,
-                        * will have to set it in their platform data.
+                        * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
+                        * capability. MMCIF implementations with this
+                        * capability, e.g. sh73a0, will have to set it
+                        * in their platform data.
                         */
                        tmp |= CMD_SET_DARS;
                        break;
index 5d49a21296187cc1c228d249b16bbbb7d79405f7..94b821042d9da49fee0e4722b146391bb3005c50 100644 (file)
@@ -321,6 +321,8 @@ source "drivers/mtd/onenand/Kconfig"
 
 source "drivers/mtd/lpddr/Kconfig"
 
+source "drivers/mtd/spi-nor/Kconfig"
+
 source "drivers/mtd/ubi/Kconfig"
 
 endif # MTD
index 4cfb31e6c966ad37d1384d59ccd12d572961ea93..99bb9a1f6e16fc324b7b0a794e06f6abbeb39575 100644 (file)
@@ -32,4 +32,5 @@ inftl-objs            := inftlcore.o inftlmount.o
 
 obj-y          += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
 
+obj-$(CONFIG_MTD_SPI_NOR)      += spi-nor/
 obj-$(CONFIG_MTD_UBI)          += ubi/
index 1210bc2923b71386b94fd53bd4440d8df137486b..c49d0b127fefb32c38539810247ff4adc5adc0fa 100644 (file)
@@ -80,7 +80,7 @@ config MTD_DATAFLASH_OTP
 
 config MTD_M25P80
        tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
-       depends on SPI_MASTER
+       depends on SPI_MASTER && MTD_SPI_NOR
        help
          This enables access to most modern SPI flash chips, used for
          program and data storage.   Series supported include Atmel AT26DF,
@@ -212,7 +212,7 @@ config MTD_DOCG3
 
 config MTD_ST_SPI_FSM
        tristate "ST Microelectronics SPI FSM Serial Flash Controller"
-       depends on ARM || SH
+       depends on ARCH_STI
        help
          This provides an MTD device driver for the ST Microelectronics
          SPI Fast Sequence Mode (FSM) Serial Flash Controller and support
index 524dab3ac9381f4d9efee0bbbfad98cb9171888a..1557d8f672c1eb5e33e5d9e8e05eced5c7cabba9 100644 (file)
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/math64.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mod_devicetable.h>
 
-#include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <linux/of_platform.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
+#include <linux/mtd/spi-nor.h>
 
-/* Flash opcodes. */
-#define        OPCODE_WREN             0x06    /* Write enable */
-#define        OPCODE_RDSR             0x05    /* Read status register */
-#define        OPCODE_WRSR             0x01    /* Write status register 1 byte */
-#define        OPCODE_NORM_READ        0x03    /* Read data bytes (low frequency) */
-#define        OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
-#define        OPCODE_DUAL_READ        0x3b    /* Read data bytes (Dual SPI) */
-#define        OPCODE_QUAD_READ        0x6b    /* Read data bytes (Quad SPI) */
-#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 */
-#define        OPCODE_RDCR             0x35    /* Read configuration register */
-
-/* 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_DUAL_READ_4B     0x3c    /* Read data bytes (Dual SPI) */
-#define        OPCODE_QUAD_READ_4B     0x6c    /* Read data bytes (Quad SPI) */
-#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 and Winbond flashes. */
-#define        OPCODE_EN4B             0xb7    /* Enter 4-byte mode */
-#define        OPCODE_EX4B             0xe9    /* Exit 4-byte mode */
-
-/* Used for Spansion flashes only. */
-#define        OPCODE_BRWR             0x17    /* Bank register write */
-
-/* Status Register bits. */
-#define        SR_WIP                  1       /* Write in progress */
-#define        SR_WEL                  2       /* Write enable latch */
-/* meaning of other SR_* bits may differ between vendors */
-#define        SR_BP0                  4       /* Block protect 0 */
-#define        SR_BP1                  8       /* Block protect 1 */
-#define        SR_BP2                  0x10    /* Block protect 2 */
-#define        SR_SRWD                 0x80    /* SR write protect */
-
-#define SR_QUAD_EN_MX           0x40    /* Macronix Quad I/O */
-
-/* Configuration Register bits. */
-#define CR_QUAD_EN_SPAN                0x2     /* Spansion Quad I/O */
-
-/* Define max times to check status register before we give up. */
-#define        MAX_READY_WAIT_JIFFIES  (40 * HZ)       /* M25P16 specs 40s max chip erase */
 #define        MAX_CMD_SIZE            6
-
-#define JEDEC_MFR(_jedec_id)   ((_jedec_id) >> 16)
-
-/****************************************************************************/
-
-enum read_type {
-       M25P80_NORMAL = 0,
-       M25P80_FAST,
-       M25P80_DUAL,
-       M25P80_QUAD,
-};
-
 struct m25p {
        struct spi_device       *spi;
-       struct mutex            lock;
+       struct spi_nor          spi_nor;
        struct mtd_info         mtd;
-       u16                     page_size;
-       u16                     addr_width;
-       u8                      erase_opcode;
-       u8                      read_opcode;
-       u8                      program_opcode;
-       u8                      *command;
-       enum read_type          flash_read;
+       u8                      command[MAX_CMD_SIZE];
 };
 
-static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
-{
-       return container_of(mtd, struct m25p, mtd);
-}
-
-/****************************************************************************/
-
-/*
- * Internal helper functions
- */
-
-/*
- * Read the status register, returning its value in the location
- * Return the status register value.
- * Returns negative if error occurred.
- */
-static int read_sr(struct m25p *flash)
-{
-       ssize_t retval;
-       u8 code = OPCODE_RDSR;
-       u8 val;
-
-       retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
-
-       if (retval < 0) {
-               dev_err(&flash->spi->dev, "error %d reading SR\n",
-                               (int) retval);
-               return retval;
-       }
-
-       return val;
-}
-
-/*
- * Read configuration register, returning its value in the
- * location. Return the configuration register value.
- * Returns negative if error occured.
- */
-static int read_cr(struct m25p *flash)
-{
-       u8 code = OPCODE_RDCR;
-       int ret;
-       u8 val;
-
-       ret = spi_write_then_read(flash->spi, &code, 1, &val, 1);
-       if (ret < 0) {
-               dev_err(&flash->spi->dev, "error %d reading CR\n", ret);
-               return ret;
-       }
-
-       return val;
-}
-
-/*
- * Write status register 1 byte
- * Returns negative if error occurred.
- */
-static int write_sr(struct m25p *flash, u8 val)
-{
-       flash->command[0] = OPCODE_WRSR;
-       flash->command[1] = val;
-
-       return spi_write(flash->spi, flash->command, 2);
-}
-
-/*
- * Set write enable latch with Write Enable command.
- * Returns negative if error occurred.
- */
-static inline int write_enable(struct m25p *flash)
-{
-       u8      code = OPCODE_WREN;
-
-       return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
-}
-
-/*
- * Send write disble instruction to the chip.
- */
-static inline int write_disable(struct m25p *flash)
-{
-       u8      code = OPCODE_WRDI;
-
-       return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
-}
-
-/*
- * Enable/disable 4-byte addressing mode.
- */
-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;
-               status = spi_write(flash->spi, flash->command, 1);
-
-               if (need_wren)
-                       write_disable(flash);
-
-               return status;
-       default:
-               /* Spansion style */
-               flash->command[0] = OPCODE_BRWR;
-               flash->command[1] = enable << 7;
-               return spi_write(flash->spi, flash->command, 2);
-       }
-}
-
-/*
- * Service routine to read status register until ready, or timeout occurs.
- * Returns non-zero if error.
- */
-static int wait_till_ready(struct m25p *flash)
-{
-       unsigned long deadline;
-       int sr;
-
-       deadline = jiffies + MAX_READY_WAIT_JIFFIES;
-
-       do {
-               if ((sr = read_sr(flash)) < 0)
-                       break;
-               else if (!(sr & SR_WIP))
-                       return 0;
-
-               cond_resched();
-
-       } while (!time_after_eq(jiffies, deadline));
-
-       return 1;
-}
-
-/*
- * Write status Register and configuration register with 2 bytes
- * The first byte will be written to the status register, while the
- * second byte will be written to the configuration register.
- * Return negative if error occured.
- */
-static int write_sr_cr(struct m25p *flash, u16 val)
-{
-       flash->command[0] = OPCODE_WRSR;
-       flash->command[1] = val & 0xff;
-       flash->command[2] = (val >> 8);
-
-       return spi_write(flash->spi, flash->command, 3);
-}
-
-static int macronix_quad_enable(struct m25p *flash)
-{
-       int ret, val;
-       u8 cmd[2];
-       cmd[0] = OPCODE_WRSR;
-
-       val = read_sr(flash);
-       cmd[1] = val | SR_QUAD_EN_MX;
-       write_enable(flash);
-
-       spi_write(flash->spi, &cmd, 2);
-
-       if (wait_till_ready(flash))
-               return 1;
-
-       ret = read_sr(flash);
-       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-               dev_err(&flash->spi->dev, "Macronix Quad bit not set\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int spansion_quad_enable(struct m25p *flash)
+static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 {
+       struct m25p *flash = nor->priv;
+       struct spi_device *spi = flash->spi;
        int ret;
-       int quad_en = CR_QUAD_EN_SPAN << 8;
-
-       write_enable(flash);
 
-       ret = write_sr_cr(flash, quad_en);
-       if (ret < 0) {
-               dev_err(&flash->spi->dev,
-                       "error while writing configuration register\n");
-               return -EINVAL;
-       }
-
-       /* read back and check it */
-       ret = read_cr(flash);
-       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-               dev_err(&flash->spi->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int set_quad_mode(struct m25p *flash, u32 jedec_id)
-{
-       int status;
-
-       switch (JEDEC_MFR(jedec_id)) {
-       case CFI_MFR_MACRONIX:
-               status = macronix_quad_enable(flash);
-               if (status) {
-                       dev_err(&flash->spi->dev,
-                               "Macronix quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
-       default:
-               status = spansion_quad_enable(flash);
-               if (status) {
-                       dev_err(&flash->spi->dev,
-                               "Spansion quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
-       }
-}
-
-/*
- * Erase the whole flash memory
- *
- * Returns 0 if successful, non-zero otherwise.
- */
-static int erase_chip(struct m25p *flash)
-{
-       pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__,
-                       (long long)(flash->mtd.size >> 10));
+       ret = spi_write_then_read(spi, &code, 1, val, len);
+       if (ret < 0)
+               dev_err(&spi->dev, "error %d reading %x\n", ret, code);
 
-       /* Wait until finished previous write command. */
-       if (wait_till_ready(flash))
-               return 1;
-
-       /* Send write enable, then erase commands. */
-       write_enable(flash);
-
-       /* Set up command buffer. */
-       flash->command[0] = OPCODE_CHIP_ERASE;
-
-       spi_write(flash->spi, flash->command, 1);
-
-       return 0;
+       return ret;
 }
 
-static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd)
+static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
 {
        /* opcode is in cmd[0] */
-       cmd[1] = addr >> (flash->addr_width * 8 -  8);
-       cmd[2] = addr >> (flash->addr_width * 8 - 16);
-       cmd[3] = addr >> (flash->addr_width * 8 - 24);
-       cmd[4] = addr >> (flash->addr_width * 8 - 32);
+       cmd[1] = addr >> (nor->addr_width * 8 -  8);
+       cmd[2] = addr >> (nor->addr_width * 8 - 16);
+       cmd[3] = addr >> (nor->addr_width * 8 - 24);
+       cmd[4] = addr >> (nor->addr_width * 8 - 32);
 }
 
-static int m25p_cmdsz(struct m25p *flash)
+static int m25p_cmdsz(struct spi_nor *nor)
 {
-       return 1 + flash->addr_width;
+       return 1 + nor->addr_width;
 }
 
-/*
- * Erase one sector of flash memory at offset ``offset'' which is any
- * address within the sector which should be erased.
- *
- * Returns 0 if successful, non-zero otherwise.
- */
-static int erase_sector(struct m25p *flash, u32 offset)
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+                       int wr_en)
 {
-       pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev),
-                       __func__, flash->mtd.erasesize / 1024, offset);
-
-       /* Wait until finished previous write command. */
-       if (wait_till_ready(flash))
-               return 1;
+       struct m25p *flash = nor->priv;
+       struct spi_device *spi = flash->spi;
 
-       /* Send write enable, then erase commands. */
-       write_enable(flash);
-
-       /* Set up command buffer. */
-       flash->command[0] = flash->erase_opcode;
-       m25p_addr2cmd(flash, offset, flash->command);
-
-       spi_write(flash->spi, flash->command, m25p_cmdsz(flash));
+       flash->command[0] = opcode;
+       if (buf)
+               memcpy(&flash->command[1], buf, len);
 
-       return 0;
+       return spi_write(spi, flash->command, len + 1);
 }
 
-/****************************************************************************/
-
-/*
- * MTD implementation
- */
-
-/*
- * Erase an address range on the flash chip.  The address range may extend
- * one or more erase sectors.  Return an error is there is a problem erasing.
- */
-static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
+static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
 {
-       struct m25p *flash = mtd_to_m25p(mtd);
-       u32 addr,len;
-       uint32_t rem;
-
-       pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev),
-                       __func__, (long long)instr->addr,
-                       (long long)instr->len);
-
-       div_u64_rem(instr->len, mtd->erasesize, &rem);
-       if (rem)
-               return -EINVAL;
-
-       addr = instr->addr;
-       len = instr->len;
-
-       mutex_lock(&flash->lock);
-
-       /* whole-chip erase? */
-       if (len == flash->mtd.size) {
-               if (erase_chip(flash)) {
-                       instr->state = MTD_ERASE_FAILED;
-                       mutex_unlock(&flash->lock);
-                       return -EIO;
-               }
+       struct m25p *flash = nor->priv;
+       struct spi_device *spi = flash->spi;
+       struct spi_transfer t[2] = {};
+       struct spi_message m;
+       int cmd_sz = m25p_cmdsz(nor);
 
-       /* REVISIT in some cases we could speed up erasing large regions
-        * by using OPCODE_SE instead of OPCODE_BE_4K.  We may have set up
-        * to use "small sector erase", but that's not always optimal.
-        */
+       spi_message_init(&m);
 
-       /* "sector"-at-a-time erase */
-       } else {
-               while (len) {
-                       if (erase_sector(flash, addr)) {
-                               instr->state = MTD_ERASE_FAILED;
-                               mutex_unlock(&flash->lock);
-                               return -EIO;
-                       }
+       if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
+               cmd_sz = 1;
 
-                       addr += mtd->erasesize;
-                       len -= mtd->erasesize;
-               }
-       }
+       flash->command[0] = nor->program_opcode;
+       m25p_addr2cmd(nor, to, flash->command);
 
-       mutex_unlock(&flash->lock);
+       t[0].tx_buf = flash->command;
+       t[0].len = cmd_sz;
+       spi_message_add_tail(&t[0], &m);
 
-       instr->state = MTD_ERASE_DONE;
-       mtd_erase_callback(instr);
+       t[1].tx_buf = buf;
+       t[1].len = len;
+       spi_message_add_tail(&t[1], &m);
 
-       return 0;
-}
+       spi_sync(spi, &m);
 
-/*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int m25p80_dummy_cycles_read(struct m25p *flash)
-{
-       switch (flash->flash_read) {
-       case M25P80_FAST:
-       case M25P80_DUAL:
-       case M25P80_QUAD:
-               return 1;
-       case M25P80_NORMAL:
-               return 0;
-       default:
-               dev_err(&flash->spi->dev, "No valid read type supported\n");
-               return -1;
-       }
+       *retlen += m.actual_length - cmd_sz;
 }
 
-static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
+static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
 {
-       switch (flash->flash_read) {
-       case M25P80_DUAL:
+       switch (nor->flash_read) {
+       case SPI_NOR_DUAL:
                return 2;
-       case M25P80_QUAD:
+       case SPI_NOR_QUAD:
                return 4;
        default:
                return 0;
@@ -505,590 +118,72 @@ static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
 }
 
 /*
- * Read an address range from the flash chip.  The address range
+ * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
  */
-static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf)
+static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
 {
-       struct m25p *flash = mtd_to_m25p(mtd);
+       struct m25p *flash = nor->priv;
+       struct spi_device *spi = flash->spi;
        struct spi_transfer t[2];
        struct spi_message m;
-       uint8_t opcode;
-       int dummy;
+       int dummy = nor->read_dummy;
+       int ret;
 
-       pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
-                       __func__, (u32)from, len);
+       /* Wait till previous write/erase is done. */
+       ret = nor->wait_till_ready(nor);
+       if (ret)
+               return ret;
 
        spi_message_init(&m);
        memset(t, 0, (sizeof t));
 
-       dummy =  m25p80_dummy_cycles_read(flash);
-       if (dummy < 0) {
-               dev_err(&flash->spi->dev, "No valid read command supported\n");
-               return -EINVAL;
-       }
+       flash->command[0] = nor->read_opcode;
+       m25p_addr2cmd(nor, from, flash->command);
 
        t[0].tx_buf = flash->command;
-       t[0].len = m25p_cmdsz(flash) + dummy;
+       t[0].len = m25p_cmdsz(nor) + dummy;
        spi_message_add_tail(&t[0], &m);
 
        t[1].rx_buf = buf;
-       t[1].rx_nbits = m25p80_rx_nbits(flash);
+       t[1].rx_nbits = m25p80_rx_nbits(nor);
        t[1].len = len;
        spi_message_add_tail(&t[1], &m);
 
-       mutex_lock(&flash->lock);
-
-       /* Wait till previous write/erase is done. */
-       if (wait_till_ready(flash)) {
-               /* REVISIT status return?? */
-               mutex_unlock(&flash->lock);
-               return 1;
-       }
-
-       /* Set up the write data buffer. */
-       opcode = flash->read_opcode;
-       flash->command[0] = opcode;
-       m25p_addr2cmd(flash, from, flash->command);
-
-       spi_sync(flash->spi, &m);
-
-       *retlen = m.actual_length - m25p_cmdsz(flash) - dummy;
-
-       mutex_unlock(&flash->lock);
+       spi_sync(spi, &m);
 
+       *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
        return 0;
 }
 
-/*
- * Write an address range to the flash chip.  Data must be written in
- * FLASH_PAGESIZE chunks.  The address range may be any size provided
- * it is within the physical boundaries.
- */
-static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
-       size_t *retlen, const u_char *buf)
+static int m25p80_erase(struct spi_nor *nor, loff_t offset)
 {
-       struct m25p *flash = mtd_to_m25p(mtd);
-       u32 page_offset, page_size;
-       struct spi_transfer t[2];
-       struct spi_message m;
-
-       pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
-                       __func__, (u32)to, len);
-
-       spi_message_init(&m);
-       memset(t, 0, (sizeof t));
-
-       t[0].tx_buf = flash->command;
-       t[0].len = m25p_cmdsz(flash);
-       spi_message_add_tail(&t[0], &m);
-
-       t[1].tx_buf = buf;
-       spi_message_add_tail(&t[1], &m);
-
-       mutex_lock(&flash->lock);
-
-       /* Wait until finished previous write command. */
-       if (wait_till_ready(flash)) {
-               mutex_unlock(&flash->lock);
-               return 1;
-       }
-
-       write_enable(flash);
-
-       /* Set up the opcode in the write buffer. */
-       flash->command[0] = flash->program_opcode;
-       m25p_addr2cmd(flash, to, flash->command);
-
-       page_offset = to & (flash->page_size - 1);
-
-       /* do all the bytes fit onto one page? */
-       if (page_offset + len <= flash->page_size) {
-               t[1].len = len;
-
-               spi_sync(flash->spi, &m);
-
-               *retlen = m.actual_length - m25p_cmdsz(flash);
-       } else {
-               u32 i;
-
-               /* the size of data remaining on the first page */
-               page_size = flash->page_size - page_offset;
-
-               t[1].len = page_size;
-               spi_sync(flash->spi, &m);
-
-               *retlen = m.actual_length - m25p_cmdsz(flash);
-
-               /* write everything in flash->page_size chunks */
-               for (i = page_size; i < len; i += page_size) {
-                       page_size = len - i;
-                       if (page_size > flash->page_size)
-                               page_size = flash->page_size;
-
-                       /* write the next page to flash */
-                       m25p_addr2cmd(flash, to + i, flash->command);
-
-                       t[1].tx_buf = buf + i;
-                       t[1].len = page_size;
-
-                       wait_till_ready(flash);
-
-                       write_enable(flash);
-
-                       spi_sync(flash->spi, &m);
-
-                       *retlen += m.actual_length - m25p_cmdsz(flash);
-               }
-       }
-
-       mutex_unlock(&flash->lock);
-
-       return 0;
-}
-
-static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
-               size_t *retlen, const u_char *buf)
-{
-       struct m25p *flash = mtd_to_m25p(mtd);
-       struct spi_transfer t[2];
-       struct spi_message m;
-       size_t actual;
-       int cmd_sz, ret;
-
-       pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
-                       __func__, (u32)to, len);
-
-       spi_message_init(&m);
-       memset(t, 0, (sizeof t));
-
-       t[0].tx_buf = flash->command;
-       t[0].len = m25p_cmdsz(flash);
-       spi_message_add_tail(&t[0], &m);
-
-       t[1].tx_buf = buf;
-       spi_message_add_tail(&t[1], &m);
+       struct m25p *flash = nor->priv;
+       int ret;
 
-       mutex_lock(&flash->lock);
+       dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
+               flash->mtd.erasesize / 1024, (u32)offset);
 
        /* Wait until finished previous write command. */
-       ret = wait_till_ready(flash);
+       ret = nor->wait_till_ready(nor);
        if (ret)
-               goto time_out;
-
-       write_enable(flash);
-
-       actual = to % 2;
-       /* Start write from odd address. */
-       if (actual) {
-               flash->command[0] = OPCODE_BP;
-               m25p_addr2cmd(flash, to, flash->command);
-
-               /* write one byte. */
-               t[1].len = 1;
-               spi_sync(flash->spi, &m);
-               ret = wait_till_ready(flash);
-               if (ret)
-                       goto time_out;
-               *retlen += m.actual_length - m25p_cmdsz(flash);
-       }
-       to += actual;
-
-       flash->command[0] = OPCODE_AAI_WP;
-       m25p_addr2cmd(flash, to, flash->command);
-
-       /* Write out most of the data here. */
-       cmd_sz = m25p_cmdsz(flash);
-       for (; actual < len - 1; actual += 2) {
-               t[0].len = cmd_sz;
-               /* write two bytes. */
-               t[1].len = 2;
-               t[1].tx_buf = buf + actual;
+               return ret;
 
-               spi_sync(flash->spi, &m);
-               ret = wait_till_ready(flash);
-               if (ret)
-                       goto time_out;
-               *retlen += m.actual_length - cmd_sz;
-               cmd_sz = 1;
-               to += 2;
-       }
-       write_disable(flash);
-       ret = wait_till_ready(flash);
+       /* Send write enable, then erase commands. */
+       ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
        if (ret)
-               goto time_out;
-
-       /* Write out trailing byte if it exists. */
-       if (actual != len) {
-               write_enable(flash);
-               flash->command[0] = OPCODE_BP;
-               m25p_addr2cmd(flash, to, flash->command);
-               t[0].len = m25p_cmdsz(flash);
-               t[1].len = 1;
-               t[1].tx_buf = buf + actual;
-
-               spi_sync(flash->spi, &m);
-               ret = wait_till_ready(flash);
-               if (ret)
-                       goto time_out;
-               *retlen += m.actual_length - m25p_cmdsz(flash);
-               write_disable(flash);
-       }
-
-time_out:
-       mutex_unlock(&flash->lock);
-       return ret;
-}
-
-static int m25p80_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-       struct m25p *flash = mtd_to_m25p(mtd);
-       uint32_t offset = ofs;
-       uint8_t status_old, status_new;
-       int res = 0;
-
-       mutex_lock(&flash->lock);
-       /* Wait until finished previous command */
-       if (wait_till_ready(flash)) {
-               res = 1;
-               goto err;
-       }
-
-       status_old = read_sr(flash);
-
-       if (offset < flash->mtd.size-(flash->mtd.size/2))
-               status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
-       else if (offset < flash->mtd.size-(flash->mtd.size/4))
-               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
-       else if (offset < flash->mtd.size-(flash->mtd.size/8))
-               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
-       else if (offset < flash->mtd.size-(flash->mtd.size/16))
-               status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2;
-       else if (offset < flash->mtd.size-(flash->mtd.size/32))
-               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
-       else if (offset < flash->mtd.size-(flash->mtd.size/64))
-               status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1;
-       else
-               status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0;
-
-       /* Only modify protection if it will not unlock other areas */
-       if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) >
-                                       (status_old&(SR_BP2|SR_BP1|SR_BP0))) {
-               write_enable(flash);
-               if (write_sr(flash, status_new) < 0) {
-                       res = 1;
-                       goto err;
-               }
-       }
-
-err:   mutex_unlock(&flash->lock);
-       return res;
-}
-
-static int m25p80_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-       struct m25p *flash = mtd_to_m25p(mtd);
-       uint32_t offset = ofs;
-       uint8_t status_old, status_new;
-       int res = 0;
-
-       mutex_lock(&flash->lock);
-       /* Wait until finished previous command */
-       if (wait_till_ready(flash)) {
-               res = 1;
-               goto err;
-       }
-
-       status_old = read_sr(flash);
-
-       if (offset+len > flash->mtd.size-(flash->mtd.size/64))
-               status_new = status_old & ~(SR_BP2|SR_BP1|SR_BP0);
-       else if (offset+len > flash->mtd.size-(flash->mtd.size/32))
-               status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0;
-       else if (offset+len > flash->mtd.size-(flash->mtd.size/16))
-               status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1;
-       else if (offset+len > flash->mtd.size-(flash->mtd.size/8))
-               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
-       else if (offset+len > flash->mtd.size-(flash->mtd.size/4))
-               status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2;
-       else if (offset+len > flash->mtd.size-(flash->mtd.size/2))
-               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
-       else
-               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
-
-       /* Only modify protection if it will not lock other areas */
-       if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) <
-                                       (status_old&(SR_BP2|SR_BP1|SR_BP0))) {
-               write_enable(flash);
-               if (write_sr(flash, status_new) < 0) {
-                       res = 1;
-                       goto err;
-               }
-       }
-
-err:   mutex_unlock(&flash->lock);
-       return res;
-}
-
-/****************************************************************************/
-
-/*
- * SPI device driver setup and teardown
- */
-
-struct flash_info {
-       /* JEDEC id zero means "no ID" (most older chips); otherwise it has
-        * a high byte of zero plus three data bytes: the manufacturer id,
-        * then a two byte device id.
-        */
-       u32             jedec_id;
-       u16             ext_id;
-
-       /* The size listed here is what works with OPCODE_SE, which isn't
-        * necessarily called a "sector" by the vendor.
-        */
-       unsigned        sector_size;
-       u16             n_sectors;
-
-       u16             page_size;
-       u16             addr_width;
-
-       u16             flags;
-#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        M25P80_DUAL_READ        0x20    /* Flash supports Dual Read */
-#define        M25P80_QUAD_READ        0x40    /* Flash supports Quad Read */
-};
-
-#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
-       ((kernel_ulong_t)&(struct flash_info) {                         \
-               .jedec_id = (_jedec_id),                                \
-               .ext_id = (_ext_id),                                    \
-               .sector_size = (_sector_size),                          \
-               .n_sectors = (_n_sectors),                              \
-               .page_size = 256,                                       \
-               .flags = (_flags),                                      \
-       })
-
-#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 = (_flags),                                      \
-       })
-
-/* NOTE: double check command sets and memory organization when you add
- * more flash chips.  This current list focusses on newer chips, which
- * have been converging on command sets which including JEDEC ID.
- */
-static const struct spi_device_id m25p_ids[] = {
-       /* Atmel -- some are (confusingly) marketed as "DataFlash" */
-       { "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
-       { "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
-
-       { "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
-       { "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
-       { "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
-
-       { "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) },
-       { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
-       { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
-       { "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
-
-       { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
-
-       /* EON -- en25xxx */
-       { "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
-       { "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
-       { "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
-       { "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
-       { "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
-       { "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
-
-       /* ESMT */
-       { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
-
-       /* Everspin */
-       { "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) },
-       { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
-
-       /* Intel/Numonyx -- xxxs33b */
-       { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
-       { "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
-       { "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
-
-       /* Macronix */
-       { "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-       { "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
-       { "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
-       { "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
-       { "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
-       { "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
-       { "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
-       { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
-       { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
-       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
-       { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
-       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) },
-       { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, M25P80_QUAD_READ) },
-
-       /* Micron */
-       { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 0) },
-       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, 0) },
-       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 0) },
-       { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K) },
-       { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, 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).
-        */
-       { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, 0) },
-       { "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
-       { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
-       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, M25P80_DUAL_READ | M25P80_QUAD_READ) },
-       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_DUAL_READ | M25P80_QUAD_READ) },
-       { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
-       { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
-       { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
-       { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
-       { "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
-       { "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
-       { "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
-       { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
-       { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
-       { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
-       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
-       { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
-       { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
-
-       /* SST -- large erase sizes are "overlays", "sectors" are 4K */
-       { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-       { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
-       { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
-       { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
-       { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
-       { "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
-       { "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
-       { "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
-       { "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-
-       /* ST Microelectronics -- newer production may have feature updates */
-       { "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
-       { "m25p10",  INFO(0x202011,  0,  32 * 1024,   4, 0) },
-       { "m25p20",  INFO(0x202012,  0,  64 * 1024,   4, 0) },
-       { "m25p40",  INFO(0x202013,  0,  64 * 1024,   8, 0) },
-       { "m25p80",  INFO(0x202014,  0,  64 * 1024,  16, 0) },
-       { "m25p16",  INFO(0x202015,  0,  64 * 1024,  32, 0) },
-       { "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 0) },
-       { "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
-       { "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
-       { "n25q032", INFO(0x20ba16,  0,  64 * 1024,  64, 0) },
-
-       { "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
-       { "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
-       { "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4, 0) },
-       { "m25p40-nonjedec",  INFO(0, 0,  64 * 1024,   8, 0) },
-       { "m25p80-nonjedec",  INFO(0, 0,  64 * 1024,  16, 0) },
-       { "m25p16-nonjedec",  INFO(0, 0,  64 * 1024,  32, 0) },
-       { "m25p32-nonjedec",  INFO(0, 0,  64 * 1024,  64, 0) },
-       { "m25p64-nonjedec",  INFO(0, 0,  64 * 1024, 128, 0) },
-       { "m25p128-nonjedec", INFO(0, 0, 256 * 1024,  64, 0) },
-
-       { "m45pe10", INFO(0x204011,  0, 64 * 1024,    2, 0) },
-       { "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 0) },
-       { "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 0) },
-
-       { "m25pe20", INFO(0x208012,  0, 64 * 1024,  4,       0) },
-       { "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
-       { "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
-
-       { "m25px16",    INFO(0x207115,  0, 64 * 1024, 32, SECT_4K) },
-       { "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, SECT_4K) },
-       { "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, SECT_4K) },
-       { "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, SECT_4K) },
-       { "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
-
-       /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
-       { "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
-       { "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
-       { "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
-       { "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
-       { "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
-       { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
-       { "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
-       { "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, 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);
-
-static const struct spi_device_id *jedec_probe(struct spi_device *spi)
-{
-       int                     tmp;
-       u8                      code = OPCODE_RDID;
-       u8                      id[5];
-       u32                     jedec;
-       u16                     ext_jedec;
-       struct flash_info       *info;
+               return ret;
 
-       /* JEDEC also defines an optional "extended device information"
-        * string for after vendor-specific data, after the three bytes
-        * we use here.  Supporting some chips might require using it.
-        */
-       tmp = spi_write_then_read(spi, &code, 1, id, 5);
-       if (tmp < 0) {
-               pr_debug("%s: error %d reading JEDEC ID\n",
-                               dev_name(&spi->dev), tmp);
-               return ERR_PTR(tmp);
-       }
-       jedec = id[0];
-       jedec = jedec << 8;
-       jedec |= id[1];
-       jedec = jedec << 8;
-       jedec |= id[2];
+       /* Set up command buffer. */
+       flash->command[0] = nor->erase_opcode;
+       m25p_addr2cmd(nor, offset, flash->command);
 
-       ext_jedec = id[3] << 8 | id[4];
+       spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
 
-       for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) {
-               info = (void *)m25p_ids[tmp].driver_data;
-               if (info->jedec_id == jedec) {
-                       if (info->ext_id == 0 || info->ext_id == ext_jedec)
-                               return &m25p_ids[tmp];
-               }
-       }
-       dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
-       return ERR_PTR(-ENODEV);
+       return 0;
 }
 
-
 /*
  * board specific setup should have ensured the SPI clock used here
  * matches what the READ command supports, at least until this driver
@@ -1096,231 +191,43 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
  */
 static int m25p_probe(struct spi_device *spi)
 {
-       const struct spi_device_id      *id = spi_get_device_id(spi);
-       struct flash_platform_data      *data;
-       struct m25p                     *flash;
-       struct flash_info               *info;
-       unsigned                        i;
        struct mtd_part_parser_data     ppdata;
-       struct device_node *np = spi->dev.of_node;
+       struct flash_platform_data      *data;
+       struct m25p *flash;
+       struct spi_nor *nor;
+       enum read_mode mode = SPI_NOR_NORMAL;
        int ret;
 
-       /* Platform data helps sort out which chip type we have, as
-        * well as how this board partitions it.  If we don't have
-        * 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 = dev_get_platdata(&spi->dev);
-       if (data && data->type) {
-               const struct spi_device_id *plat_id;
-
-               for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) {
-                       plat_id = &m25p_ids[i];
-                       if (strcmp(data->type, plat_id->name))
-                               continue;
-                       break;
-               }
-
-               if (i < ARRAY_SIZE(m25p_ids) - 1)
-                       id = plat_id;
-               else
-                       dev_warn(&spi->dev, "unrecognized id %s\n", data->type);
-       }
-
-       info = (void *)id->driver_data;
-
-       if (info->jedec_id) {
-               const struct spi_device_id *jid;
-
-               jid = jedec_probe(spi);
-               if (IS_ERR(jid)) {
-                       return PTR_ERR(jid);
-               } else if (jid != id) {
-                       /*
-                        * JEDEC knows better, so overwrite platform ID. We
-                        * can't trust partitions any longer, but we'll let
-                        * mtd apply them anyway, since some partitions may be
-                        * marked read-only, and we don't want to lose that
-                        * information, even if it's not 100% accurate.
-                        */
-                       dev_warn(&spi->dev, "found %s, expected %s\n",
-                                jid->name, id->name);
-                       id = jid;
-                       info = (void *)jid->driver_data;
-               }
-       }
-
        flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
        if (!flash)
                return -ENOMEM;
 
-       flash->command = devm_kzalloc(&spi->dev, MAX_CMD_SIZE, GFP_KERNEL);
-       if (!flash->command)
-               return -ENOMEM;
-
-       flash->spi = spi;
-       mutex_init(&flash->lock);
-       spi_set_drvdata(spi, flash);
-
-       /*
-        * Atmel, SST and Intel/Numonyx serial flash tend to power
-        * up with the software protection bits set
-        */
+       nor = &flash->spi_nor;
 
-       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL ||
-           JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL ||
-           JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) {
-               write_enable(flash);
-               write_sr(flash, 0);
-       }
-
-       if (data && data->name)
-               flash->mtd.name = data->name;
-       else
-               flash->mtd.name = dev_name(&spi->dev);
-
-       flash->mtd.type = MTD_NORFLASH;
-       flash->mtd.writesize = 1;
-       flash->mtd.flags = MTD_CAP_NORFLASH;
-       flash->mtd.size = info->sector_size * info->n_sectors;
-       flash->mtd._erase = m25p80_erase;
-       flash->mtd._read = m25p80_read;
-
-       /* flash protection support for STmicro chips */
-       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
-               flash->mtd._lock = m25p80_lock;
-               flash->mtd._unlock = m25p80_unlock;
-       }
+       /* install the hooks */
+       nor->read = m25p80_read;
+       nor->write = m25p80_write;
+       nor->erase = m25p80_erase;
+       nor->write_reg = m25p80_write_reg;
+       nor->read_reg = m25p80_read_reg;
 
-       /* sst flash chips use AAI word program */
-       if (info->flags & SST_WRITE)
-               flash->mtd._write = sst_write;
-       else
-               flash->mtd._write = m25p80_write;
+       nor->dev = &spi->dev;
+       nor->mtd = &flash->mtd;
+       nor->priv = flash;
 
-       /* prefer "small sector" erase if possible */
-       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;
-       }
+       spi_set_drvdata(spi, flash);
+       flash->mtd.priv = nor;
+       flash->spi = spi;
 
-       if (info->flags & M25P_NO_ERASE)
-               flash->mtd.flags |= MTD_NO_ERASE;
+       if (spi->mode & SPI_RX_QUAD)
+               mode = SPI_NOR_QUAD;
+       ret = spi_nor_scan(nor, spi_get_device_id(spi), mode);
+       if (ret)
+               return ret;
 
+       data = dev_get_platdata(&spi->dev);
        ppdata.of_node = spi->dev.of_node;
-       flash->mtd.dev.parent = &spi->dev;
-       flash->page_size = info->page_size;
-       flash->mtd.writebufsize = flash->page_size;
-
-       if (np) {
-               /* If we were instantiated by DT, use it */
-               if (of_property_read_bool(np, "m25p,fast-read"))
-                       flash->flash_read = M25P80_FAST;
-               else
-                       flash->flash_read = M25P80_NORMAL;
-       } else {
-               /* If we weren't instantiated by DT, default to fast-read */
-               flash->flash_read = M25P80_FAST;
-       }
-
-       /* Some devices cannot do fast-read, no matter what DT tells us */
-       if (info->flags & M25P_NO_FR)
-               flash->flash_read = M25P80_NORMAL;
-
-       /* Quad/Dual-read mode takes precedence over fast/normal */
-       if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) {
-               ret = set_quad_mode(flash, info->jedec_id);
-               if (ret) {
-                       dev_err(&flash->spi->dev, "quad mode not supported\n");
-                       return ret;
-               }
-               flash->flash_read = M25P80_QUAD;
-       } else if (spi->mode & SPI_RX_DUAL && info->flags & M25P80_DUAL_READ) {
-               flash->flash_read = M25P80_DUAL;
-       }
 
-       /* Default commands */
-       switch (flash->flash_read) {
-       case M25P80_QUAD:
-               flash->read_opcode = OPCODE_QUAD_READ;
-               break;
-       case M25P80_DUAL:
-               flash->read_opcode = OPCODE_DUAL_READ;
-               break;
-       case M25P80_FAST:
-               flash->read_opcode = OPCODE_FAST_READ;
-               break;
-       case M25P80_NORMAL:
-               flash->read_opcode = OPCODE_NORM_READ;
-               break;
-       default:
-               dev_err(&flash->spi->dev, "No Read opcode defined\n");
-               return -EINVAL;
-       }
-
-       flash->program_opcode = OPCODE_PP;
-
-       if (info->addr_width)
-               flash->addr_width = info->addr_width;
-       else if (flash->mtd.size > 0x1000000) {
-               /* enable 4-byte addressing if the device exceeds 16MiB */
-               flash->addr_width = 4;
-               if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
-                       /* Dedicated 4-byte command set */
-                       switch (flash->flash_read) {
-                       case M25P80_QUAD:
-                               flash->read_opcode = OPCODE_QUAD_READ_4B;
-                               break;
-                       case M25P80_DUAL:
-                               flash->read_opcode = OPCODE_DUAL_READ_4B;
-                               break;
-                       case M25P80_FAST:
-                               flash->read_opcode = OPCODE_FAST_READ_4B;
-                               break;
-                       case M25P80_NORMAL:
-                               flash->read_opcode = OPCODE_NORM_READ_4B;
-                               break;
-                       }
-                       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
-                       set_4byte(flash, info->jedec_id, 1);
-       } else {
-               flash->addr_width = 3;
-       }
-
-       dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
-                       (long long)flash->mtd.size >> 10);
-
-       pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) "
-                       ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
-               flash->mtd.name,
-               (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
-               flash->mtd.erasesize, flash->mtd.erasesize / 1024,
-               flash->mtd.numeraseregions);
-
-       if (flash->mtd.numeraseregions)
-               for (i = 0; i < flash->mtd.numeraseregions; i++)
-                       pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, "
-                               ".erasesize = 0x%.8x (%uKiB), "
-                               ".numblocks = %d }\n",
-                               i, (long long)flash->mtd.eraseregions[i].offset,
-                               flash->mtd.eraseregions[i].erasesize,
-                               flash->mtd.eraseregions[i].erasesize / 1024,
-                               flash->mtd.eraseregions[i].numblocks);
-
-
-       /* partitions should match sector boundaries; and it may be good to
-        * use readonly partitions for writeprotected sectors (BP2..BP0).
-        */
        return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
                        data ? data->parts : NULL,
                        data ? data->nr_parts : 0);
@@ -1341,7 +248,7 @@ static struct spi_driver m25p80_driver = {
                .name   = "m25p80",
                .owner  = THIS_MODULE,
        },
-       .id_table       = m25p_ids,
+       .id_table       = spi_nor_ids,
        .probe  = m25p_probe,
        .remove = m25p_remove,
 
index 4f0c2c7c898ea7b208faa1c3eeae24b90e8db271..f59a125295d01ddfafec5c596b846e9ea49dd437 100644 (file)
 #define _MTD_SERIAL_FLASH_CMDS_H
 
 /* Generic Flash Commands/OPCODEs */
-#define FLASH_CMD_WREN         0x06
-#define FLASH_CMD_WRDI         0x04
-#define FLASH_CMD_RDID         0x9f
-#define FLASH_CMD_RDSR         0x05
-#define FLASH_CMD_RDSR2                0x35
-#define FLASH_CMD_WRSR         0x01
-#define FLASH_CMD_SE_4K                0x20
-#define FLASH_CMD_SE_32K       0x52
-#define FLASH_CMD_SE           0xd8
-#define FLASH_CMD_CHIPERASE    0xc7
-#define FLASH_CMD_WRVCR                0x81
-#define FLASH_CMD_RDVCR                0x85
+#define SPINOR_OP_RDSR2                0x35
+#define SPINOR_OP_WRVCR                0x81
+#define SPINOR_OP_RDVCR                0x85
 
 /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
-#define FLASH_CMD_READ         0x03    /* READ */
-#define FLASH_CMD_READ_FAST    0x0b    /* FAST READ */
-#define FLASH_CMD_READ_1_1_2   0x3b    /* DUAL OUTPUT READ */
-#define FLASH_CMD_READ_1_2_2   0xbb    /* DUAL I/O READ */
-#define FLASH_CMD_READ_1_1_4   0x6b    /* QUAD OUTPUT READ */
-#define FLASH_CMD_READ_1_4_4   0xeb    /* QUAD I/O READ */
+#define SPINOR_OP_READ_1_2_2   0xbb    /* DUAL I/O READ */
+#define SPINOR_OP_READ_1_4_4   0xeb    /* QUAD I/O READ */
 
-#define FLASH_CMD_WRITE                0x02    /* PAGE PROGRAM */
-#define FLASH_CMD_WRITE_1_1_2  0xa2    /* DUAL INPUT PROGRAM */
-#define FLASH_CMD_WRITE_1_2_2  0xd2    /* DUAL INPUT EXT PROGRAM */
-#define FLASH_CMD_WRITE_1_1_4  0x32    /* QUAD INPUT PROGRAM */
-#define FLASH_CMD_WRITE_1_4_4  0x12    /* QUAD INPUT EXT PROGRAM */
-
-#define FLASH_CMD_EN4B_ADDR    0xb7    /* Enter 4-byte address mode */
-#define FLASH_CMD_EX4B_ADDR    0xe9    /* Exit 4-byte address mode */
+#define SPINOR_OP_WRITE                0x02    /* PAGE PROGRAM */
+#define SPINOR_OP_WRITE_1_1_2  0xa2    /* DUAL INPUT PROGRAM */
+#define SPINOR_OP_WRITE_1_2_2  0xd2    /* DUAL INPUT EXT PROGRAM */
+#define SPINOR_OP_WRITE_1_1_4  0x32    /* QUAD INPUT PROGRAM */
+#define SPINOR_OP_WRITE_1_4_4  0x12    /* QUAD INPUT EXT PROGRAM */
 
 /* READ commands with 32-bit addressing */
-#define FLASH_CMD_READ4                0x13
-#define FLASH_CMD_READ4_FAST   0x0c
-#define FLASH_CMD_READ4_1_1_2  0x3c
-#define FLASH_CMD_READ4_1_2_2  0xbc
-#define FLASH_CMD_READ4_1_1_4  0x6c
-#define FLASH_CMD_READ4_1_4_4  0xec
+#define SPINOR_OP_READ4_1_2_2  0xbc
+#define SPINOR_OP_READ4_1_4_4  0xec
 
 /* Configuration flags */
 #define FLASH_FLAG_SINGLE      0x000000ff
index 1957d7c8e1853c4588057c1512e3d3ceb0c80e74..f97fe144077d77b6cc6bf91da47ce043afc7fb8a 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 
 #define STFSM_MAX_WAIT_SEQ_MS  1000     /* FSM execution time */
 
-/* Flash Commands */
-#define FLASH_CMD_WREN         0x06
-#define FLASH_CMD_WRDI         0x04
-#define FLASH_CMD_RDID         0x9f
-#define FLASH_CMD_RDSR         0x05
-#define FLASH_CMD_RDSR2                0x35
-#define FLASH_CMD_WRSR         0x01
-#define FLASH_CMD_SE_4K                0x20
-#define FLASH_CMD_SE_32K       0x52
-#define FLASH_CMD_SE           0xd8
-#define FLASH_CMD_CHIPERASE    0xc7
-#define FLASH_CMD_WRVCR                0x81
-#define FLASH_CMD_RDVCR                0x85
-
-#define FLASH_CMD_READ         0x03    /* READ */
-#define FLASH_CMD_READ_FAST    0x0b    /* FAST READ */
-#define FLASH_CMD_READ_1_1_2   0x3b    /* DUAL OUTPUT READ */
-#define FLASH_CMD_READ_1_2_2   0xbb    /* DUAL I/O READ */
-#define FLASH_CMD_READ_1_1_4   0x6b    /* QUAD OUTPUT READ */
-#define FLASH_CMD_READ_1_4_4   0xeb    /* QUAD I/O READ */
-
-#define FLASH_CMD_WRITE                0x02    /* PAGE PROGRAM */
-#define FLASH_CMD_WRITE_1_1_2  0xa2    /* DUAL INPUT PROGRAM */
-#define FLASH_CMD_WRITE_1_2_2  0xd2    /* DUAL INPUT EXT PROGRAM */
-#define FLASH_CMD_WRITE_1_1_4  0x32    /* QUAD INPUT PROGRAM */
-#define FLASH_CMD_WRITE_1_4_4  0x12    /* QUAD INPUT EXT PROGRAM */
-
-#define FLASH_CMD_EN4B_ADDR    0xb7    /* Enter 4-byte address mode */
-#define FLASH_CMD_EX4B_ADDR    0xe9    /* Exit 4-byte address mode */
-
-/* READ commands with 32-bit addressing (N25Q256 and S25FLxxxS) */
-#define FLASH_CMD_READ4                0x13
-#define FLASH_CMD_READ4_FAST   0x0c
-#define FLASH_CMD_READ4_1_1_2  0x3c
-#define FLASH_CMD_READ4_1_2_2  0xbc
-#define FLASH_CMD_READ4_1_1_4  0x6c
-#define FLASH_CMD_READ4_1_4_4  0xec
-
 /* S25FLxxxS commands */
 #define S25FL_CMD_WRITE4_1_1_4 0x34
 #define S25FL_CMD_SE4          0xdc
 #define S25FL_CMD_DYBWR                0xe1
 #define S25FL_CMD_DYBRD                0xe0
 #define S25FL_CMD_WRITE4       0x12    /* Note, opcode clashes with
-                                       * 'FLASH_CMD_WRITE_1_4_4'
+                                       * 'SPINOR_OP_WRITE_1_4_4'
                                        * as found on N25Qxxx devices! */
 
 /* Status register */
 #define S25FL_STATUS_E_ERR     0x20
 #define S25FL_STATUS_P_ERR     0x40
 
+#define N25Q_CMD_WRVCR         0x81
+#define N25Q_CMD_RDVCR         0x85
+#define N25Q_CMD_RDVECR        0x65
+#define N25Q_CMD_RDNVCR        0xb5
+#define N25Q_CMD_WRNVCR        0xb1
+
 #define FLASH_PAGESIZE         256                     /* In Bytes    */
 #define FLASH_PAGESIZE_32      (FLASH_PAGESIZE / 4)    /* In uint32_t */
 #define FLASH_MAX_BUSY_WAIT    (300 * HZ)      /* Maximum 'CHIPERASE' time */
  */
 #define CFG_READ_TOGGLE_32BIT_ADDR     0x00000001
 #define CFG_WRITE_TOGGLE_32BIT_ADDR    0x00000002
-#define CFG_WRITE_EX_32BIT_ADDR_DELAY  0x00000004
 #define CFG_ERASESEC_TOGGLE_32BIT_ADDR 0x00000008
 #define CFG_S25FL_CHECK_ERROR_FLAGS    0x00000010
 
@@ -329,7 +297,7 @@ struct flash_info {
        u32             jedec_id;
        u16             ext_id;
        /*
-        * The size listed here is what works with FLASH_CMD_SE, which isn't
+        * The size listed here is what works with SPINOR_OP_SE, which isn't
         * necessarily called a "sector" by the vendor.
         */
        unsigned        sector_size;
@@ -369,17 +337,26 @@ static struct flash_info flash_types[] = {
        { "m25px32", 0x207116, 0,  64 * 1024,  64, M25PX_FLAG, 75, NULL },
        { "m25px64", 0x207117, 0,  64 * 1024, 128, M25PX_FLAG, 75, NULL },
 
+       /* Macronix MX25xxx
+        *     - Support for 'FLASH_FLAG_WRITE_1_4_4' is omitted for devices
+        *       where operating frequency must be reduced.
+        */
 #define MX25_FLAG (FLASH_FLAG_READ_WRITE       |       \
                   FLASH_FLAG_READ_FAST         |       \
                   FLASH_FLAG_READ_1_1_2        |       \
                   FLASH_FLAG_READ_1_2_2        |       \
                   FLASH_FLAG_READ_1_1_4        |       \
-                  FLASH_FLAG_READ_1_4_4        |       \
                   FLASH_FLAG_SE_4K             |       \
                   FLASH_FLAG_SE_32K)
+       { "mx25l3255e",  0xc29e16, 0, 64 * 1024, 64,
+         (MX25_FLAG | FLASH_FLAG_WRITE_1_4_4), 86,
+         stfsm_mx25_config},
        { "mx25l25635e", 0xc22019, 0, 64*1024, 512,
          (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70,
          stfsm_mx25_config },
+       { "mx25l25655e", 0xc22619, 0, 64*1024, 512,
+         (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70,
+         stfsm_mx25_config},
 
 #define N25Q_FLAG (FLASH_FLAG_READ_WRITE       |       \
                   FLASH_FLAG_READ_FAST         |       \
@@ -407,6 +384,8 @@ static struct flash_info flash_types[] = {
                        FLASH_FLAG_READ_1_4_4   |       \
                        FLASH_FLAG_WRITE_1_1_4  |       \
                        FLASH_FLAG_READ_FAST)
+       { "s25fl032p",  0x010215, 0x4d00,  64 * 1024,  64, S25FLXXXP_FLAG, 80,
+         stfsm_s25fl_config},
        { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024,  64, S25FLXXXP_FLAG, 80,
          stfsm_s25fl_config },
        { "s25fl129p1", 0x012018, 0x4d01,  64 * 1024, 256, S25FLXXXP_FLAG, 80,
@@ -473,22 +452,22 @@ static struct flash_info flash_types[] = {
 
 /* Default READ configurations, in order of preference */
 static struct seq_rw_config default_read_configs[] = {
-       {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ_1_4_4,   0, 4, 4, 0x00, 2, 4},
-       {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ_1_1_4,   0, 1, 4, 0x00, 4, 0},
-       {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ_1_2_2,   0, 2, 2, 0x00, 4, 0},
-       {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ_1_1_2,   0, 1, 2, 0x00, 0, 8},
-       {FLASH_FLAG_READ_FAST,  FLASH_CMD_READ_FAST,    0, 1, 1, 0x00, 0, 8},
-       {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ,         0, 1, 1, 0x00, 0, 0},
+       {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4,   0, 4, 4, 0x00, 2, 4},
+       {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4,   0, 1, 4, 0x00, 4, 0},
+       {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2,   0, 2, 2, 0x00, 4, 0},
+       {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2,   0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,  SPINOR_OP_READ_FAST,    0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ,         0, 1, 1, 0x00, 0, 0},
        {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
 };
 
 /* Default WRITE configurations */
 static struct seq_rw_config default_write_configs[] = {
-       {FLASH_FLAG_WRITE_1_4_4, FLASH_CMD_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0},
-       {FLASH_FLAG_WRITE_1_1_4, FLASH_CMD_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0},
-       {FLASH_FLAG_WRITE_1_2_2, FLASH_CMD_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0},
-       {FLASH_FLAG_WRITE_1_1_2, FLASH_CMD_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0},
-       {FLASH_FLAG_READ_WRITE,  FLASH_CMD_WRITE,       1, 1, 1, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_4_4, SPINOR_OP_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_1_4, SPINOR_OP_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_2_2, SPINOR_OP_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_1_2, SPINOR_OP_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0},
+       {FLASH_FLAG_READ_WRITE,  SPINOR_OP_WRITE,       1, 1, 1, 0x00, 0, 0},
        {0x00,                   0,                     0, 0, 0, 0x00, 0, 0},
 };
 
@@ -511,12 +490,12 @@ static struct seq_rw_config default_write_configs[] = {
  * cycles.
  */
 static struct seq_rw_config n25q_read3_configs[] = {
-       {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ_1_4_4,   0, 4, 4, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ_1_1_4,   0, 1, 4, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ_1_2_2,   0, 2, 2, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ_1_1_2,   0, 1, 2, 0x00, 0, 8},
-       {FLASH_FLAG_READ_FAST,  FLASH_CMD_READ_FAST,    0, 1, 1, 0x00, 0, 8},
-       {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ,         0, 1, 1, 0x00, 0, 0},
+       {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4,   0, 4, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4,   0, 1, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2,   0, 2, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2,   0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,  SPINOR_OP_READ_FAST,    0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ,         0, 1, 1, 0x00, 0, 0},
        {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
 };
 
@@ -526,12 +505,12 @@ static struct seq_rw_config n25q_read3_configs[] = {
  *     - 'FAST' variants configured for 8 dummy cycles (see note above.)
  */
 static struct seq_rw_config n25q_read4_configs[] = {
-       {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ4_1_4_4,  0, 4, 4, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ4_1_2_2,  0, 2, 2, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
-       {FLASH_FLAG_READ_FAST,  FLASH_CMD_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
-       {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ4,        0, 1, 1, 0x00, 0, 0},
+       {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,  SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
        {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
 };
 
@@ -544,7 +523,7 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
 {
        seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
                           SEQ_OPC_CYCLES(8) |
-                          SEQ_OPC_OPCODE(FLASH_CMD_EN4B_ADDR) |
+                          SEQ_OPC_OPCODE(SPINOR_OP_EN4B) |
                           SEQ_OPC_CSDEASSERT);
 
        seq->seq[0] = STFSM_INST_CMD1;
@@ -572,12 +551,12 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
  * entering a state that is incompatible with the SPIBoot Controller.
  */
 static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
-       {FLASH_FLAG_READ_1_4_4,  FLASH_CMD_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
-       {FLASH_FLAG_READ_1_1_4,  FLASH_CMD_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
-       {FLASH_FLAG_READ_1_2_2,  FLASH_CMD_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
-       {FLASH_FLAG_READ_1_1_2,  FLASH_CMD_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
-       {FLASH_FLAG_READ_FAST,   FLASH_CMD_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
-       {FLASH_FLAG_READ_WRITE,  FLASH_CMD_READ4,        0, 1, 1, 0x00, 0, 0},
+       {FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
+       {FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
+       {FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
        {0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
 };
 
@@ -590,13 +569,13 @@ static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
 /*
  * [W25Qxxx] Configuration
  */
-#define W25Q_STATUS_QE                 (0x1 << 9)
+#define W25Q_STATUS_QE                 (0x1 << 1)
 
 static struct stfsm_seq stfsm_seq_read_jedec = {
        .data_size = TRANSFER_SIZE(8),
        .seq_opc[0] = (SEQ_OPC_PADS_1 |
                       SEQ_OPC_CYCLES(8) |
-                      SEQ_OPC_OPCODE(FLASH_CMD_RDID)),
+                      SEQ_OPC_OPCODE(SPINOR_OP_RDID)),
        .seq = {
                STFSM_INST_CMD1,
                STFSM_INST_DATA_READ,
@@ -612,7 +591,7 @@ static struct stfsm_seq stfsm_seq_read_status_fifo = {
        .data_size = TRANSFER_SIZE(4),
        .seq_opc[0] = (SEQ_OPC_PADS_1 |
                       SEQ_OPC_CYCLES(8) |
-                      SEQ_OPC_OPCODE(FLASH_CMD_RDSR)),
+                      SEQ_OPC_OPCODE(SPINOR_OP_RDSR)),
        .seq = {
                STFSM_INST_CMD1,
                STFSM_INST_DATA_READ,
@@ -628,10 +607,10 @@ static struct stfsm_seq stfsm_seq_erase_sector = {
        /* 'addr_cfg' configured during initialisation */
        .seq_opc = {
                (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+                SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT),
 
                (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                SEQ_OPC_OPCODE(FLASH_CMD_SE)),
+                SEQ_OPC_OPCODE(SPINOR_OP_SE)),
        },
        .seq = {
                STFSM_INST_CMD1,
@@ -649,10 +628,10 @@ static struct stfsm_seq stfsm_seq_erase_sector = {
 static struct stfsm_seq stfsm_seq_erase_chip = {
        .seq_opc = {
                (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+                SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT),
 
                (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                SEQ_OPC_OPCODE(FLASH_CMD_CHIPERASE) | SEQ_OPC_CSDEASSERT),
+                SEQ_OPC_OPCODE(SPINOR_OP_CHIP_ERASE) | SEQ_OPC_CSDEASSERT),
        },
        .seq = {
                STFSM_INST_CMD1,
@@ -669,26 +648,9 @@ static struct stfsm_seq stfsm_seq_erase_chip = {
 
 static struct stfsm_seq stfsm_seq_write_status = {
        .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                      SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
-       .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                      SEQ_OPC_OPCODE(FLASH_CMD_WRSR)),
-       .seq = {
-               STFSM_INST_CMD1,
-               STFSM_INST_CMD2,
-               STFSM_INST_STA_WR1,
-               STFSM_INST_STOP,
-       },
-       .seq_cfg = (SEQ_CFG_PADS_1 |
-                   SEQ_CFG_READNOTWRITE |
-                   SEQ_CFG_CSDEASSERT |
-                   SEQ_CFG_STARTSEQ),
-};
-
-static struct stfsm_seq stfsm_seq_wrvcr = {
-       .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                      SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+                      SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT),
        .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                      SEQ_OPC_OPCODE(FLASH_CMD_WRVCR)),
+                      SEQ_OPC_OPCODE(SPINOR_OP_WRSR)),
        .seq = {
                STFSM_INST_CMD1,
                STFSM_INST_CMD2,
@@ -704,9 +666,9 @@ static struct stfsm_seq stfsm_seq_wrvcr = {
 static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq)
 {
        seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                          SEQ_OPC_OPCODE(FLASH_CMD_EN4B_ADDR));
+                          SEQ_OPC_OPCODE(SPINOR_OP_EN4B));
        seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                          SEQ_OPC_OPCODE(FLASH_CMD_WREN) |
+                          SEQ_OPC_OPCODE(SPINOR_OP_WREN) |
                           SEQ_OPC_CSDEASSERT);
 
        seq->seq[0] = STFSM_INST_CMD2;
@@ -793,7 +755,7 @@ static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size)
 
        dev_dbg(fsm->dev, "Reading %d bytes from FIFO\n", size);
 
-       BUG_ON((((uint32_t)buf) & 0x3) || (size & 0x3));
+       BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3));
 
        while (remaining) {
                for (;;) {
@@ -817,7 +779,7 @@ static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf,
 
        dev_dbg(fsm->dev, "writing %d bytes to FIFO\n", size);
 
-       BUG_ON((((uint32_t)buf) & 0x3) || (size & 0x3));
+       BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3));
 
        writesl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words);
 
@@ -827,7 +789,7 @@ static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf,
 static int stfsm_enter_32bit_addr(struct stfsm *fsm, int enter)
 {
        struct stfsm_seq *seq = &fsm->stfsm_seq_en_32bit_addr;
-       uint32_t cmd = enter ? FLASH_CMD_EN4B_ADDR : FLASH_CMD_EX4B_ADDR;
+       uint32_t cmd = enter ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
 
        seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
                           SEQ_OPC_CYCLES(8) |
@@ -851,7 +813,7 @@ static uint8_t stfsm_wait_busy(struct stfsm *fsm)
        /* Use RDRS1 */
        seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
                           SEQ_OPC_CYCLES(8) |
-                          SEQ_OPC_OPCODE(FLASH_CMD_RDSR));
+                          SEQ_OPC_OPCODE(SPINOR_OP_RDSR));
 
        /* Load read_status sequence */
        stfsm_load_seq(fsm, seq);
@@ -889,60 +851,57 @@ static uint8_t stfsm_wait_busy(struct stfsm *fsm)
 }
 
 static int stfsm_read_status(struct stfsm *fsm, uint8_t cmd,
-                          uint8_t *status)
+                            uint8_t *data, int bytes)
 {
        struct stfsm_seq *seq = &stfsm_seq_read_status_fifo;
        uint32_t tmp;
+       uint8_t *t = (uint8_t *)&tmp;
+       int i;
 
-       dev_dbg(fsm->dev, "reading STA[%s]\n",
-               (cmd == FLASH_CMD_RDSR) ? "1" : "2");
+       dev_dbg(fsm->dev, "read 'status' register [0x%02x], %d byte(s)\n",
+               cmd, bytes);
 
-       seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
-                          SEQ_OPC_CYCLES(8) |
+       BUG_ON(bytes != 1 && bytes != 2);
+
+       seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
                           SEQ_OPC_OPCODE(cmd)),
 
        stfsm_load_seq(fsm, seq);
 
        stfsm_read_fifo(fsm, &tmp, 4);
 
-       *status = (uint8_t)(tmp >> 24);
+       for (i = 0; i < bytes; i++)
+               data[i] = t[i];
 
        stfsm_wait_seq(fsm);
 
        return 0;
 }
 
-static int stfsm_write_status(struct stfsm *fsm, uint16_t status,
-                              int sta_bytes)
+static int stfsm_write_status(struct stfsm *fsm, uint8_t cmd,
+                           uint16_t data, int bytes, int wait_busy)
 {
        struct stfsm_seq *seq = &stfsm_seq_write_status;
 
-       dev_dbg(fsm->dev, "writing STA[%s] 0x%04x\n",
-               (sta_bytes == 1) ? "1" : "1+2", status);
-
-       seq->status = (uint32_t)status | STA_PADS_1 | STA_CSDEASSERT;
-       seq->seq[2] = (sta_bytes == 1) ?
-               STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2;
-
-       stfsm_load_seq(fsm, seq);
-
-       stfsm_wait_seq(fsm);
+       dev_dbg(fsm->dev,
+               "write 'status' register [0x%02x], %d byte(s), 0x%04x\n"
+               " %s wait-busy\n", cmd, bytes, data, wait_busy ? "with" : "no");
 
-       return 0;
-};
+       BUG_ON(bytes != 1 && bytes != 2);
 
-static int stfsm_wrvcr(struct stfsm *fsm, uint8_t data)
-{
-       struct stfsm_seq *seq = &stfsm_seq_wrvcr;
-
-       dev_dbg(fsm->dev, "writing VCR 0x%02x\n", data);
+       seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(cmd));
 
-       seq->status = (STA_DATA_BYTE1(data) | STA_PADS_1 | STA_CSDEASSERT);
+       seq->status = (uint32_t)data | STA_PADS_1 | STA_CSDEASSERT;
+       seq->seq[2] = (bytes == 1) ? STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2;
 
        stfsm_load_seq(fsm, seq);
 
        stfsm_wait_seq(fsm);
 
+       if (wait_busy)
+               stfsm_wait_busy(fsm);
+
        return 0;
 }
 
@@ -1027,7 +986,7 @@ static void stfsm_prepare_rw_seq(struct stfsm *fsm,
        if (cfg->write)
                seq->seq_opc[i++] = (SEQ_OPC_PADS_1 |
                                     SEQ_OPC_CYCLES(8) |
-                                    SEQ_OPC_OPCODE(FLASH_CMD_WREN) |
+                                    SEQ_OPC_OPCODE(SPINOR_OP_WREN) |
                                     SEQ_OPC_CSDEASSERT);
 
        /* Address configuration (24 or 32-bit addresses) */
@@ -1149,31 +1108,36 @@ static int stfsm_mx25_config(struct stfsm *fsm)
                stfsm_mx25_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr);
 
                soc_reset = stfsm_can_handle_soc_reset(fsm);
-               if (soc_reset || !fsm->booted_from_spi) {
+               if (soc_reset || !fsm->booted_from_spi)
                        /* If we can handle SoC resets, we enable 32-bit address
                         * mode pervasively */
                        stfsm_enter_32bit_addr(fsm, 1);
 
-               } else {
+               else
                        /* Else, enable/disable 32-bit addressing before/after
                         * each operation */
                        fsm->configuration = (CFG_READ_TOGGLE_32BIT_ADDR |
                                              CFG_WRITE_TOGGLE_32BIT_ADDR |
                                              CFG_ERASESEC_TOGGLE_32BIT_ADDR);
-                       /* It seems a small delay is required after exiting
-                        * 32-bit mode following a write operation.  The issue
-                        * is under investigation.
-                        */
-                       fsm->configuration |= CFG_WRITE_EX_32BIT_ADDR_DELAY;
-               }
        }
 
-       /* For QUAD mode, set 'QE' STATUS bit */
+       /* Check status of 'QE' bit, update if required. */
+       stfsm_read_status(fsm, SPINOR_OP_RDSR, &sta, 1);
        data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
        if (data_pads == 4) {
-               stfsm_read_status(fsm, FLASH_CMD_RDSR, &sta);
-               sta |= MX25_STATUS_QE;
-               stfsm_write_status(fsm, sta, 1);
+               if (!(sta & MX25_STATUS_QE)) {
+                       /* Set 'QE' */
+                       sta |= MX25_STATUS_QE;
+
+                       stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1);
+               }
+       } else {
+               if (sta & MX25_STATUS_QE) {
+                       /* Clear 'QE' */
+                       sta &= ~MX25_STATUS_QE;
+
+                       stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1);
+               }
        }
 
        return 0;
@@ -1239,7 +1203,7 @@ static int stfsm_n25q_config(struct stfsm *fsm)
         */
        vcr = (N25Q_VCR_DUMMY_CYCLES(8) | N25Q_VCR_XIP_DISABLED |
               N25Q_VCR_WRAP_CONT);
-       stfsm_wrvcr(fsm, vcr);
+       stfsm_write_status(fsm, N25Q_CMD_WRVCR, vcr, 1, 0);
 
        return 0;
 }
@@ -1297,7 +1261,7 @@ static void stfsm_s25fl_write_dyb(struct stfsm *fsm, uint32_t offs, uint8_t dby)
 {
        struct stfsm_seq seq = {
                .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
-                              SEQ_OPC_OPCODE(FLASH_CMD_WREN) |
+                              SEQ_OPC_OPCODE(SPINOR_OP_WREN) |
                               SEQ_OPC_CSDEASSERT),
                .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
                               SEQ_OPC_OPCODE(S25FL_CMD_DYBWR)),
@@ -1337,7 +1301,7 @@ static int stfsm_s25fl_clear_status_reg(struct stfsm *fsm)
                               SEQ_OPC_CSDEASSERT),
                .seq_opc[1] = (SEQ_OPC_PADS_1 |
                               SEQ_OPC_CYCLES(8) |
-                              SEQ_OPC_OPCODE(FLASH_CMD_WRDI) |
+                              SEQ_OPC_OPCODE(SPINOR_OP_WRDI) |
                               SEQ_OPC_CSDEASSERT),
                .seq = {
                        STFSM_INST_CMD1,
@@ -1367,6 +1331,7 @@ static int stfsm_s25fl_config(struct stfsm *fsm)
        uint32_t offs;
        uint16_t sta_wr;
        uint8_t sr1, cr1, dyb;
+       int update_sr = 0;
        int ret;
 
        if (flags & FLASH_FLAG_32BIT_ADDR) {
@@ -1414,34 +1379,28 @@ static int stfsm_s25fl_config(struct stfsm *fsm)
                }
        }
 
-       /* Check status of 'QE' bit */
+       /* Check status of 'QE' bit, update if required. */
+       stfsm_read_status(fsm, SPINOR_OP_RDSR2, &cr1, 1);
        data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
-       stfsm_read_status(fsm, FLASH_CMD_RDSR2, &cr1);
        if (data_pads == 4) {
                if (!(cr1 & STFSM_S25FL_CONFIG_QE)) {
                        /* Set 'QE' */
                        cr1 |= STFSM_S25FL_CONFIG_QE;
 
-                       stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1);
-                       sta_wr = ((uint16_t)cr1  << 8) | sr1;
-
-                       stfsm_write_status(fsm, sta_wr, 2);
-
-                       stfsm_wait_busy(fsm);
+                       update_sr = 1;
                }
        } else {
-               if ((cr1 & STFSM_S25FL_CONFIG_QE)) {
+               if (cr1 & STFSM_S25FL_CONFIG_QE) {
                        /* Clear 'QE' */
                        cr1 &= ~STFSM_S25FL_CONFIG_QE;
 
-                       stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1);
-                       sta_wr = ((uint16_t)cr1  << 8) | sr1;
-
-                       stfsm_write_status(fsm, sta_wr, 2);
-
-                       stfsm_wait_busy(fsm);
+                       update_sr = 1;
                }
-
+       }
+       if (update_sr) {
+               stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1);
+               sta_wr = ((uint16_t)cr1  << 8) | sr1;
+               stfsm_write_status(fsm, SPINOR_OP_WRSR, sta_wr, 2, 1);
        }
 
        /*
@@ -1456,27 +1415,36 @@ static int stfsm_s25fl_config(struct stfsm *fsm)
 static int stfsm_w25q_config(struct stfsm *fsm)
 {
        uint32_t data_pads;
-       uint16_t sta_wr;
-       uint8_t sta1, sta2;
+       uint8_t sr1, sr2;
+       uint16_t sr_wr;
+       int update_sr = 0;
        int ret;
 
        ret = stfsm_prepare_rwe_seqs_default(fsm);
        if (ret)
                return ret;
 
-       /* If using QUAD mode, set QE STATUS bit */
+       /* Check status of 'QE' bit, update if required. */
+       stfsm_read_status(fsm, SPINOR_OP_RDSR2, &sr2, 1);
        data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
        if (data_pads == 4) {
-               stfsm_read_status(fsm, FLASH_CMD_RDSR, &sta1);
-               stfsm_read_status(fsm, FLASH_CMD_RDSR2, &sta2);
-
-               sta_wr = ((uint16_t)sta2 << 8) | sta1;
-
-               sta_wr |= W25Q_STATUS_QE;
-
-               stfsm_write_status(fsm, sta_wr, 2);
-
-               stfsm_wait_busy(fsm);
+               if (!(sr2 & W25Q_STATUS_QE)) {
+                       /* Set 'QE' */
+                       sr2 |= W25Q_STATUS_QE;
+                       update_sr = 1;
+               }
+       } else {
+               if (sr2 & W25Q_STATUS_QE) {
+                       /* Clear 'QE' */
+                       sr2 &= ~W25Q_STATUS_QE;
+                       update_sr = 1;
+               }
+       }
+       if (update_sr) {
+               /* Write status register */
+               stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1);
+               sr_wr = ((uint16_t)sr2 << 8) | sr1;
+               stfsm_write_status(fsm, SPINOR_OP_WRSR, sr_wr, 2, 1);
        }
 
        return 0;
@@ -1506,7 +1474,7 @@ static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size,
        read_mask = (data_pads << 2) - 1;
 
        /* Handle non-aligned buf */
-       p = ((uint32_t)buf & 0x3) ? (uint8_t *)page_buf : buf;
+       p = ((uintptr_t)buf & 0x3) ? (uint8_t *)page_buf : buf;
 
        /* Handle non-aligned size */
        size_ub = (size + read_mask) & ~read_mask;
@@ -1528,7 +1496,7 @@ static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size,
        }
 
        /* Handle non-aligned buf */
-       if ((uint32_t)buf & 0x3)
+       if ((uintptr_t)buf & 0x3)
                memcpy(buf, page_buf, size);
 
        /* Wait for sequence to finish */
@@ -1570,7 +1538,7 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf,
        write_mask = (data_pads << 2) - 1;
 
        /* Handle non-aligned buf */
-       if ((uint32_t)buf & 0x3) {
+       if ((uintptr_t)buf & 0x3) {
                memcpy(page_buf, buf, size);
                p = (uint8_t *)page_buf;
        } else {
@@ -1628,11 +1596,8 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf,
                stfsm_s25fl_clear_status_reg(fsm);
 
        /* Exit 32-bit address mode, if required */
-       if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) {
+       if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR)
                stfsm_enter_32bit_addr(fsm, 0);
-               if (fsm->configuration & CFG_WRITE_EX_32BIT_ADDR_DELAY)
-                       udelay(1);
-       }
 
        return 0;
 }
@@ -1736,7 +1701,7 @@ static int stfsm_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 
        while (len) {
                /* Write up to page boundary */
-               bytes = min(FLASH_PAGESIZE - page_offs, len);
+               bytes = min_t(size_t, FLASH_PAGESIZE - page_offs, len);
 
                ret = stfsm_write(fsm, b, bytes, to);
                if (ret)
@@ -1935,6 +1900,13 @@ static int stfsm_init(struct stfsm *fsm)
               fsm->base + SPI_CONFIGDATA);
        writel(STFSM_DEFAULT_WR_TIME, fsm->base + SPI_STATUS_WR_TIME_REG);
 
+       /*
+        * Set the FSM 'WAIT' delay to the minimum workable value.  Note, for
+        * our purposes, the WAIT instruction is used purely to achieve
+        * "sequence validity" rather than actually implement a delay.
+        */
+       writel(0x00000001, fsm->base + SPI_PROGRAM_ERASE_TIME);
+
        /* Clear FIFO, just in case */
        stfsm_clear_fifo(fsm);
 
index 0b2ccb68c0d0240efdb9c5de9189f8e89a4ca890..43e30992a3697a76f932bc778c76d8bcdf7080ce 100644 (file)
@@ -82,12 +82,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 
        block = blk_rq_pos(req) << 9 >> tr->blkshift;
        nsect = blk_rq_cur_bytes(req) >> tr->blkshift;
-
-       buf = req->buffer;
+       buf = bio_data(req->bio);
 
        if (req->cmd_type != REQ_TYPE_FS)
                return -EIO;
 
+       if (req->cmd_flags & REQ_FLUSH)
+               return tr->flush(dev);
+
        if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
            get_capacity(req->rq_disk))
                return -EIO;
@@ -408,6 +410,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        if (!new->rq)
                goto error3;
 
+       if (tr->flush)
+               blk_queue_flush(new->rq, REQ_FLUSH);
+
        new->rq->queuedata = new;
        blk_queue_logical_block_size(new->rq, tr->blksize);
 
index 4615d79fc93f795c869687117744e01653219478..b922c8efcf4012376548c15e4a3af50562d47095 100644 (file)
@@ -523,6 +523,7 @@ static struct nand_ecclayout hwecc4_2048 = {
 #if defined(CONFIG_OF)
 static const struct of_device_id davinci_nand_of_match[] = {
        {.compatible = "ti,davinci-nand", },
+       {.compatible = "ti,keystone-nand", },
        {},
 };
 MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
@@ -581,6 +582,11 @@ static struct davinci_nand_pdata
                    of_property_read_bool(pdev->dev.of_node,
                        "ti,davinci-nand-use-bbt"))
                        pdata->bbt_options = NAND_BBT_USE_FLASH;
+
+               if (of_device_is_compatible(pdev->dev.of_node,
+                                           "ti,keystone-nand")) {
+                       pdata->options |= NAND_NO_SUBPAGE_WRITE;
+               }
        }
 
        return dev_get_platdata(&pdev->dev);
index dd1df605a1d61ec8a43ffb5515ea50ce2f3c9b69..ec4db2a359e5de9d7e6a57fb855698115e9722f1 100644 (file)
@@ -861,7 +861,7 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
        struct resources *r = &this->resources;
        unsigned long rate = clk_get_rate(r->clock[0]);
        int mode = this->timing_mode;
-       int dll_threshold = 16; /* in ns */
+       int dll_threshold = this->devdata->max_chain_delay;
        unsigned long delay;
        unsigned long clk_period;
        int t_rea;
@@ -886,9 +886,6 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
        /* [3] for GPMI_HW_GPMI_CTRL1 */
        hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
 
-       if (GPMI_IS_MX6Q(this))
-               dll_threshold = 12;
-
        /*
         * Enlarge 10 times for the numerator and denominator in {3}.
         * This make us to get more accurate result.
index bb77f750e75a3b1cfee16e5ecbf95efea95ead1a..e88d64e1e9632df9e349616af77d204e2f4e4ca3 100644 (file)
@@ -53,6 +53,24 @@ static struct nand_ecclayout gpmi_hw_ecclayout = {
        .oobfree = { {.offset = 0, .length = 0} }
 };
 
+static const struct gpmi_devdata gpmi_devdata_imx23 = {
+       .type = IS_MX23,
+       .bch_max_ecc_strength = 20,
+       .max_chain_delay = 16,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx28 = {
+       .type = IS_MX28,
+       .bch_max_ecc_strength = 20,
+       .max_chain_delay = 16,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6q = {
+       .type = IS_MX6Q,
+       .bch_max_ecc_strength = 40,
+       .max_chain_delay = 12,
+};
+
 static irqreturn_t bch_irq(int irq, void *cookie)
 {
        struct gpmi_nand_data *this = cookie;
@@ -102,14 +120,8 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
                /* The mx23/mx28 only support the GF13. */
                if (geo->gf_len == 14)
                        return false;
-
-               if (geo->ecc_strength > MXS_ECC_STRENGTH_MAX)
-                       return false;
-       } else if (GPMI_IS_MX6Q(this)) {
-               if (geo->ecc_strength > MX6_ECC_STRENGTH_MAX)
-                       return false;
        }
-       return true;
+       return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
 }
 
 /*
@@ -270,8 +282,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
                        "We can not support this nand chip."
                        " Its required ecc strength(%d) is beyond our"
                        " capability(%d).\n", geo->ecc_strength,
-                       (GPMI_IS_MX6Q(this) ? MX6_ECC_STRENGTH_MAX
-                                       : MXS_ECC_STRENGTH_MAX));
+                       this->devdata->bch_max_ecc_strength);
                return -EINVAL;
        }
 
@@ -1740,23 +1751,16 @@ err_out:
        return ret;
 }
 
-static const struct platform_device_id gpmi_ids[] = {
-       { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
-       { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
-       { .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, },
-       {}
-};
-
 static const struct of_device_id gpmi_nand_id_table[] = {
        {
                .compatible = "fsl,imx23-gpmi-nand",
-               .data = (void *)&gpmi_ids[IS_MX23],
+               .data = (void *)&gpmi_devdata_imx23,
        }, {
                .compatible = "fsl,imx28-gpmi-nand",
-               .data = (void *)&gpmi_ids[IS_MX28],
+               .data = (void *)&gpmi_devdata_imx28,
        }, {
                .compatible = "fsl,imx6q-gpmi-nand",
-               .data = (void *)&gpmi_ids[IS_MX6Q],
+               .data = (void *)&gpmi_devdata_imx6q,
        }, {}
 };
 MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
@@ -1767,18 +1771,18 @@ static int gpmi_nand_probe(struct platform_device *pdev)
        const struct of_device_id *of_id;
        int ret;
 
+       this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
+       if (!this)
+               return -ENOMEM;
+
        of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
        if (of_id) {
-               pdev->id_entry = of_id->data;
+               this->devdata = of_id->data;
        } else {
                dev_err(&pdev->dev, "Failed to find the right device id.\n");
                return -ENODEV;
        }
 
-       this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
-       if (!this)
-               return -ENOMEM;
-
        platform_set_drvdata(pdev, this);
        this->pdev  = pdev;
        this->dev   = &pdev->dev;
@@ -1823,7 +1827,6 @@ static struct platform_driver gpmi_nand_driver = {
        },
        .probe   = gpmi_nand_probe,
        .remove  = gpmi_nand_remove,
-       .id_table = gpmi_ids,
 };
 module_platform_driver(gpmi_nand_driver);
 
index 4c801fa1872530e681e801d2adaee333d4acffb4..7904e8329b67c04829a771a6bef5baf093cf65d9 100644 (file)
@@ -119,11 +119,24 @@ struct nand_timing {
        int8_t  tRHOH_in_ns;
 };
 
+enum gpmi_type {
+       IS_MX23,
+       IS_MX28,
+       IS_MX6Q
+};
+
+struct gpmi_devdata {
+       enum gpmi_type type;
+       int bch_max_ecc_strength;
+       int max_chain_delay; /* See the async EDO mode */
+};
+
 struct gpmi_nand_data {
        /* flags */
 #define GPMI_ASYNC_EDO_ENABLED (1 << 0)
 #define GPMI_TIMING_INIT_OK    (1 << 1)
        int                     flags;
+       const struct gpmi_devdata *devdata;
 
        /* System Interface */
        struct device           *dev;
@@ -281,15 +294,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
 #define STATUS_ERASED          0xff
 #define STATUS_UNCORRECTABLE   0xfe
 
-/* BCH's bit correction capability. */
-#define MXS_ECC_STRENGTH_MAX   20      /* mx23 and mx28 */
-#define MX6_ECC_STRENGTH_MAX   40
-
-/* Use the platform_id to distinguish different Archs. */
-#define IS_MX23                        0x0
-#define IS_MX28                        0x1
-#define IS_MX6Q                        0x2
-#define GPMI_IS_MX23(x)                ((x)->pdev->id_entry->driver_data == IS_MX23)
-#define GPMI_IS_MX28(x)                ((x)->pdev->id_entry->driver_data == IS_MX28)
-#define GPMI_IS_MX6Q(x)                ((x)->pdev->id_entry->driver_data == IS_MX6Q)
+/* Use the devdata to distinguish different Archs. */
+#define GPMI_IS_MX23(x)                ((x)->devdata->type == IS_MX23)
+#define GPMI_IS_MX28(x)                ((x)->devdata->type == IS_MX28)
+#define GPMI_IS_MX6Q(x)                ((x)->devdata->type == IS_MX6Q)
 #endif
index 9d01c4df838c91000dda6793ae231b0dd0992062..f6c5685b79a6a9f167784bdb344583657eaf9a80 100644 (file)
@@ -1204,8 +1204,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
         * ecc.pos. Let's make sure that there are no gaps in ECC positions.
         */
        for (i = 0; i < eccfrag_len - 1; i++) {
-               if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=
-                       eccpos[i + start_step * chip->ecc.bytes + 1]) {
+               if (eccpos[i + index] + 1 != eccpos[i + index + 1]) {
                        gaps = 1;
                        break;
                }
@@ -3607,7 +3606,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 
        chip->onfi_version = 0;
        if (!type->name || !type->pagesize) {
-               /* Check is chip is ONFI compliant */
+               /* Check if the chip is ONFI compliant */
                if (nand_flash_detect_onfi(mtd, chip, &busw))
                        goto ident_done;
 
index 053c9a2d47c3d02daca5589f622bb0e083c67afa..97c4c0216c90727b79bb58425aa9cdd9e2493792 100644 (file)
@@ -506,7 +506,7 @@ int __nand_correct_data(unsigned char *buf,
        if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
                return 1;       /* error in ECC data; no action needed */
 
-       pr_err("%s: uncorrectable ECC error", __func__);
+       pr_err("%s: uncorrectable ECC error\n", __func__);
        return -1;
 }
 EXPORT_SYMBOL(__nand_correct_data);
index 42e8a770e631c6eb4f98658cd9cef88d08ca1350..4f0d83648e5a5ad9f5f0260e21b01067f81099be 100644 (file)
@@ -575,12 +575,12 @@ static int alloc_device(struct nandsim *ns)
                cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
                if (IS_ERR(cfile))
                        return PTR_ERR(cfile);
-               if (!cfile->f_op->read && !cfile->f_op->aio_read) {
+               if (!(cfile->f_mode & FMODE_CAN_READ)) {
                        NS_ERR("alloc_device: cache file not readable\n");
                        err = -EINVAL;
                        goto err_close;
                }
-               if (!cfile->f_op->write && !cfile->f_op->aio_write) {
+               if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
                        NS_ERR("alloc_device: cache file not writeable\n");
                        err = -EINVAL;
                        goto err_close;
index 1ff49b80bdaf7e3a454c02574165d1a59a04a72b..1b800bcda5a47550505b2b4910304b414ed53beb 100644 (file)
@@ -1237,6 +1237,7 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
        return 0;
 }
 
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
 /**
  * erased_sector_bitflips - count bit flips
  * @data:      data sector buffer
@@ -1276,7 +1277,6 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
        return flip_bits;
 }
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
 /**
  * omap_elm_correct_data - corrects page data area in case error reported
  * @mtd:       MTD device structure
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
new file mode 100644 (file)
index 0000000..f8acfa4
--- /dev/null
@@ -0,0 +1,17 @@
+menuconfig MTD_SPI_NOR
+       tristate "SPI-NOR device support"
+       depends on MTD
+       help
+         This is the framework for the SPI NOR which can be used by the SPI
+         device drivers and the SPI-NOR device driver.
+
+if MTD_SPI_NOR
+
+config SPI_FSL_QUADSPI
+       tristate "Freescale Quad SPI controller"
+       depends on ARCH_MXC
+       help
+         This enables support for the Quad SPI controller in master mode.
+         We only connect the NOR to this controller now.
+
+endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
new file mode 100644 (file)
index 0000000..6a7ce14
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MTD_SPI_NOR)      += spi-nor.o
+obj-$(CONFIG_SPI_FSL_QUADSPI)  += fsl-quadspi.o
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
new file mode 100644 (file)
index 0000000..8d659a2
--- /dev/null
@@ -0,0 +1,1009 @@
+/*
+ * Freescale QuadSPI driver.
+ *
+ * Copyright (C) 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 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/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/completion.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+
+/* The registers */
+#define QUADSPI_MCR                    0x00
+#define QUADSPI_MCR_RESERVED_SHIFT     16
+#define QUADSPI_MCR_RESERVED_MASK      (0xF << QUADSPI_MCR_RESERVED_SHIFT)
+#define QUADSPI_MCR_MDIS_SHIFT         14
+#define QUADSPI_MCR_MDIS_MASK          (1 << QUADSPI_MCR_MDIS_SHIFT)
+#define QUADSPI_MCR_CLR_TXF_SHIFT      11
+#define QUADSPI_MCR_CLR_TXF_MASK       (1 << QUADSPI_MCR_CLR_TXF_SHIFT)
+#define QUADSPI_MCR_CLR_RXF_SHIFT      10
+#define QUADSPI_MCR_CLR_RXF_MASK       (1 << QUADSPI_MCR_CLR_RXF_SHIFT)
+#define QUADSPI_MCR_DDR_EN_SHIFT       7
+#define QUADSPI_MCR_DDR_EN_MASK                (1 << QUADSPI_MCR_DDR_EN_SHIFT)
+#define QUADSPI_MCR_END_CFG_SHIFT      2
+#define QUADSPI_MCR_END_CFG_MASK       (3 << QUADSPI_MCR_END_CFG_SHIFT)
+#define QUADSPI_MCR_SWRSTHD_SHIFT      1
+#define QUADSPI_MCR_SWRSTHD_MASK       (1 << QUADSPI_MCR_SWRSTHD_SHIFT)
+#define QUADSPI_MCR_SWRSTSD_SHIFT      0
+#define QUADSPI_MCR_SWRSTSD_MASK       (1 << QUADSPI_MCR_SWRSTSD_SHIFT)
+
+#define QUADSPI_IPCR                   0x08
+#define QUADSPI_IPCR_SEQID_SHIFT       24
+#define QUADSPI_IPCR_SEQID_MASK                (0xF << QUADSPI_IPCR_SEQID_SHIFT)
+
+#define QUADSPI_BUF0CR                 0x10
+#define QUADSPI_BUF1CR                 0x14
+#define QUADSPI_BUF2CR                 0x18
+#define QUADSPI_BUFXCR_INVALID_MSTRID  0xe
+
+#define QUADSPI_BUF3CR                 0x1c
+#define QUADSPI_BUF3CR_ALLMST_SHIFT    31
+#define QUADSPI_BUF3CR_ALLMST          (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
+
+#define QUADSPI_BFGENCR                        0x20
+#define QUADSPI_BFGENCR_PAR_EN_SHIFT   16
+#define QUADSPI_BFGENCR_PAR_EN_MASK    (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT))
+#define QUADSPI_BFGENCR_SEQID_SHIFT    12
+#define QUADSPI_BFGENCR_SEQID_MASK     (0xF << QUADSPI_BFGENCR_SEQID_SHIFT)
+
+#define QUADSPI_BUF0IND                        0x30
+#define QUADSPI_BUF1IND                        0x34
+#define QUADSPI_BUF2IND                        0x38
+#define QUADSPI_SFAR                   0x100
+
+#define QUADSPI_SMPR                   0x108
+#define QUADSPI_SMPR_DDRSMP_SHIFT      16
+#define QUADSPI_SMPR_DDRSMP_MASK       (7 << QUADSPI_SMPR_DDRSMP_SHIFT)
+#define QUADSPI_SMPR_FSDLY_SHIFT       6
+#define QUADSPI_SMPR_FSDLY_MASK                (1 << QUADSPI_SMPR_FSDLY_SHIFT)
+#define QUADSPI_SMPR_FSPHS_SHIFT       5
+#define QUADSPI_SMPR_FSPHS_MASK                (1 << QUADSPI_SMPR_FSPHS_SHIFT)
+#define QUADSPI_SMPR_HSENA_SHIFT       0
+#define QUADSPI_SMPR_HSENA_MASK                (1 << QUADSPI_SMPR_HSENA_SHIFT)
+
+#define QUADSPI_RBSR                   0x10c
+#define QUADSPI_RBSR_RDBFL_SHIFT       8
+#define QUADSPI_RBSR_RDBFL_MASK                (0x3F << QUADSPI_RBSR_RDBFL_SHIFT)
+
+#define QUADSPI_RBCT                   0x110
+#define QUADSPI_RBCT_WMRK_MASK         0x1F
+#define QUADSPI_RBCT_RXBRD_SHIFT       8
+#define QUADSPI_RBCT_RXBRD_USEIPS      (0x1 << QUADSPI_RBCT_RXBRD_SHIFT)
+
+#define QUADSPI_TBSR                   0x150
+#define QUADSPI_TBDR                   0x154
+#define QUADSPI_SR                     0x15c
+#define QUADSPI_SR_IP_ACC_SHIFT                1
+#define QUADSPI_SR_IP_ACC_MASK         (0x1 << QUADSPI_SR_IP_ACC_SHIFT)
+#define QUADSPI_SR_AHB_ACC_SHIFT       2
+#define QUADSPI_SR_AHB_ACC_MASK                (0x1 << QUADSPI_SR_AHB_ACC_SHIFT)
+
+#define QUADSPI_FR                     0x160
+#define QUADSPI_FR_TFF_MASK            0x1
+
+#define QUADSPI_SFA1AD                 0x180
+#define QUADSPI_SFA2AD                 0x184
+#define QUADSPI_SFB1AD                 0x188
+#define QUADSPI_SFB2AD                 0x18c
+#define QUADSPI_RBDR                   0x200
+
+#define QUADSPI_LUTKEY                 0x300
+#define QUADSPI_LUTKEY_VALUE           0x5AF05AF0
+
+#define QUADSPI_LCKCR                  0x304
+#define QUADSPI_LCKER_LOCK             0x1
+#define QUADSPI_LCKER_UNLOCK           0x2
+
+#define QUADSPI_RSER                   0x164
+#define QUADSPI_RSER_TFIE              (0x1 << 0)
+
+#define QUADSPI_LUT_BASE               0x310
+
+/*
+ * The definition of the LUT register shows below:
+ *
+ *  ---------------------------------------------------
+ *  | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ *  ---------------------------------------------------
+ */
+#define OPRND0_SHIFT           0
+#define PAD0_SHIFT             8
+#define INSTR0_SHIFT           10
+#define OPRND1_SHIFT           16
+
+/* Instruction set for the LUT register. */
+#define LUT_STOP               0
+#define LUT_CMD                        1
+#define LUT_ADDR               2
+#define LUT_DUMMY              3
+#define LUT_MODE               4
+#define LUT_MODE2              5
+#define LUT_MODE4              6
+#define LUT_READ               7
+#define LUT_WRITE              8
+#define LUT_JMP_ON_CS          9
+#define LUT_ADDR_DDR           10
+#define LUT_MODE_DDR           11
+#define LUT_MODE2_DDR          12
+#define LUT_MODE4_DDR          13
+#define LUT_READ_DDR           14
+#define LUT_WRITE_DDR          15
+#define LUT_DATA_LEARN         16
+
+/*
+ * The PAD definitions for LUT register.
+ *
+ * The pad stands for the lines number of IO[0:3].
+ * For example, the Quad read need four IO lines, so you should
+ * set LUT_PAD4 which means we use four IO lines.
+ */
+#define LUT_PAD1               0
+#define LUT_PAD2               1
+#define LUT_PAD4               2
+
+/* Oprands for the LUT register. */
+#define ADDR24BIT              0x18
+#define ADDR32BIT              0x20
+
+/* Macros for constructing the LUT register. */
+#define LUT0(ins, pad, opr)                                            \
+               (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
+               ((LUT_##ins) << INSTR0_SHIFT))
+
+#define LUT1(ins, pad, opr)    (LUT0(ins, pad, opr) << OPRND1_SHIFT)
+
+/* other macros for LUT register. */
+#define QUADSPI_LUT(x)          (QUADSPI_LUT_BASE + (x) * 4)
+#define QUADSPI_LUT_NUM                64
+
+/* SEQID -- we can have 16 seqids at most. */
+#define SEQID_QUAD_READ                0
+#define SEQID_WREN             1
+#define SEQID_WRDI             2
+#define SEQID_RDSR             3
+#define SEQID_SE               4
+#define SEQID_CHIP_ERASE       5
+#define SEQID_PP               6
+#define SEQID_RDID             7
+#define SEQID_WRSR             8
+#define SEQID_RDCR             9
+#define SEQID_EN4B             10
+#define SEQID_BRWR             11
+
+enum fsl_qspi_devtype {
+       FSL_QUADSPI_VYBRID,
+       FSL_QUADSPI_IMX6SX,
+};
+
+struct fsl_qspi_devtype_data {
+       enum fsl_qspi_devtype devtype;
+       int rxfifo;
+       int txfifo;
+};
+
+static struct fsl_qspi_devtype_data vybrid_data = {
+       .devtype = FSL_QUADSPI_VYBRID,
+       .rxfifo = 128,
+       .txfifo = 64
+};
+
+static struct fsl_qspi_devtype_data imx6sx_data = {
+       .devtype = FSL_QUADSPI_IMX6SX,
+       .rxfifo = 128,
+       .txfifo = 512
+};
+
+#define FSL_QSPI_MAX_CHIP      4
+struct fsl_qspi {
+       struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
+       struct spi_nor nor[FSL_QSPI_MAX_CHIP];
+       void __iomem *iobase;
+       void __iomem *ahb_base; /* Used when read from AHB bus */
+       u32 memmap_phy;
+       struct clk *clk, *clk_en;
+       struct device *dev;
+       struct completion c;
+       struct fsl_qspi_devtype_data *devtype_data;
+       u32 nor_size;
+       u32 nor_num;
+       u32 clk_rate;
+       unsigned int chip_base_addr; /* We may support two chips. */
+};
+
+static inline int is_vybrid_qspi(struct fsl_qspi *q)
+{
+       return q->devtype_data->devtype == FSL_QUADSPI_VYBRID;
+}
+
+static inline int is_imx6sx_qspi(struct fsl_qspi *q)
+{
+       return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX;
+}
+
+/*
+ * An IC bug makes us to re-arrange the 32-bit data.
+ * The following chips, such as IMX6SLX, have fixed this bug.
+ */
+static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
+{
+       return is_vybrid_qspi(q) ? __swab32(a) : a;
+}
+
+static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
+{
+       writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+       writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
+}
+
+static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
+{
+       writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+       writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
+}
+
+static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
+{
+       struct fsl_qspi *q = dev_id;
+       u32 reg;
+
+       /* clear interrupt */
+       reg = readl(q->iobase + QUADSPI_FR);
+       writel(reg, q->iobase + QUADSPI_FR);
+
+       if (reg & QUADSPI_FR_TFF_MASK)
+               complete(&q->c);
+
+       dev_dbg(q->dev, "QUADSPI_FR : 0x%.8x:0x%.8x\n", q->chip_base_addr, reg);
+       return IRQ_HANDLED;
+}
+
+static void fsl_qspi_init_lut(struct fsl_qspi *q)
+{
+       void __iomem *base = q->iobase;
+       int rxfifo = q->devtype_data->rxfifo;
+       u32 lut_base;
+       u8 cmd, addrlen, dummy;
+       int i;
+
+       fsl_qspi_unlock_lut(q);
+
+       /* Clear all the LUT table */
+       for (i = 0; i < QUADSPI_LUT_NUM; i++)
+               writel(0, base + QUADSPI_LUT_BASE + i * 4);
+
+       /* Quad Read */
+       lut_base = SEQID_QUAD_READ * 4;
+
+       if (q->nor_size <= SZ_16M) {
+               cmd = SPINOR_OP_READ_1_1_4;
+               addrlen = ADDR24BIT;
+               dummy = 8;
+       } else {
+               /* use the 4-byte address */
+               cmd = SPINOR_OP_READ_1_1_4;
+               addrlen = ADDR32BIT;
+               dummy = 8;
+       }
+
+       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+                       base + QUADSPI_LUT(lut_base));
+       writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo),
+                       base + QUADSPI_LUT(lut_base + 1));
+
+       /* Write enable */
+       lut_base = SEQID_WREN * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_WREN), base + QUADSPI_LUT(lut_base));
+
+       /* Page Program */
+       lut_base = SEQID_PP * 4;
+
+       if (q->nor_size <= SZ_16M) {
+               cmd = SPINOR_OP_PP;
+               addrlen = ADDR24BIT;
+       } else {
+               /* use the 4-byte address */
+               cmd = SPINOR_OP_PP;
+               addrlen = ADDR32BIT;
+       }
+
+       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+                       base + QUADSPI_LUT(lut_base));
+       writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
+
+       /* Read Status */
+       lut_base = SEQID_RDSR * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(READ, PAD1, 0x1),
+                       base + QUADSPI_LUT(lut_base));
+
+       /* Erase a sector */
+       lut_base = SEQID_SE * 4;
+
+       if (q->nor_size <= SZ_16M) {
+               cmd = SPINOR_OP_SE;
+               addrlen = ADDR24BIT;
+       } else {
+               /* use the 4-byte address */
+               cmd = SPINOR_OP_SE;
+               addrlen = ADDR32BIT;
+       }
+
+       writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+                       base + QUADSPI_LUT(lut_base));
+
+       /* Erase the whole chip */
+       lut_base = SEQID_CHIP_ERASE * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
+                       base + QUADSPI_LUT(lut_base));
+
+       /* READ ID */
+       lut_base = SEQID_RDID * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(READ, PAD1, 0x8),
+                       base + QUADSPI_LUT(lut_base));
+
+       /* Write Register */
+       lut_base = SEQID_WRSR * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(WRITE, PAD1, 0x2),
+                       base + QUADSPI_LUT(lut_base));
+
+       /* Read Configuration Register */
+       lut_base = SEQID_RDCR * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(READ, PAD1, 0x1),
+                       base + QUADSPI_LUT(lut_base));
+
+       /* Write disable */
+       lut_base = SEQID_WRDI * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_WRDI), base + QUADSPI_LUT(lut_base));
+
+       /* Enter 4 Byte Mode (Micron) */
+       lut_base = SEQID_EN4B * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_EN4B), base + QUADSPI_LUT(lut_base));
+
+       /* Enter 4 Byte Mode (Spansion) */
+       lut_base = SEQID_BRWR * 4;
+       writel(LUT0(CMD, PAD1, SPINOR_OP_BRWR), base + QUADSPI_LUT(lut_base));
+
+       fsl_qspi_lock_lut(q);
+}
+
+/* Get the SEQID for the command */
+static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+{
+       switch (cmd) {
+       case SPINOR_OP_READ_1_1_4:
+               return SEQID_QUAD_READ;
+       case SPINOR_OP_WREN:
+               return SEQID_WREN;
+       case SPINOR_OP_WRDI:
+               return SEQID_WRDI;
+       case SPINOR_OP_RDSR:
+               return SEQID_RDSR;
+       case SPINOR_OP_SE:
+               return SEQID_SE;
+       case SPINOR_OP_CHIP_ERASE:
+               return SEQID_CHIP_ERASE;
+       case SPINOR_OP_PP:
+               return SEQID_PP;
+       case SPINOR_OP_RDID:
+               return SEQID_RDID;
+       case SPINOR_OP_WRSR:
+               return SEQID_WRSR;
+       case SPINOR_OP_RDCR:
+               return SEQID_RDCR;
+       case SPINOR_OP_EN4B:
+               return SEQID_EN4B;
+       case SPINOR_OP_BRWR:
+               return SEQID_BRWR;
+       default:
+               dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
+               break;
+       }
+       return -EINVAL;
+}
+
+static int
+fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
+{
+       void __iomem *base = q->iobase;
+       int seqid;
+       u32 reg, reg2;
+       int err;
+
+       init_completion(&q->c);
+       dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n",
+                       q->chip_base_addr, addr, len, cmd);
+
+       /* save the reg */
+       reg = readl(base + QUADSPI_MCR);
+
+       writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR);
+       writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
+                       base + QUADSPI_RBCT);
+       writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
+
+       do {
+               reg2 = readl(base + QUADSPI_SR);
+               if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) {
+                       udelay(1);
+                       dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2);
+                       continue;
+               }
+               break;
+       } while (1);
+
+       /* trigger the LUT now */
+       seqid = fsl_qspi_get_seqid(q, cmd);
+       writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
+
+       /* Wait for the interrupt. */
+       err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000));
+       if (!err) {
+               dev_err(q->dev,
+                       "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
+                       cmd, addr, readl(base + QUADSPI_FR),
+                       readl(base + QUADSPI_SR));
+               err = -ETIMEDOUT;
+       } else {
+               err = 0;
+       }
+
+       /* restore the MCR */
+       writel(reg, base + QUADSPI_MCR);
+
+       return err;
+}
+
+/* Read out the data from the QUADSPI_RBDR buffer registers. */
+static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
+{
+       u32 tmp;
+       int i = 0;
+
+       while (len > 0) {
+               tmp = readl(q->iobase + QUADSPI_RBDR + i * 4);
+               tmp = fsl_qspi_endian_xchg(q, tmp);
+               dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n",
+                               q->chip_base_addr, tmp);
+
+               if (len >= 4) {
+                       *((u32 *)rxbuf) = tmp;
+                       rxbuf += 4;
+               } else {
+                       memcpy(rxbuf, &tmp, len);
+                       break;
+               }
+
+               len -= 4;
+               i++;
+       }
+}
+
+/*
+ * If we have changed the content of the flash by writing or erasing,
+ * we need to invalidate the AHB buffer. If we do not do so, we may read out
+ * the wrong data. The spec tells us reset the AHB domain and Serial Flash
+ * domain at the same time.
+ */
+static inline void fsl_qspi_invalid(struct fsl_qspi *q)
+{
+       u32 reg;
+
+       reg = readl(q->iobase + QUADSPI_MCR);
+       reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
+       writel(reg, q->iobase + QUADSPI_MCR);
+
+       /*
+        * The minimum delay : 1 AHB + 2 SFCK clocks.
+        * Delay 1 us is enough.
+        */
+       udelay(1);
+
+       reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
+       writel(reg, q->iobase + QUADSPI_MCR);
+}
+
+static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+                               u8 opcode, unsigned int to, u32 *txbuf,
+                               unsigned count, size_t *retlen)
+{
+       int ret, i, j;
+       u32 tmp;
+
+       dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
+               q->chip_base_addr, to, count);
+
+       /* clear the TX FIFO. */
+       tmp = readl(q->iobase + QUADSPI_MCR);
+       writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR);
+
+       /* fill the TX data to the FIFO */
+       for (j = 0, i = ((count + 3) / 4); j < i; j++) {
+               tmp = fsl_qspi_endian_xchg(q, *txbuf);
+               writel(tmp, q->iobase + QUADSPI_TBDR);
+               txbuf++;
+       }
+
+       /* Trigger it */
+       ret = fsl_qspi_runcmd(q, opcode, to, count);
+
+       if (ret == 0 && retlen)
+               *retlen += count;
+
+       return ret;
+}
+
+static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
+{
+       int nor_size = q->nor_size;
+       void __iomem *base = q->iobase;
+
+       writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
+       writel(nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
+       writel(nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
+       writel(nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
+}
+
+/*
+ * There are two different ways to read out the data from the flash:
+ *  the "IP Command Read" and the "AHB Command Read".
+ *
+ * The IC guy suggests we use the "AHB Command Read" which is faster
+ * then the "IP Command Read". (What's more is that there is a bug in
+ * the "IP Command Read" in the Vybrid.)
+ *
+ * After we set up the registers for the "AHB Command Read", we can use
+ * the memcpy to read the data directly. A "missed" access to the buffer
+ * causes the controller to clear the buffer, and use the sequence pointed
+ * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
+ */
+static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
+{
+       void __iomem *base = q->iobase;
+       int seqid;
+
+       /* AHB configuration for access buffer 0/1/2 .*/
+       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+       writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
+       writel(QUADSPI_BUF3CR_ALLMST, base + QUADSPI_BUF3CR);
+
+       /* We only use the buffer3 */
+       writel(0, base + QUADSPI_BUF0IND);
+       writel(0, base + QUADSPI_BUF1IND);
+       writel(0, base + QUADSPI_BUF2IND);
+
+       /* Set the default lut sequence for AHB Read. */
+       seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+       writel(seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
+               q->iobase + QUADSPI_BFGENCR);
+}
+
+/* We use this function to do some basic init for spi_nor_scan(). */
+static int fsl_qspi_nor_setup(struct fsl_qspi *q)
+{
+       void __iomem *base = q->iobase;
+       u32 reg;
+       int ret;
+
+       /* the default frequency, we will change it in the future.*/
+       ret = clk_set_rate(q->clk, 66000000);
+       if (ret)
+               return ret;
+
+       /* Init the LUT table. */
+       fsl_qspi_init_lut(q);
+
+       /* Disable the module */
+       writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
+                       base + QUADSPI_MCR);
+
+       reg = readl(base + QUADSPI_SMPR);
+       writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK
+                       | QUADSPI_SMPR_FSPHS_MASK
+                       | QUADSPI_SMPR_HSENA_MASK
+                       | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
+
+       /* Enable the module */
+       writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
+                       base + QUADSPI_MCR);
+
+       /* enable the interrupt */
+       writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
+
+       return 0;
+}
+
+static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
+{
+       unsigned long rate = q->clk_rate;
+       int ret;
+
+       if (is_imx6sx_qspi(q))
+               rate *= 4;
+
+       ret = clk_set_rate(q->clk, rate);
+       if (ret)
+               return ret;
+
+       /* Init the LUT table again. */
+       fsl_qspi_init_lut(q);
+
+       /* Init for AHB read */
+       fsl_qspi_init_abh_read(q);
+
+       return 0;
+}
+
+static struct of_device_id fsl_qspi_dt_ids[] = {
+       { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
+       { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
+
+static void fsl_qspi_set_base_addr(struct fsl_qspi *q, struct spi_nor *nor)
+{
+       q->chip_base_addr = q->nor_size * (nor - q->nor);
+}
+
+static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+       int ret;
+       struct fsl_qspi *q = nor->priv;
+
+       ret = fsl_qspi_runcmd(q, opcode, 0, len);
+       if (ret)
+               return ret;
+
+       fsl_qspi_read_data(q, len, buf);
+       return 0;
+}
+
+static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+                       int write_enable)
+{
+       struct fsl_qspi *q = nor->priv;
+       int ret;
+
+       if (!buf) {
+               ret = fsl_qspi_runcmd(q, opcode, 0, 1);
+               if (ret)
+                       return ret;
+
+               if (opcode == SPINOR_OP_CHIP_ERASE)
+                       fsl_qspi_invalid(q);
+
+       } else if (len > 0) {
+               ret = fsl_qspi_nor_write(q, nor, opcode, 0,
+                                       (u32 *)buf, len, NULL);
+       } else {
+               dev_err(q->dev, "invalid cmd %d\n", opcode);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void fsl_qspi_write(struct spi_nor *nor, loff_t to,
+               size_t len, size_t *retlen, const u_char *buf)
+{
+       struct fsl_qspi *q = nor->priv;
+
+       fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+                               (u32 *)buf, len, retlen);
+
+       /* invalid the data in the AHB buffer. */
+       fsl_qspi_invalid(q);
+}
+
+static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
+               size_t len, size_t *retlen, u_char *buf)
+{
+       struct fsl_qspi *q = nor->priv;
+       u8 cmd = nor->read_opcode;
+       int ret;
+
+       dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
+               cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
+
+       /* Wait until the previous command is finished. */
+       ret = nor->wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       /* Read out the data directly from the AHB buffer.*/
+       memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
+
+       *retlen += len;
+       return 0;
+}
+
+static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
+{
+       struct fsl_qspi *q = nor->priv;
+       int ret;
+
+       dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
+               nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
+
+       /* Wait until finished previous write command. */
+       ret = nor->wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       /* Send write enable, then erase commands. */
+       ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+       if (ret)
+               return ret;
+
+       ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
+       if (ret)
+               return ret;
+
+       fsl_qspi_invalid(q);
+       return 0;
+}
+
+static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       struct fsl_qspi *q = nor->priv;
+       int ret;
+
+       ret = clk_enable(q->clk_en);
+       if (ret)
+               return ret;
+
+       ret = clk_enable(q->clk);
+       if (ret) {
+               clk_disable(q->clk_en);
+               return ret;
+       }
+
+       fsl_qspi_set_base_addr(q, nor);
+       return 0;
+}
+
+static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       struct fsl_qspi *q = nor->priv;
+
+       clk_disable(q->clk);
+       clk_disable(q->clk_en);
+}
+
+static int fsl_qspi_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct mtd_part_parser_data ppdata;
+       struct device *dev = &pdev->dev;
+       struct fsl_qspi *q;
+       struct resource *res;
+       struct spi_nor *nor;
+       struct mtd_info *mtd;
+       int ret, i = 0;
+       bool has_second_chip = false;
+       const struct of_device_id *of_id =
+                       of_match_device(fsl_qspi_dt_ids, &pdev->dev);
+
+       q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
+       if (!q)
+               return -ENOMEM;
+
+       q->nor_num = of_get_child_count(dev->of_node);
+       if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP)
+               return -ENODEV;
+
+       /* find the resources */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
+       q->iobase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(q->iobase)) {
+               ret = PTR_ERR(q->iobase);
+               goto map_failed;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                       "QuadSPI-memory");
+       q->ahb_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(q->ahb_base)) {
+               ret = PTR_ERR(q->ahb_base);
+               goto map_failed;
+       }
+       q->memmap_phy = res->start;
+
+       /* find the clocks */
+       q->clk_en = devm_clk_get(dev, "qspi_en");
+       if (IS_ERR(q->clk_en)) {
+               ret = PTR_ERR(q->clk_en);
+               goto map_failed;
+       }
+
+       q->clk = devm_clk_get(dev, "qspi");
+       if (IS_ERR(q->clk)) {
+               ret = PTR_ERR(q->clk);
+               goto map_failed;
+       }
+
+       ret = clk_prepare_enable(q->clk_en);
+       if (ret) {
+               dev_err(dev, "can not enable the qspi_en clock\n");
+               goto map_failed;
+       }
+
+       ret = clk_prepare_enable(q->clk);
+       if (ret) {
+               clk_disable_unprepare(q->clk_en);
+               dev_err(dev, "can not enable the qspi clock\n");
+               goto map_failed;
+       }
+
+       /* find the irq */
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+               dev_err(dev, "failed to get the irq\n");
+               goto irq_failed;
+       }
+
+       ret = devm_request_irq(dev, ret,
+                       fsl_qspi_irq_handler, 0, pdev->name, q);
+       if (ret) {
+               dev_err(dev, "failed to request irq.\n");
+               goto irq_failed;
+       }
+
+       q->dev = dev;
+       q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data;
+       platform_set_drvdata(pdev, q);
+
+       ret = fsl_qspi_nor_setup(q);
+       if (ret)
+               goto irq_failed;
+
+       if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
+               has_second_chip = true;
+
+       /* iterate the subnodes. */
+       for_each_available_child_of_node(dev->of_node, np) {
+               const struct spi_device_id *id;
+               char modalias[40];
+
+               /* skip the holes */
+               if (!has_second_chip)
+                       i *= 2;
+
+               nor = &q->nor[i];
+               mtd = &q->mtd[i];
+
+               nor->mtd = mtd;
+               nor->dev = dev;
+               nor->priv = q;
+               mtd->priv = nor;
+
+               /* fill the hooks */
+               nor->read_reg = fsl_qspi_read_reg;
+               nor->write_reg = fsl_qspi_write_reg;
+               nor->read = fsl_qspi_read;
+               nor->write = fsl_qspi_write;
+               nor->erase = fsl_qspi_erase;
+
+               nor->prepare = fsl_qspi_prep;
+               nor->unprepare = fsl_qspi_unprep;
+
+               if (of_modalias_node(np, modalias, sizeof(modalias)) < 0)
+                       goto map_failed;
+
+               id = spi_nor_match_id(modalias);
+               if (!id)
+                       goto map_failed;
+
+               ret = of_property_read_u32(np, "spi-max-frequency",
+                               &q->clk_rate);
+               if (ret < 0)
+                       goto map_failed;
+
+               /* set the chip address for READID */
+               fsl_qspi_set_base_addr(q, nor);
+
+               ret = spi_nor_scan(nor, id, SPI_NOR_QUAD);
+               if (ret)
+                       goto map_failed;
+
+               ppdata.of_node = np;
+               ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+               if (ret)
+                       goto map_failed;
+
+               /* Set the correct NOR size now. */
+               if (q->nor_size == 0) {
+                       q->nor_size = mtd->size;
+
+                       /* Map the SPI NOR to accessiable address */
+                       fsl_qspi_set_map_addr(q);
+               }
+
+               /*
+                * The TX FIFO is 64 bytes in the Vybrid, but the Page Program
+                * may writes 265 bytes per time. The write is working in the
+                * unit of the TX FIFO, not in the unit of the SPI NOR's page
+                * size.
+                *
+                * So shrink the spi_nor->page_size if it is larger then the
+                * TX FIFO.
+                */
+               if (nor->page_size > q->devtype_data->txfifo)
+                       nor->page_size = q->devtype_data->txfifo;
+
+               i++;
+       }
+
+       /* finish the rest init. */
+       ret = fsl_qspi_nor_setup_last(q);
+       if (ret)
+               goto last_init_failed;
+
+       clk_disable(q->clk);
+       clk_disable(q->clk_en);
+       dev_info(dev, "QuadSPI SPI NOR flash driver\n");
+       return 0;
+
+last_init_failed:
+       for (i = 0; i < q->nor_num; i++)
+               mtd_device_unregister(&q->mtd[i]);
+
+irq_failed:
+       clk_disable_unprepare(q->clk);
+       clk_disable_unprepare(q->clk_en);
+map_failed:
+       dev_err(dev, "Freescale QuadSPI probe failed\n");
+       return ret;
+}
+
+static int fsl_qspi_remove(struct platform_device *pdev)
+{
+       struct fsl_qspi *q = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < q->nor_num; i++)
+               mtd_device_unregister(&q->mtd[i]);
+
+       /* disable the hardware */
+       writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+       writel(0x0, q->iobase + QUADSPI_RSER);
+
+       clk_unprepare(q->clk);
+       clk_unprepare(q->clk_en);
+       return 0;
+}
+
+static struct platform_driver fsl_qspi_driver = {
+       .driver = {
+               .name   = "fsl-quadspi",
+               .bus    = &platform_bus_type,
+               .owner  = THIS_MODULE,
+               .of_match_table = fsl_qspi_dt_ids,
+       },
+       .probe          = fsl_qspi_probe,
+       .remove         = fsl_qspi_remove,
+};
+module_platform_driver(fsl_qspi_driver);
+
+MODULE_DESCRIPTION("Freescale QuadSPI Controller Driver");
+MODULE_AUTHOR("Freescale Semiconductor Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
new file mode 100644 (file)
index 0000000..d6f44d5
--- /dev/null
@@ -0,0 +1,1107 @@
+/*
+ * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with
+ * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
+ *
+ * Copyright (C) 2005, Intec Automation Inc.
+ * Copyright (C) 2014, Freescale Semiconductor, Inc.
+ *
+ * This code 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/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/math64.h>
+
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of_platform.h>
+#include <linux/spi/flash.h>
+#include <linux/mtd/spi-nor.h>
+
+/* Define max times to check status register before we give up. */
+#define        MAX_READY_WAIT_JIFFIES  (40 * HZ) /* M25P16 specs 40s max chip erase */
+
+#define JEDEC_MFR(_jedec_id)   ((_jedec_id) >> 16)
+
+/*
+ * Read the status register, returning its value in the location
+ * Return the status register value.
+ * Returns negative if error occurred.
+ */
+static int read_sr(struct spi_nor *nor)
+{
+       int ret;
+       u8 val;
+
+       ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
+       if (ret < 0) {
+               pr_err("error %d reading SR\n", (int) ret);
+               return ret;
+       }
+
+       return val;
+}
+
+/*
+ * Read configuration register, returning its value in the
+ * location. Return the configuration register value.
+ * Returns negative if error occured.
+ */
+static int read_cr(struct spi_nor *nor)
+{
+       int ret;
+       u8 val;
+
+       ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1);
+       if (ret < 0) {
+               dev_err(nor->dev, "error %d reading CR\n", ret);
+               return ret;
+       }
+
+       return val;
+}
+
+/*
+ * Dummy Cycle calculation for different type of read.
+ * It can be used to support more commands with
+ * different dummy cycle requirements.
+ */
+static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+{
+       switch (nor->flash_read) {
+       case SPI_NOR_FAST:
+       case SPI_NOR_DUAL:
+       case SPI_NOR_QUAD:
+               return 1;
+       case SPI_NOR_NORMAL:
+               return 0;
+       }
+       return 0;
+}
+
+/*
+ * Write status register 1 byte
+ * Returns negative if error occurred.
+ */
+static inline int write_sr(struct spi_nor *nor, u8 val)
+{
+       nor->cmd_buf[0] = val;
+       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+}
+
+/*
+ * Set write enable latch with Write Enable command.
+ * Returns negative if error occurred.
+ */
+static inline int write_enable(struct spi_nor *nor)
+{
+       return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+}
+
+/*
+ * Send write disble instruction to the chip.
+ */
+static inline int write_disable(struct spi_nor *nor)
+{
+       return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
+}
+
+static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+{
+       return mtd->priv;
+}
+
+/* Enable/disable 4-byte addressing mode. */
+static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable)
+{
+       int status;
+       bool need_wren = false;
+       u8 cmd;
+
+       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(nor);
+
+               cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
+               status = nor->write_reg(nor, cmd, NULL, 0, 0);
+               if (need_wren)
+                       write_disable(nor);
+
+               return status;
+       default:
+               /* Spansion style */
+               nor->cmd_buf[0] = enable << 7;
+               return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0);
+       }
+}
+
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+       unsigned long deadline;
+       int sr;
+
+       deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+
+       do {
+               cond_resched();
+
+               sr = read_sr(nor);
+               if (sr < 0)
+                       break;
+               else if (!(sr & SR_WIP))
+                       return 0;
+       } while (!time_after_eq(jiffies, deadline));
+
+       return -ETIMEDOUT;
+}
+
+/*
+ * Service routine to read status register until ready, or timeout occurs.
+ * Returns non-zero if error.
+ */
+static int wait_till_ready(struct spi_nor *nor)
+{
+       return nor->wait_till_ready(nor);
+}
+
+/*
+ * Erase the whole flash memory
+ *
+ * Returns 0 if successful, non-zero otherwise.
+ */
+static int erase_chip(struct spi_nor *nor)
+{
+       int ret;
+
+       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10));
+
+       /* Wait until finished previous write command. */
+       ret = wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       /* Send write enable, then erase commands. */
+       write_enable(nor);
+
+       return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
+}
+
+static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       int ret = 0;
+
+       mutex_lock(&nor->lock);
+
+       if (nor->prepare) {
+               ret = nor->prepare(nor, ops);
+               if (ret) {
+                       dev_err(nor->dev, "failed in the preparation.\n");
+                       mutex_unlock(&nor->lock);
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       if (nor->unprepare)
+               nor->unprepare(nor, ops);
+       mutex_unlock(&nor->lock);
+}
+
+/*
+ * Erase an address range on the nor chip.  The address range may extend
+ * one or more erase sectors.  Return an error is there is a problem erasing.
+ */
+static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       u32 addr, len;
+       uint32_t rem;
+       int ret;
+
+       dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
+                       (long long)instr->len);
+
+       div_u64_rem(instr->len, mtd->erasesize, &rem);
+       if (rem)
+               return -EINVAL;
+
+       addr = instr->addr;
+       len = instr->len;
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE);
+       if (ret)
+               return ret;
+
+       /* whole-chip erase? */
+       if (len == mtd->size) {
+               if (erase_chip(nor)) {
+                       ret = -EIO;
+                       goto erase_err;
+               }
+
+       /* REVISIT in some cases we could speed up erasing large regions
+        * by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K.  We may have set up
+        * to use "small sector erase", but that's not always optimal.
+        */
+
+       /* "sector"-at-a-time erase */
+       } else {
+               while (len) {
+                       if (nor->erase(nor, addr)) {
+                               ret = -EIO;
+                               goto erase_err;
+                       }
+
+                       addr += mtd->erasesize;
+                       len -= mtd->erasesize;
+               }
+       }
+
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+
+       return ret;
+
+erase_err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+       instr->state = MTD_ERASE_FAILED;
+       return ret;
+}
+
+static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       uint32_t offset = ofs;
+       uint8_t status_old, status_new;
+       int ret = 0;
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
+       if (ret)
+               return ret;
+
+       /* Wait until finished previous command */
+       ret = wait_till_ready(nor);
+       if (ret)
+               goto err;
+
+       status_old = read_sr(nor);
+
+       if (offset < mtd->size - (mtd->size / 2))
+               status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
+       else if (offset < mtd->size - (mtd->size / 4))
+               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+       else if (offset < mtd->size - (mtd->size / 8))
+               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+       else if (offset < mtd->size - (mtd->size / 16))
+               status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
+       else if (offset < mtd->size - (mtd->size / 32))
+               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+       else if (offset < mtd->size - (mtd->size / 64))
+               status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
+       else
+               status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
+
+       /* Only modify protection if it will not unlock other areas */
+       if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) >
+                               (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
+               write_enable(nor);
+               ret = write_sr(nor, status_new);
+               if (ret)
+                       goto err;
+       }
+
+err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+       return ret;
+}
+
+static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       uint32_t offset = ofs;
+       uint8_t status_old, status_new;
+       int ret = 0;
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
+       if (ret)
+               return ret;
+
+       /* Wait until finished previous command */
+       ret = wait_till_ready(nor);
+       if (ret)
+               goto err;
+
+       status_old = read_sr(nor);
+
+       if (offset+len > mtd->size - (mtd->size / 64))
+               status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0);
+       else if (offset+len > mtd->size - (mtd->size / 32))
+               status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
+       else if (offset+len > mtd->size - (mtd->size / 16))
+               status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
+       else if (offset+len > mtd->size - (mtd->size / 8))
+               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+       else if (offset+len > mtd->size - (mtd->size / 4))
+               status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
+       else if (offset+len > mtd->size - (mtd->size / 2))
+               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+       else
+               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+
+       /* Only modify protection if it will not lock other areas */
+       if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) <
+                               (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
+               write_enable(nor);
+               ret = write_sr(nor, status_new);
+               if (ret)
+                       goto err;
+       }
+
+err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
+       return ret;
+}
+
+struct flash_info {
+       /* JEDEC id zero means "no ID" (most older chips); otherwise it has
+        * a high byte of zero plus three data bytes: the manufacturer id,
+        * then a two byte device id.
+        */
+       u32             jedec_id;
+       u16             ext_id;
+
+       /* The size listed here is what works with SPINOR_OP_SE, which isn't
+        * necessarily called a "sector" by the vendor.
+        */
+       unsigned        sector_size;
+       u16             n_sectors;
+
+       u16             page_size;
+       u16             addr_width;
+
+       u16             flags;
+#define        SECT_4K                 0x01    /* SPINOR_OP_BE_4K works uniformly */
+#define        SPI_NOR_NO_ERASE        0x02    /* No erase command needed */
+#define        SST_WRITE               0x04    /* use SST byte programming */
+#define        SPI_NOR_NO_FR           0x08    /* Can't do fastread */
+#define        SECT_4K_PMC             0x10    /* SPINOR_OP_BE_4K_PMC works uniformly */
+#define        SPI_NOR_DUAL_READ       0x20    /* Flash supports Dual Read */
+#define        SPI_NOR_QUAD_READ       0x40    /* Flash supports Quad Read */
+};
+
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
+       ((kernel_ulong_t)&(struct flash_info) {                         \
+               .jedec_id = (_jedec_id),                                \
+               .ext_id = (_ext_id),                                    \
+               .sector_size = (_sector_size),                          \
+               .n_sectors = (_n_sectors),                              \
+               .page_size = 256,                                       \
+               .flags = (_flags),                                      \
+       })
+
+#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 = (_flags),                                      \
+       })
+
+/* NOTE: double check command sets and memory organization when you add
+ * more nor chips.  This current list focusses on newer chips, which
+ * have been converging on command sets which including JEDEC ID.
+ */
+const struct spi_device_id spi_nor_ids[] = {
+       /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+       { "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
+       { "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
+
+       { "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
+       { "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
+       { "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
+
+       { "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) },
+       { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
+       { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
+       { "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
+
+       { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
+
+       /* EON -- en25xxx */
+       { "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
+       { "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
+       { "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
+       { "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
+       { "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
+       { "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
+
+       /* ESMT */
+       { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
+
+       /* Everspin */
+       { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+
+       /* GigaDevice */
+       { "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
+       { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
+
+       /* Intel/Numonyx -- xxxs33b */
+       { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
+       { "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
+       { "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+
+       /* Macronix */
+       { "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
+       { "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
+       { "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
+       { "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
+       { "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
+       { "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
+       { "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
+       { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+       { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+       { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+       { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
+
+       /* Micron */
+       { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 0) },
+       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, 0) },
+       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 0) },
+       { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K) },
+       { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, 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).
+        */
+       { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, 0) },
+       { "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
+       { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
+       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
+       { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
+       { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
+       { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
+       { "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
+       { "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
+       { "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
+       { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
+       { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
+       { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
+       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
+       { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
+       { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
+
+       /* SST -- large erase sizes are "overlays", "sectors" are 4K */
+       { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
+       { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
+       { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
+       { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
+       { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
+       { "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
+       { "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
+       { "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
+       { "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
+
+       /* ST Microelectronics -- newer production may have feature updates */
+       { "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
+       { "m25p10",  INFO(0x202011,  0,  32 * 1024,   4, 0) },
+       { "m25p20",  INFO(0x202012,  0,  64 * 1024,   4, 0) },
+       { "m25p40",  INFO(0x202013,  0,  64 * 1024,   8, 0) },
+       { "m25p80",  INFO(0x202014,  0,  64 * 1024,  16, 0) },
+       { "m25p16",  INFO(0x202015,  0,  64 * 1024,  32, 0) },
+       { "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 0) },
+       { "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
+       { "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
+       { "n25q032", INFO(0x20ba16,  0,  64 * 1024,  64, 0) },
+
+       { "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
+       { "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
+       { "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4, 0) },
+       { "m25p40-nonjedec",  INFO(0, 0,  64 * 1024,   8, 0) },
+       { "m25p80-nonjedec",  INFO(0, 0,  64 * 1024,  16, 0) },
+       { "m25p16-nonjedec",  INFO(0, 0,  64 * 1024,  32, 0) },
+       { "m25p32-nonjedec",  INFO(0, 0,  64 * 1024,  64, 0) },
+       { "m25p64-nonjedec",  INFO(0, 0,  64 * 1024, 128, 0) },
+       { "m25p128-nonjedec", INFO(0, 0, 256 * 1024,  64, 0) },
+
+       { "m45pe10", INFO(0x204011,  0, 64 * 1024,    2, 0) },
+       { "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 0) },
+       { "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 0) },
+
+       { "m25pe20", INFO(0x208012,  0, 64 * 1024,  4,       0) },
+       { "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
+       { "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
+
+       { "m25px16",    INFO(0x207115,  0, 64 * 1024, 32, SECT_4K) },
+       { "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, SECT_4K) },
+       { "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, SECT_4K) },
+       { "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, SECT_4K) },
+       { "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
+
+       /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+       { "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
+       { "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
+       { "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
+       { "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
+       { "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
+       { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
+       { "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
+       { "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, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "cat25c03", CAT25_INFO(  32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+       { },
+};
+EXPORT_SYMBOL_GPL(spi_nor_ids);
+
+static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
+{
+       int                     tmp;
+       u8                      id[5];
+       u32                     jedec;
+       u16                     ext_jedec;
+       struct flash_info       *info;
+
+       tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, 5);
+       if (tmp < 0) {
+               dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
+               return ERR_PTR(tmp);
+       }
+       jedec = id[0];
+       jedec = jedec << 8;
+       jedec |= id[1];
+       jedec = jedec << 8;
+       jedec |= id[2];
+
+       ext_jedec = id[3] << 8 | id[4];
+
+       for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+               info = (void *)spi_nor_ids[tmp].driver_data;
+               if (info->jedec_id == jedec) {
+                       if (info->ext_id == 0 || info->ext_id == ext_jedec)
+                               return &spi_nor_ids[tmp];
+               }
+       }
+       dev_err(nor->dev, "unrecognized JEDEC id %06x\n", jedec);
+       return ERR_PTR(-ENODEV);
+}
+
+static const struct spi_device_id *jedec_probe(struct spi_nor *nor)
+{
+       return nor->read_id(nor);
+}
+
+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       int ret;
+
+       dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+       if (ret)
+               return ret;
+
+       ret = nor->read(nor, from, len, retlen, buf);
+
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+       return ret;
+}
+
+static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+               size_t *retlen, const u_char *buf)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       size_t actual;
+       int ret;
+
+       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
+       if (ret)
+               return ret;
+
+       /* Wait until finished previous write command. */
+       ret = wait_till_ready(nor);
+       if (ret)
+               goto time_out;
+
+       write_enable(nor);
+
+       nor->sst_write_second = false;
+
+       actual = to % 2;
+       /* Start write from odd address. */
+       if (actual) {
+               nor->program_opcode = SPINOR_OP_BP;
+
+               /* write one byte. */
+               nor->write(nor, to, 1, retlen, buf);
+               ret = wait_till_ready(nor);
+               if (ret)
+                       goto time_out;
+       }
+       to += actual;
+
+       /* Write out most of the data here. */
+       for (; actual < len - 1; actual += 2) {
+               nor->program_opcode = SPINOR_OP_AAI_WP;
+
+               /* write two bytes. */
+               nor->write(nor, to, 2, retlen, buf + actual);
+               ret = wait_till_ready(nor);
+               if (ret)
+                       goto time_out;
+               to += 2;
+               nor->sst_write_second = true;
+       }
+       nor->sst_write_second = false;
+
+       write_disable(nor);
+       ret = wait_till_ready(nor);
+       if (ret)
+               goto time_out;
+
+       /* Write out trailing byte if it exists. */
+       if (actual != len) {
+               write_enable(nor);
+
+               nor->program_opcode = SPINOR_OP_BP;
+               nor->write(nor, to, 1, retlen, buf + actual);
+
+               ret = wait_till_ready(nor);
+               if (ret)
+                       goto time_out;
+               write_disable(nor);
+       }
+time_out:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return ret;
+}
+
+/*
+ * Write an address range to the nor chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
+ */
+static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       u32 page_offset, page_size, i;
+       int ret;
+
+       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
+       if (ret)
+               return ret;
+
+       /* Wait until finished previous write command. */
+       ret = wait_till_ready(nor);
+       if (ret)
+               goto write_err;
+
+       write_enable(nor);
+
+       page_offset = to & (nor->page_size - 1);
+
+       /* do all the bytes fit onto one page? */
+       if (page_offset + len <= nor->page_size) {
+               nor->write(nor, to, len, retlen, buf);
+       } else {
+               /* the size of data remaining on the first page */
+               page_size = nor->page_size - page_offset;
+               nor->write(nor, to, page_size, retlen, buf);
+
+               /* write everything in nor->page_size chunks */
+               for (i = page_size; i < len; i += page_size) {
+                       page_size = len - i;
+                       if (page_size > nor->page_size)
+                               page_size = nor->page_size;
+
+                       wait_till_ready(nor);
+                       write_enable(nor);
+
+                       nor->write(nor, to + i, page_size, retlen, buf + i);
+               }
+       }
+
+write_err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return 0;
+}
+
+static int macronix_quad_enable(struct spi_nor *nor)
+{
+       int ret, val;
+
+       val = read_sr(nor);
+       write_enable(nor);
+
+       nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
+       nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+
+       if (wait_till_ready(nor))
+               return 1;
+
+       ret = read_sr(nor);
+       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
+               dev_err(nor->dev, "Macronix Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Write status Register and configuration register with 2 bytes
+ * The first byte will be written to the status register, while the
+ * second byte will be written to the configuration register.
+ * Return negative if error occured.
+ */
+static int write_sr_cr(struct spi_nor *nor, u16 val)
+{
+       nor->cmd_buf[0] = val & 0xff;
+       nor->cmd_buf[1] = (val >> 8);
+
+       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
+}
+
+static int spansion_quad_enable(struct spi_nor *nor)
+{
+       int ret;
+       int quad_en = CR_QUAD_EN_SPAN << 8;
+
+       write_enable(nor);
+
+       ret = write_sr_cr(nor, quad_en);
+       if (ret < 0) {
+               dev_err(nor->dev,
+                       "error while writing configuration register\n");
+               return -EINVAL;
+       }
+
+       /* read back and check it */
+       ret = read_cr(nor);
+       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+               dev_err(nor->dev, "Spansion Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
+{
+       int status;
+
+       switch (JEDEC_MFR(jedec_id)) {
+       case CFI_MFR_MACRONIX:
+               status = macronix_quad_enable(nor);
+               if (status) {
+                       dev_err(nor->dev, "Macronix quad-read not enabled\n");
+                       return -EINVAL;
+               }
+               return status;
+       default:
+               status = spansion_quad_enable(nor);
+               if (status) {
+                       dev_err(nor->dev, "Spansion quad-read not enabled\n");
+                       return -EINVAL;
+               }
+               return status;
+       }
+}
+
+static int spi_nor_check(struct spi_nor *nor)
+{
+       if (!nor->dev || !nor->read || !nor->write ||
+               !nor->read_reg || !nor->write_reg || !nor->erase) {
+               pr_err("spi-nor: please fill all the necessary fields!\n");
+               return -EINVAL;
+       }
+
+       if (!nor->read_id)
+               nor->read_id = spi_nor_read_id;
+       if (!nor->wait_till_ready)
+               nor->wait_till_ready = spi_nor_wait_till_ready;
+
+       return 0;
+}
+
+int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
+                       enum read_mode mode)
+{
+       struct flash_info               *info;
+       struct flash_platform_data      *data;
+       struct device *dev = nor->dev;
+       struct mtd_info *mtd = nor->mtd;
+       struct device_node *np = dev->of_node;
+       int ret;
+       int i;
+
+       ret = spi_nor_check(nor);
+       if (ret)
+               return ret;
+
+       /* Platform data helps sort out which chip type we have, as
+        * well as how this board partitions it.  If we don't have
+        * 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 = dev_get_platdata(dev);
+       if (data && data->type) {
+               const struct spi_device_id *plat_id;
+
+               for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) {
+                       plat_id = &spi_nor_ids[i];
+                       if (strcmp(data->type, plat_id->name))
+                               continue;
+                       break;
+               }
+
+               if (i < ARRAY_SIZE(spi_nor_ids) - 1)
+                       id = plat_id;
+               else
+                       dev_warn(dev, "unrecognized id %s\n", data->type);
+       }
+
+       info = (void *)id->driver_data;
+
+       if (info->jedec_id) {
+               const struct spi_device_id *jid;
+
+               jid = jedec_probe(nor);
+               if (IS_ERR(jid)) {
+                       return PTR_ERR(jid);
+               } else if (jid != id) {
+                       /*
+                        * JEDEC knows better, so overwrite platform ID. We
+                        * can't trust partitions any longer, but we'll let
+                        * mtd apply them anyway, since some partitions may be
+                        * marked read-only, and we don't want to lose that
+                        * information, even if it's not 100% accurate.
+                        */
+                       dev_warn(dev, "found %s, expected %s\n",
+                                jid->name, id->name);
+                       id = jid;
+                       info = (void *)jid->driver_data;
+               }
+       }
+
+       mutex_init(&nor->lock);
+
+       /*
+        * Atmel, SST and Intel/Numonyx serial nor tend to power
+        * up with the software protection bits set
+        */
+
+       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL ||
+           JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL ||
+           JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) {
+               write_enable(nor);
+               write_sr(nor, 0);
+       }
+
+       if (data && data->name)
+               mtd->name = data->name;
+       else
+               mtd->name = dev_name(dev);
+
+       mtd->type = MTD_NORFLASH;
+       mtd->writesize = 1;
+       mtd->flags = MTD_CAP_NORFLASH;
+       mtd->size = info->sector_size * info->n_sectors;
+       mtd->_erase = spi_nor_erase;
+       mtd->_read = spi_nor_read;
+
+       /* nor protection support for STmicro chips */
+       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
+               mtd->_lock = spi_nor_lock;
+               mtd->_unlock = spi_nor_unlock;
+       }
+
+       /* sst nor chips use AAI word program */
+       if (info->flags & SST_WRITE)
+               mtd->_write = sst_write;
+       else
+               mtd->_write = spi_nor_write;
+
+       /* prefer "small sector" erase if possible */
+       if (info->flags & SECT_4K) {
+               nor->erase_opcode = SPINOR_OP_BE_4K;
+               mtd->erasesize = 4096;
+       } else if (info->flags & SECT_4K_PMC) {
+               nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
+               mtd->erasesize = 4096;
+       } else {
+               nor->erase_opcode = SPINOR_OP_SE;
+               mtd->erasesize = info->sector_size;
+       }
+
+       if (info->flags & SPI_NOR_NO_ERASE)
+               mtd->flags |= MTD_NO_ERASE;
+
+       mtd->dev.parent = dev;
+       nor->page_size = info->page_size;
+       mtd->writebufsize = nor->page_size;
+
+       if (np) {
+               /* If we were instantiated by DT, use it */
+               if (of_property_read_bool(np, "m25p,fast-read"))
+                       nor->flash_read = SPI_NOR_FAST;
+               else
+                       nor->flash_read = SPI_NOR_NORMAL;
+       } else {
+               /* If we weren't instantiated by DT, default to fast-read */
+               nor->flash_read = SPI_NOR_FAST;
+       }
+
+       /* Some devices cannot do fast-read, no matter what DT tells us */
+       if (info->flags & SPI_NOR_NO_FR)
+               nor->flash_read = SPI_NOR_NORMAL;
+
+       /* Quad/Dual-read mode takes precedence over fast/normal */
+       if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+               ret = set_quad_mode(nor, info->jedec_id);
+               if (ret) {
+                       dev_err(dev, "quad mode not supported\n");
+                       return ret;
+               }
+               nor->flash_read = SPI_NOR_QUAD;
+       } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
+               nor->flash_read = SPI_NOR_DUAL;
+       }
+
+       /* Default commands */
+       switch (nor->flash_read) {
+       case SPI_NOR_QUAD:
+               nor->read_opcode = SPINOR_OP_READ_1_1_4;
+               break;
+       case SPI_NOR_DUAL:
+               nor->read_opcode = SPINOR_OP_READ_1_1_2;
+               break;
+       case SPI_NOR_FAST:
+               nor->read_opcode = SPINOR_OP_READ_FAST;
+               break;
+       case SPI_NOR_NORMAL:
+               nor->read_opcode = SPINOR_OP_READ;
+               break;
+       default:
+               dev_err(dev, "No Read opcode defined\n");
+               return -EINVAL;
+       }
+
+       nor->program_opcode = SPINOR_OP_PP;
+
+       if (info->addr_width)
+               nor->addr_width = info->addr_width;
+       else if (mtd->size > 0x1000000) {
+               /* enable 4-byte addressing if the device exceeds 16MiB */
+               nor->addr_width = 4;
+               if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
+                       /* Dedicated 4-byte command set */
+                       switch (nor->flash_read) {
+                       case SPI_NOR_QUAD:
+                               nor->read_opcode = SPINOR_OP_READ4_1_1_4;
+                               break;
+                       case SPI_NOR_DUAL:
+                               nor->read_opcode = SPINOR_OP_READ4_1_1_2;
+                               break;
+                       case SPI_NOR_FAST:
+                               nor->read_opcode = SPINOR_OP_READ4_FAST;
+                               break;
+                       case SPI_NOR_NORMAL:
+                               nor->read_opcode = SPINOR_OP_READ4;
+                               break;
+                       }
+                       nor->program_opcode = SPINOR_OP_PP_4B;
+                       /* No small sector erase for 4-byte command set */
+                       nor->erase_opcode = SPINOR_OP_SE_4B;
+                       mtd->erasesize = info->sector_size;
+               } else
+                       set_4byte(nor, info->jedec_id, 1);
+       } else {
+               nor->addr_width = 3;
+       }
+
+       nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+
+       dev_info(dev, "%s (%lld Kbytes)\n", id->name,
+                       (long long)mtd->size >> 10);
+
+       dev_dbg(dev,
+               "mtd .name = %s, .size = 0x%llx (%lldMiB), "
+               ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
+               mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20),
+               mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions);
+
+       if (mtd->numeraseregions)
+               for (i = 0; i < mtd->numeraseregions; i++)
+                       dev_dbg(dev,
+                               "mtd.eraseregions[%d] = { .offset = 0x%llx, "
+                               ".erasesize = 0x%.8x (%uKiB), "
+                               ".numblocks = %d }\n",
+                               i, (long long)mtd->eraseregions[i].offset,
+                               mtd->eraseregions[i].erasesize,
+                               mtd->eraseregions[i].erasesize / 1024,
+                               mtd->eraseregions[i].numblocks);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spi_nor_scan);
+
+const struct spi_device_id *spi_nor_match_id(char *name)
+{
+       const struct spi_device_id *id = spi_nor_ids;
+
+       while (id->name[0]) {
+               if (!strcmp(name, id->name))
+                       return id;
+               id++;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_nor_match_id);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>");
+MODULE_AUTHOR("Mike Lavender");
+MODULE_DESCRIPTION("framework for SPI NOR");
index 2e9e2d11f204aa8db90d775743778ce5719443e4..f19ab1acde1f22dedaf700e5dd8919bebf33f2c4 100644 (file)
@@ -69,8 +69,8 @@ static int write_eraseblock(int ebnum)
        int err = 0;
        loff_t addr = ebnum * mtd->erasesize;
 
+       prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
        for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
-               prandom_bytes_state(&rnd_state, writebuf, use_len);
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
@@ -78,7 +78,7 @@ static int write_eraseblock(int ebnum)
                ops.oobretlen = 0;
                ops.ooboffs   = use_offset;
                ops.datbuf    = NULL;
-               ops.oobbuf    = writebuf;
+               ops.oobbuf    = writebuf + (use_len_max * i) + use_offset;
                err = mtd_write_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
                        pr_err("error: writeoob failed at %#llx\n",
@@ -122,8 +122,8 @@ static int verify_eraseblock(int ebnum)
        int err = 0;
        loff_t addr = ebnum * mtd->erasesize;
 
+       prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
        for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
-               prandom_bytes_state(&rnd_state, writebuf, use_len);
                ops.mode      = MTD_OPS_AUTO_OOB;
                ops.len       = 0;
                ops.retlen    = 0;
@@ -139,7 +139,8 @@ static int verify_eraseblock(int ebnum)
                        errcnt += 1;
                        return err ? err : -1;
                }
-               if (memcmp(readbuf, writebuf, use_len)) {
+               if (memcmp(readbuf, writebuf + (use_len_max * i) + use_offset,
+                          use_len)) {
                        pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
@@ -166,7 +167,9 @@ static int verify_eraseblock(int ebnum)
                                errcnt += 1;
                                return err ? err : -1;
                        }
-                       if (memcmp(readbuf + use_offset, writebuf, use_len)) {
+                       if (memcmp(readbuf + use_offset,
+                                  writebuf + (use_len_max * i) + use_offset,
+                                  use_len)) {
                                pr_err("error: verify failed at %#llx\n",
                                                (long long)addr);
                                errcnt += 1;
@@ -566,8 +569,8 @@ static int __init mtd_oobtest_init(void)
                if (bbt[i] || bbt[i + 1])
                        continue;
                addr = (i + 1) * mtd->erasesize - mtd->writesize;
+               prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
                for (pg = 0; pg < cnt; ++pg) {
-                       prandom_bytes_state(&rnd_state, writebuf, sz);
                        ops.mode      = MTD_OPS_AUTO_OOB;
                        ops.len       = 0;
                        ops.retlen    = 0;
@@ -575,7 +578,7 @@ static int __init mtd_oobtest_init(void)
                        ops.oobretlen = 0;
                        ops.ooboffs   = 0;
                        ops.datbuf    = NULL;
-                       ops.oobbuf    = writebuf;
+                       ops.oobbuf    = writebuf + pg * sz;
                        err = mtd_write_oob(mtd, addr, &ops);
                        if (err)
                                goto out;
index 7ff473c871a9a249bd02007c2176ec5c471d7626..20a667c95da4b86e2076dec801d5e0770f88bf3f 100644 (file)
@@ -253,7 +253,7 @@ static int do_ubiblock_request(struct ubiblock *dev, struct request *req)
         * flash access anyway.
         */
        mutex_lock(&dev->dev_mutex);
-       ret = ubiblock_read(dev, req->buffer, sec, len);
+       ret = ubiblock_read(dev, bio_data(req->bio), sec, len);
        mutex_unlock(&dev->dev_mutex);
 
        return ret;
@@ -431,7 +431,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
         * Create one workqueue per volume (per registered block device).
         * Rembember workqueues are cheap, they're not threads.
         */
-       dev->wq = alloc_workqueue(gd->disk_name, 0, 0);
+       dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name);
        if (!dev->wq)
                goto out_free_queue;
        INIT_WORK(&dev->work, ubiblock_do_work);
index 02317c1c02385914c94175fa8757089c677e2b94..0f3425dac91046300f93587d4f341e080c98e322 100644 (file)
@@ -671,6 +671,8 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
 
        e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
        self_check_in_wl_tree(ubi, e, &ubi->free);
+       ubi->free_count--;
+       ubi_assert(ubi->free_count >= 0);
        rb_erase(&e->u.rb, &ubi->free);
 
        return e;
@@ -684,6 +686,9 @@ int ubi_wl_get_peb(struct ubi_device *ubi)
        peb = __wl_get_peb(ubi);
        spin_unlock(&ubi->wl_lock);
 
+       if (peb < 0)
+               return peb;
+
        err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset,
                                    ubi->peb_size - ubi->vid_hdr_aloffset);
        if (err) {
@@ -1068,6 +1073,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
 
                        /* Give the unused PEB back */
                        wl_tree_add(e2, &ubi->free);
+                       ubi->free_count++;
                        goto out_cancel;
                }
                self_check_in_wl_tree(ubi, e1, &ubi->used);
index b667a51ed21517a3ee6cf2be6ab4c7e306a713a2..9a0d61e0c188a9f37f51ff2f4520ef34749f1497 100644 (file)
@@ -2440,7 +2440,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
                goto err_free;
        }
 
-       slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg);
+       slave_agg_no = bond_xmit_hash(bond, skb) % slaves_in_agg;
        first_ok_slave = NULL;
 
        bond_for_each_slave_rcu(bond, slave, iter) {
index 9f69e818b0009db7881b3f8c862393836e5a604b..70de039dad2e09783887ec1b5e82265c26db993f 100644 (file)
@@ -1347,6 +1347,77 @@ void bond_alb_deinitialize(struct bonding *bond)
                rlb_deinitialize(bond);
 }
 
+static int bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
+               struct slave *tx_slave)
+{
+       struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+       struct ethhdr *eth_data = eth_hdr(skb);
+
+       if (!tx_slave) {
+               /* unbalanced or unassigned, send through primary */
+               tx_slave = rcu_dereference(bond->curr_active_slave);
+               if (bond->params.tlb_dynamic_lb)
+                       bond_info->unbalanced_load += skb->len;
+       }
+
+       if (tx_slave && SLAVE_IS_OK(tx_slave)) {
+               if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
+                       ether_addr_copy(eth_data->h_source,
+                                       tx_slave->dev->dev_addr);
+               }
+
+               bond_dev_queue_xmit(bond, skb, tx_slave->dev);
+               goto out;
+       }
+
+       if (tx_slave && bond->params.tlb_dynamic_lb) {
+               _lock_tx_hashtbl(bond);
+               __tlb_clear_slave(bond, tx_slave, 0);
+               _unlock_tx_hashtbl(bond);
+       }
+
+       /* no suitable interface, frame not sent */
+       dev_kfree_skb_any(skb);
+out:
+       return NETDEV_TX_OK;
+}
+
+int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       struct ethhdr *eth_data;
+       struct slave *tx_slave = NULL;
+       u32 hash_index;
+
+       skb_reset_mac_header(skb);
+       eth_data = eth_hdr(skb);
+
+       /* Do not TX balance any multicast or broadcast */
+       if (!is_multicast_ether_addr(eth_data->h_dest)) {
+               switch (skb->protocol) {
+               case htons(ETH_P_IP):
+               case htons(ETH_P_IPX):
+                   /* In case of IPX, it will falback to L2 hash */
+               case htons(ETH_P_IPV6):
+                       hash_index = bond_xmit_hash(bond, skb);
+                       if (bond->params.tlb_dynamic_lb) {
+                               tx_slave = tlb_choose_channel(bond,
+                                                             hash_index & 0xFF,
+                                                             skb->len);
+                       } else {
+                               struct list_head *iter;
+                               int idx = hash_index % bond->slave_cnt;
+
+                               bond_for_each_slave_rcu(bond, tx_slave, iter)
+                                       if (--idx < 0)
+                                               break;
+                       }
+                       break;
+               }
+       }
+       return bond_do_alb_xmit(skb, bond, tx_slave);
+}
+
 int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
@@ -1355,7 +1426,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
        struct slave *tx_slave = NULL;
        static const __be32 ip_bcast = htonl(0xffffffff);
        int hash_size = 0;
-       int do_tx_balance = 1;
+       bool do_tx_balance = true;
        u32 hash_index = 0;
        const u8 *hash_start = NULL;
        struct ipv6hdr *ip6hdr;
@@ -1370,7 +1441,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast) ||
                    (iph->daddr == ip_bcast) ||
                    (iph->protocol == IPPROTO_IGMP)) {
-                       do_tx_balance = 0;
+                       do_tx_balance = false;
                        break;
                }
                hash_start = (char *)&(iph->daddr);
@@ -1382,7 +1453,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                 * that here just in case.
                 */
                if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast)) {
-                       do_tx_balance = 0;
+                       do_tx_balance = false;
                        break;
                }
 
@@ -1390,7 +1461,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                 * broadcasts in IPv4.
                 */
                if (ether_addr_equal_64bits(eth_data->h_dest, mac_v6_allmcast)) {
-                       do_tx_balance = 0;
+                       do_tx_balance = false;
                        break;
                }
 
@@ -1400,7 +1471,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                 */
                ip6hdr = ipv6_hdr(skb);
                if (ipv6_addr_any(&ip6hdr->saddr)) {
-                       do_tx_balance = 0;
+                       do_tx_balance = false;
                        break;
                }
 
@@ -1410,7 +1481,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
        case ETH_P_IPX:
                if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
                        /* something is wrong with this packet */
-                       do_tx_balance = 0;
+                       do_tx_balance = false;
                        break;
                }
 
@@ -1419,7 +1490,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                         * this family since it has an "ARP" like
                         * mechanism
                         */
-                       do_tx_balance = 0;
+                       do_tx_balance = false;
                        break;
                }
 
@@ -1427,12 +1498,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                hash_size = ETH_ALEN;
                break;
        case ETH_P_ARP:
-               do_tx_balance = 0;
+               do_tx_balance = false;
                if (bond_info->rlb_enabled)
                        tx_slave = rlb_arp_xmit(skb, bond);
                break;
        default:
-               do_tx_balance = 0;
+               do_tx_balance = false;
                break;
        }
 
@@ -1441,32 +1512,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                tx_slave = tlb_choose_channel(bond, hash_index, skb->len);
        }
 
-       if (!tx_slave) {
-               /* unbalanced or unassigned, send through primary */
-               tx_slave = rcu_dereference(bond->curr_active_slave);
-               bond_info->unbalanced_load += skb->len;
-       }
-
-       if (tx_slave && SLAVE_IS_OK(tx_slave)) {
-               if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
-                       ether_addr_copy(eth_data->h_source,
-                                       tx_slave->dev->dev_addr);
-               }
-
-               bond_dev_queue_xmit(bond, skb, tx_slave->dev);
-               goto out;
-       }
-
-       if (tx_slave) {
-               _lock_tx_hashtbl(bond);
-               __tlb_clear_slave(bond, tx_slave, 0);
-               _unlock_tx_hashtbl(bond);
-       }
-
-       /* no suitable interface, frame not sent */
-       dev_kfree_skb_any(skb);
-out:
-       return NETDEV_TX_OK;
+       return bond_do_alb_xmit(skb, bond, tx_slave);
 }
 
 void bond_alb_monitor(struct work_struct *work)
index e09dd4bfafffcf585b8f853f7661e2e416c58602..5fc76c01636cb6eb0e9e96d14fc0c79566741900 100644 (file)
@@ -175,6 +175,7 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave);
 void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
 void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
 int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
+int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
 void bond_alb_monitor(struct work_struct *);
 int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
 void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
index 69aff72c895716fe6c579d2bf7f46c79ddca2a36..9d08e007d85309a86be139e8e9b39cc36cfcd7b0 100644 (file)
@@ -3015,20 +3015,18 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
  * bond_xmit_hash - generate a hash value based on the xmit policy
  * @bond: bonding device
  * @skb: buffer to use for headers
- * @count: modulo value
  *
  * This function will extract the necessary headers from the skb buffer and use
  * them to generate a hash based on the xmit_policy set in the bonding device
- * which will be reduced modulo count before returning.
  */
-int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count)
+u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
 {
        struct flow_keys flow;
        u32 hash;
 
        if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 ||
            !bond_flow_dissect(bond, skb, &flow))
-               return bond_eth_hash(skb) % count;
+               return bond_eth_hash(skb);
 
        if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 ||
            bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23)
@@ -3039,7 +3037,7 @@ int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count)
        hash ^= (hash >> 16);
        hash ^= (hash >> 8);
 
-       return hash % count;
+       return hash;
 }
 
 /*-------------------------- Device entry points ----------------------------*/
@@ -3098,7 +3096,8 @@ static int bond_open(struct net_device *bond_dev)
                 */
                if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB)))
                        return -ENOMEM;
-               queue_delayed_work(bond->wq, &bond->alb_work, 0);
+               if (bond->params.tlb_dynamic_lb)
+                       queue_delayed_work(bond->wq, &bond->alb_work, 0);
        }
 
        if (bond->params.miimon)  /* link check interval, in milliseconds. */
@@ -3666,7 +3665,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
 
-       bond_xmit_slave_id(bond, skb, bond_xmit_hash(bond, skb, bond->slave_cnt));
+       bond_xmit_slave_id(bond, skb, bond_xmit_hash(bond, skb) % bond->slave_cnt);
 
        return NETDEV_TX_OK;
 }
@@ -3776,8 +3775,9 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
        case BOND_MODE_8023AD:
                return bond_3ad_xmit_xor(skb, dev);
        case BOND_MODE_ALB:
-       case BOND_MODE_TLB:
                return bond_alb_xmit(skb, dev);
+       case BOND_MODE_TLB:
+               return bond_tlb_xmit(skb, dev);
        default:
                /* Should never happen, mode already checked */
                pr_err("%s: Error: Unknown bonding mode %d\n",
@@ -3998,7 +3998,8 @@ static int bond_check_params(struct bond_params *params)
 
        if (xmit_hash_policy) {
                if ((bond_mode != BOND_MODE_XOR) &&
-                   (bond_mode != BOND_MODE_8023AD)) {
+                   (bond_mode != BOND_MODE_8023AD) &&
+                   (bond_mode != BOND_MODE_TLB)) {
                        pr_info("xmit_hash_policy param is irrelevant in mode %s\n",
                                bond_mode_name(bond_mode));
                } else {
@@ -4304,6 +4305,7 @@ static int bond_check_params(struct bond_params *params)
        params->min_links = min_links;
        params->lp_interval = lp_interval;
        params->packets_per_slave = packets_per_slave;
+       params->tlb_dynamic_lb = 1; /* Default value */
        if (packets_per_slave > 0) {
                params->reciprocal_packets_per_slave =
                        reciprocal_value(packets_per_slave);
index 724e30fa20b9fa70166b5d9b25ed9029fab6db73..9fba7a1e6d51ead234de9d1468fe6c094971ccfb 100644 (file)
@@ -70,6 +70,8 @@ static int bond_option_mode_set(struct bonding *bond,
                                const struct bond_opt_value *newval);
 static int bond_option_slaves_set(struct bonding *bond,
                                  const struct bond_opt_value *newval);
+static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval);
 
 
 static const struct bond_opt_value bond_mode_tbl[] = {
@@ -179,6 +181,12 @@ static const struct bond_opt_value bond_lp_interval_tbl[] = {
        { NULL,      -1,      0},
 };
 
+static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
+       { "off", 0,  0},
+       { "on",  1,  BOND_VALFLAG_DEFAULT},
+       { NULL,  -1, 0}
+};
+
 static const struct bond_option bond_opts[] = {
        [BOND_OPT_MODE] = {
                .id = BOND_OPT_MODE,
@@ -199,7 +207,7 @@ static const struct bond_option bond_opts[] = {
        [BOND_OPT_XMIT_HASH] = {
                .id = BOND_OPT_XMIT_HASH,
                .name = "xmit_hash_policy",
-               .desc = "balance-xor and 802.3ad hashing method",
+               .desc = "balance-xor, 802.3ad, and tlb hashing method",
                .values = bond_xmit_hashtype_tbl,
                .set = bond_option_xmit_hash_policy_set
        },
@@ -364,6 +372,15 @@ static const struct bond_option bond_opts[] = {
                .flags = BOND_OPTFLAG_RAWVAL,
                .set = bond_option_slaves_set
        },
+       [BOND_OPT_TLB_DYNAMIC_LB] = {
+               .id = BOND_OPT_TLB_DYNAMIC_LB,
+               .name = "dynamic_lb",
+               .desc = "Enable dynamic flow shuffling",
+               .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_TLB)),
+               .values = bond_tlb_dynamic_lb_tbl,
+               .flags = BOND_OPTFLAG_IFDOWN,
+               .set = bond_option_tlb_dynamic_lb_set,
+       },
        { }
 };
 
@@ -1337,3 +1354,13 @@ err_no_cmd:
        ret = -EPERM;
        goto out;
 }
+
+static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval)
+{
+       pr_info("%s: Setting dynamic-lb to %s (%llu)\n",
+               bond->dev->name, newval->string, newval->value);
+       bond->params.tlb_dynamic_lb = newval->value;
+
+       return 0;
+}
index 12be9e1bfb0c0d048229a1698c2b384847fbd794..c1860f06145aca73e4c358f20d00fb96aacc2143 100644 (file)
@@ -62,6 +62,7 @@ enum {
        BOND_OPT_RESEND_IGMP,
        BOND_OPT_LP_INTERVAL,
        BOND_OPT_SLAVES,
+       BOND_OPT_TLB_DYNAMIC_LB,
        BOND_OPT_LAST
 };
 
index 0e8b268da0a08f58c4443c6c36aa62bb9ef0f071..cb95ee44c2b4df4a694be5ca1a00d3e101c20f61 100644 (file)
@@ -534,7 +534,7 @@ static ssize_t bonding_show_min_links(struct device *d,
 {
        struct bonding *bond = to_bond(d);
 
-       return sprintf(buf, "%d\n", bond->params.min_links);
+       return sprintf(buf, "%u\n", bond->params.min_links);
 }
 
 static ssize_t bonding_store_min_links(struct device *d,
@@ -1039,6 +1039,34 @@ static ssize_t bonding_store_lp_interval(struct device *d,
 static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR,
                   bonding_show_lp_interval, bonding_store_lp_interval);
 
+static ssize_t bonding_show_tlb_dynamic_lb(struct device *d,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct bonding *bond = to_bond(d);
+       return sprintf(buf, "%d\n", bond->params.tlb_dynamic_lb);
+}
+
+static ssize_t bonding_store_tlb_dynamic_lb(struct device *d,
+                                           struct device_attribute *attr,
+                                           const char *buf,
+                                           size_t count)
+{
+       struct bonding *bond = to_bond(d);
+       int ret;
+
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_TLB_DYNAMIC_LB,
+                                  (char *)buf);
+       if (!ret)
+               ret = count;
+
+       return ret;
+}
+
+static DEVICE_ATTR(tlb_dynamic_lb, S_IRUGO | S_IWUSR,
+                  bonding_show_tlb_dynamic_lb,
+                  bonding_store_tlb_dynamic_lb);
+
 static ssize_t bonding_show_packets_per_slave(struct device *d,
                                              struct device_attribute *attr,
                                              char *buf)
@@ -1099,6 +1127,7 @@ static struct attribute *per_bond_attrs[] = {
        &dev_attr_min_links.attr,
        &dev_attr_lp_interval.attr,
        &dev_attr_packets_per_slave.attr,
+       &dev_attr_tlb_dynamic_lb.attr,
        NULL,
 };
 
index b8bdd0acc8f334ac97bca2ddfea602f473c3272f..c1c7c2f12ac44618648dc5395d2fe935bdaf2208 100644 (file)
@@ -174,6 +174,7 @@ struct bond_params {
        int resend_igmp;
        int lp_interval;
        int packets_per_slave;
+       int tlb_dynamic_lb;
        struct reciprocal_value reciprocal_packets_per_slave;
 };
 
@@ -499,7 +500,7 @@ int bond_sysfs_slave_add(struct slave *slave);
 void bond_sysfs_slave_del(struct slave *slave);
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
-int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count);
+u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
 void bond_create_debugfs(void);
index 9e7d95dae2c7038478d6efadddba81e2778f47a9..4aacaa9b478aa912b574540d25598eb00bd1b12e 100644 (file)
@@ -77,12 +77,6 @@ config CAN_TI_HECC
          Driver for TI HECC (High End CAN Controller) module found on many
          TI devices. The device specifications are available from www.ti.com
 
-config CAN_MCP251X
-       tristate "Microchip MCP251x SPI CAN controllers"
-       depends on SPI && HAS_DMA
-       ---help---
-         Driver for the Microchip MCP251x SPI CAN controllers.
-
 config CAN_BFIN
        depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
        tristate "Analog Devices Blackfin on-chip CAN"
@@ -133,6 +127,8 @@ source "drivers/net/can/c_can/Kconfig"
 
 source "drivers/net/can/cc770/Kconfig"
 
+source "drivers/net/can/spi/Kconfig"
+
 source "drivers/net/can/usb/Kconfig"
 
 source "drivers/net/can/softing/Kconfig"
index c7440392adbbaaabd5ca5b8ba872ba18c23f41d2..c42058868b0fd07a6112deb6044861d69b094bbf 100644 (file)
@@ -10,6 +10,7 @@ can-dev-y                     := dev.o
 
 can-dev-$(CONFIG_CAN_LEDS)     += led.o
 
+obj-y                          += spi/
 obj-y                          += usb/
 obj-y                          += softing/
 
@@ -19,7 +20,6 @@ obj-$(CONFIG_CAN_C_CAN)               += c_can/
 obj-$(CONFIG_CAN_CC770)                += cc770/
 obj-$(CONFIG_CAN_AT91)         += at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)      += ti_hecc.o
-obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
 obj-$(CONFIG_CAN_BFIN)         += bfin_can.o
 obj-$(CONFIG_CAN_JANZ_ICAN3)   += janz-ican3.o
 obj-$(CONFIG_CAN_FLEXCAN)      += flexcan.o
index 61ffc12d8fd8e4e01056b06fd3ae73be7abe513e..8ab7103d4f44ea616ae8cb945eda8ea84aa3059b 100644 (file)
@@ -14,6 +14,13 @@ config CAN_C_CAN_PLATFORM
          SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
          boards like am335x, dm814x, dm813x and dm811x.
 
+config CAN_C_CAN_STRICT_FRAME_ORDERING
+       bool "Force a strict RX CAN frame order (may cause frame loss)"
+       ---help---
+         The RX split buffer prevents packet reordering but can cause packet
+         loss. Only enable this option when you accept to lose CAN frames
+         in favour of getting the received CAN frames in the correct order.
+
 config CAN_C_CAN_PCI
        tristate "Generic PCI Bus based C_CAN/D_CAN driver"
        depends on PCI
index a5c8dcfa83579376a36105c8c055e63f792c42ad..a2ca820b5373841d2083d8d5de02fa9fce6c0ecf 100644 (file)
@@ -60,6 +60,8 @@
 #define CONTROL_IE             BIT(1)
 #define CONTROL_INIT           BIT(0)
 
+#define CONTROL_IRQMSK         (CONTROL_EIE | CONTROL_IE | CONTROL_SIE)
+
 /* test register */
 #define TEST_RX                        BIT(7)
 #define TEST_TX1               BIT(6)
 #define IF_COMM_CONTROL                BIT(4)
 #define IF_COMM_CLR_INT_PND    BIT(3)
 #define IF_COMM_TXRQST         BIT(2)
+#define IF_COMM_CLR_NEWDAT     IF_COMM_TXRQST
 #define IF_COMM_DATAA          BIT(1)
 #define IF_COMM_DATAB          BIT(0)
-#define IF_COMM_ALL            (IF_COMM_MASK | IF_COMM_ARB | \
-                               IF_COMM_CONTROL | IF_COMM_TXRQST | \
-                               IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* TX buffer setup */
+#define IF_COMM_TX             (IF_COMM_ARB | IF_COMM_CONTROL | \
+                                IF_COMM_TXRQST |                \
+                                IF_COMM_DATAA | IF_COMM_DATAB)
 
 /* For the low buffers we clear the interrupt bit, but keep newdat */
 #define IF_COMM_RCV_LOW                (IF_COMM_MASK | IF_COMM_ARB | \
                                 IF_COMM_DATAA | IF_COMM_DATAB)
 
 /* For the high buffers we clear the interrupt bit and newdat */
-#define IF_COMM_RCV_HIGH       (IF_COMM_RCV_LOW | IF_COMM_TXRQST)
+#define IF_COMM_RCV_HIGH       (IF_COMM_RCV_LOW | IF_COMM_CLR_NEWDAT)
+
+
+/* Receive setup of message objects */
+#define IF_COMM_RCV_SETUP      (IF_COMM_MASK | IF_COMM_ARB | IF_COMM_CONTROL)
+
+/* Invalidation of message objects */
+#define IF_COMM_INVAL          (IF_COMM_ARB | IF_COMM_CONTROL)
 
 /* IFx arbitration */
-#define IF_ARB_MSGVAL          BIT(15)
-#define IF_ARB_MSGXTD          BIT(14)
-#define IF_ARB_TRANSMIT                BIT(13)
+#define IF_ARB_MSGVAL          BIT(31)
+#define IF_ARB_MSGXTD          BIT(30)
+#define IF_ARB_TRANSMIT                BIT(29)
 
 /* IFx message control */
 #define IF_MCONT_NEWDAT                BIT(15)
 #define IF_MCONT_EOB           BIT(7)
 #define IF_MCONT_DLC_MASK      0xf
 
+#define IF_MCONT_RCV           (IF_MCONT_RXIE | IF_MCONT_UMASK)
+#define IF_MCONT_RCV_EOB       (IF_MCONT_RCV | IF_MCONT_EOB)
+
+#define IF_MCONT_TX            (IF_MCONT_TXIE | IF_MCONT_EOB)
+
 /*
  * Use IF1 for RX and IF2 for TX
  */
 #define IF_RX                  0
 #define IF_TX                  1
 
-/* status interrupt */
-#define STATUS_INTERRUPT       0x8000
-
-/* global interrupt masks */
-#define ENABLE_ALL_INTERRUPTS  1
-#define DISABLE_ALL_INTERRUPTS 0
-
 /* minimum timeout for checking BUSY status */
 #define MIN_TIMEOUT_VALUE      6
 
@@ -171,6 +181,7 @@ enum c_can_lec_type {
        LEC_BIT0_ERROR,
        LEC_CRC_ERROR,
        LEC_UNUSED,
+       LEC_MASK = LEC_UNUSED,
 };
 
 /*
@@ -226,143 +237,115 @@ static inline void c_can_reset_ram(const struct c_can_priv *priv, bool enable)
                priv->raminit(priv, enable);
 }
 
-static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
+static void c_can_irq_control(struct c_can_priv *priv, bool enable)
 {
-       return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
-                       C_CAN_MSG_OBJ_TX_FIRST;
-}
-
-static inline int get_tx_echo_msg_obj(int txecho)
-{
-       return (txecho & C_CAN_NEXT_MSG_OBJ_MASK) + C_CAN_MSG_OBJ_TX_FIRST;
-}
-
-static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
-{
-       u32 val = priv->read_reg(priv, index);
-       val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
-       return val;
-}
-
-static void c_can_enable_all_interrupts(struct c_can_priv *priv,
-                                               int enable)
-{
-       unsigned int cntrl_save = priv->read_reg(priv,
-                                               C_CAN_CTRL_REG);
+       u32 ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK;
 
        if (enable)
-               cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
-       else
-               cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
+               ctrl |= CONTROL_IRQMSK;
 
-       priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save);
+       priv->write_reg(priv, C_CAN_CTRL_REG, ctrl);
 }
 
-static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
+static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj)
 {
-       int count = MIN_TIMEOUT_VALUE;
+       struct c_can_priv *priv = netdev_priv(dev);
+       int cnt, reg = C_CAN_IFACE(COMREQ_REG, iface);
+
+       priv->write_reg(priv, reg + 1, cmd);
+       priv->write_reg(priv, reg, obj);
 
-       while (count && priv->read_reg(priv,
-                               C_CAN_IFACE(COMREQ_REG, iface)) &
-                               IF_COMR_BUSY) {
-               count--;
+       for (cnt = MIN_TIMEOUT_VALUE; cnt; cnt--) {
+               if (!(priv->read_reg(priv, reg) & IF_COMR_BUSY))
+                       return;
                udelay(1);
        }
+       netdev_err(dev, "Updating object timed out\n");
 
-       if (!count)
-               return 1;
+}
 
-       return 0;
+static inline void c_can_object_get(struct net_device *dev, int iface,
+                                   u32 obj, u32 cmd)
+{
+       c_can_obj_update(dev, iface, cmd, obj);
 }
 
-static inline void c_can_object_get(struct net_device *dev,
-                                       int iface, int objno, int mask)
+static inline void c_can_object_put(struct net_device *dev, int iface,
+                                   u32 obj, u32 cmd)
 {
-       struct c_can_priv *priv = netdev_priv(dev);
+       c_can_obj_update(dev, iface, cmd | IF_COMM_WR, obj);
+}
 
-       /*
-        * As per specs, after writting the message object number in the
-        * IF command request register the transfer b/w interface
-        * register and message RAM must be complete in 6 CAN-CLK
-        * period.
-        */
-       priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
-                       IFX_WRITE_LOW_16BIT(mask));
-       priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
-                       IFX_WRITE_LOW_16BIT(objno));
+/*
+ * Note: According to documentation clearing TXIE while MSGVAL is set
+ * is not allowed, but works nicely on C/DCAN. And that lowers the I/O
+ * load significantly.
+ */
+static void c_can_inval_tx_object(struct net_device *dev, int iface, int obj)
+{
+       struct c_can_priv *priv = netdev_priv(dev);
 
-       if (c_can_msg_obj_is_busy(priv, iface))
-               netdev_err(dev, "timed out in object get\n");
+       priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
+       c_can_object_put(dev, iface, obj, IF_COMM_INVAL);
 }
 
-static inline void c_can_object_put(struct net_device *dev,
-                                       int iface, int objno, int mask)
+static void c_can_inval_msg_object(struct net_device *dev, int iface, int obj)
 {
        struct c_can_priv *priv = netdev_priv(dev);
 
-       /*
-        * As per specs, after writting the message object number in the
-        * IF command request register the transfer b/w interface
-        * register and message RAM must be complete in 6 CAN-CLK
-        * period.
-        */
-       priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
-                       (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
-       priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
-                       IFX_WRITE_LOW_16BIT(objno));
-
-       if (c_can_msg_obj_is_busy(priv, iface))
-               netdev_err(dev, "timed out in object put\n");
+       priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
+       priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
+       c_can_inval_tx_object(dev, iface, obj);
 }
 
-static void c_can_write_msg_object(struct net_device *dev,
-                       int iface, struct can_frame *frame, int objno)
+static void c_can_setup_tx_object(struct net_device *dev, int iface,
+                                 struct can_frame *frame, int idx)
 {
-       int i;
-       u16 flags = 0;
-       unsigned int id;
        struct c_can_priv *priv = netdev_priv(dev);
-
-       if (!(frame->can_id & CAN_RTR_FLAG))
-               flags |= IF_ARB_TRANSMIT;
+       u16 ctrl = IF_MCONT_TX | frame->can_dlc;
+       bool rtr = frame->can_id & CAN_RTR_FLAG;
+       u32 arb = IF_ARB_MSGVAL;
+       int i;
 
        if (frame->can_id & CAN_EFF_FLAG) {
-               id = frame->can_id & CAN_EFF_MASK;
-               flags |= IF_ARB_MSGXTD;
-       } else
-               id = ((frame->can_id & CAN_SFF_MASK) << 18);
+               arb |= frame->can_id & CAN_EFF_MASK;
+               arb |= IF_ARB_MSGXTD;
+       } else {
+               arb |= (frame->can_id & CAN_SFF_MASK) << 18;
+       }
+
+       if (!rtr)
+               arb |= IF_ARB_TRANSMIT;
 
-       flags |= IF_ARB_MSGVAL;
+       /*
+        * If we change the DIR bit, we need to invalidate the buffer
+        * first, i.e. clear the MSGVAL flag in the arbiter.
+        */
+       if (rtr != (bool)test_bit(idx, &priv->tx_dir)) {
+               u32 obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
+
+               c_can_inval_msg_object(dev, iface, obj);
+               change_bit(idx, &priv->tx_dir);
+       }
+
+       priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), arb);
+       priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), arb >> 16);
 
-       priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
-                               IFX_WRITE_LOW_16BIT(id));
-       priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags |
-                               IFX_WRITE_HIGH_16BIT(id));
+       priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
 
        for (i = 0; i < frame->can_dlc; i += 2) {
                priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
                                frame->data[i] | (frame->data[i + 1] << 8));
        }
-
-       /* enable interrupt for this message object */
-       priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
-                       IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
-                       frame->can_dlc);
-       c_can_object_put(dev, iface, objno, IF_COMM_ALL);
 }
 
 static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
-                                               int iface,
-                                               int ctrl_mask)
+                                                      int iface)
 {
        int i;
-       struct c_can_priv *priv = netdev_priv(dev);
 
-       for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
-               priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
-                               ctrl_mask & ~IF_MCONT_NEWDAT);
-               c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
-       }
+       for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++)
+               c_can_object_get(dev, iface, i, IF_COMM_CLR_NEWDAT);
 }
 
 static int c_can_handle_lost_msg_obj(struct net_device *dev,
@@ -377,6 +360,9 @@ static int c_can_handle_lost_msg_obj(struct net_device *dev,
        priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
        c_can_object_put(dev, iface, objno, IF_COMM_CONTROL);
 
+       stats->rx_errors++;
+       stats->rx_over_errors++;
+
        /* create an error msg */
        skb = alloc_can_err_skb(dev, &frame);
        if (unlikely(!skb))
@@ -384,22 +370,18 @@ static int c_can_handle_lost_msg_obj(struct net_device *dev,
 
        frame->can_id |= CAN_ERR_CRTL;
        frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-       stats->rx_errors++;
-       stats->rx_over_errors++;
 
        netif_receive_skb(skb);
        return 1;
 }
 
-static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
+static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
 {
-       u16 flags, data;
-       int i;
-       unsigned int val;
-       struct c_can_priv *priv = netdev_priv(dev);
        struct net_device_stats *stats = &dev->stats;
-       struct sk_buff *skb;
+       struct c_can_priv *priv = netdev_priv(dev);
        struct can_frame *frame;
+       struct sk_buff *skb;
+       u32 arb, data;
 
        skb = alloc_can_skb(dev, &frame);
        if (!skb) {
@@ -409,115 +391,82 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
 
        frame->can_dlc = get_can_dlc(ctrl & 0x0F);
 
-       flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
-       val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
-               (flags << 16);
+       arb = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface));
+       arb |= priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface)) << 16;
 
-       if (flags & IF_ARB_MSGXTD)
-               frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+       if (arb & IF_ARB_MSGXTD)
+               frame->can_id = (arb & CAN_EFF_MASK) | CAN_EFF_FLAG;
        else
-               frame->can_id = (val >> 18) & CAN_SFF_MASK;
+               frame->can_id = (arb >> 18) & CAN_SFF_MASK;
 
-       if (flags & IF_ARB_TRANSMIT)
+       if (arb & IF_ARB_TRANSMIT) {
                frame->can_id |= CAN_RTR_FLAG;
-       else {
-               for (i = 0; i < frame->can_dlc; i += 2) {
-                       data = priv->read_reg(priv,
-                               C_CAN_IFACE(DATA1_REG, iface) + i / 2);
+       } else {
+               int i, dreg = C_CAN_IFACE(DATA1_REG, iface);
+
+               for (i = 0; i < frame->can_dlc; i += 2, dreg ++) {
+                       data = priv->read_reg(priv, dreg);
                        frame->data[i] = data;
                        frame->data[i + 1] = data >> 8;
                }
        }
 
-       netif_receive_skb(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += frame->can_dlc;
+
+       netif_receive_skb(skb);
        return 0;
 }
 
 static void c_can_setup_receive_object(struct net_device *dev, int iface,
-                                       int objno, unsigned int mask,
-                                       unsigned int id, unsigned int mcont)
+                                      u32 obj, u32 mask, u32 id, u32 mcont)
 {
        struct c_can_priv *priv = netdev_priv(dev);
 
-       priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
-                       IFX_WRITE_LOW_16BIT(mask));
-
-       /* According to C_CAN documentation, the reserved bit
-        * in IFx_MASK2 register is fixed 1
-        */
-       priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
-                       IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
+       mask |= BIT(29);
+       priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), mask);
+       priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), mask >> 16);
 
-       priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
-                       IFX_WRITE_LOW_16BIT(id));
-       priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface),
-                       (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
+       id |= IF_ARB_MSGVAL;
+       priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), id);
+       priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), id >> 16);
 
        priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
-       c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
-
-       netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
-                       c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
-}
-
-static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
-{
-       struct c_can_priv *priv = netdev_priv(dev);
-
-       priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
-       priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
-       priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
-
-       c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
-
-       netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
-                       c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
-}
-
-static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int objno)
-{
-       int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
-
-       /*
-        * as transmission request register's bit n-1 corresponds to
-        * message object n, we need to handle the same properly.
-        */
-       if (val & (1 << (objno - 1)))
-               return 1;
-
-       return 0;
+       c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP);
 }
 
 static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
-                                       struct net_device *dev)
+                                   struct net_device *dev)
 {
-       u32 msg_obj_no;
-       struct c_can_priv *priv = netdev_priv(dev);
        struct can_frame *frame = (struct can_frame *)skb->data;
+       struct c_can_priv *priv = netdev_priv(dev);
+       u32 idx, obj;
 
        if (can_dropped_invalid_skb(dev, skb))
                return NETDEV_TX_OK;
-
-       spin_lock_bh(&priv->xmit_lock);
-       msg_obj_no = get_tx_next_msg_obj(priv);
-
-       /* prepare message object for transmission */
-       c_can_write_msg_object(dev, IF_TX, frame, msg_obj_no);
-       priv->dlc[msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST] = frame->can_dlc;
-       can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
-
        /*
-        * we have to stop the queue in case of a wrap around or
-        * if the next TX message object is still in use
+        * This is not a FIFO. C/D_CAN sends out the buffers
+        * prioritized. The lowest buffer number wins.
         */
-       priv->tx_next++;
-       if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
-                       (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
+       idx = fls(atomic_read(&priv->tx_active));
+       obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
+
+       /* If this is the last buffer, stop the xmit queue */
+       if (idx == C_CAN_MSG_OBJ_TX_NUM - 1)
                netif_stop_queue(dev);
-       spin_unlock_bh(&priv->xmit_lock);
+       /*
+        * Store the message in the interface so we can call
+        * can_put_echo_skb(). We must do this before we enable
+        * transmit as we might race against do_tx().
+        */
+       c_can_setup_tx_object(dev, IF_TX, frame, idx);
+       priv->dlc[idx] = frame->can_dlc;
+       can_put_echo_skb(skb, dev, idx);
+
+       /* Update the active bits */
+       atomic_add((1 << idx), &priv->tx_active);
+       /* Start transmission */
+       c_can_object_put(dev, IF_TX, obj, IF_COMM_TX);
 
        return NETDEV_TX_OK;
 }
@@ -594,11 +543,10 @@ static void c_can_configure_msg_objects(struct net_device *dev)
 
        /* setup receive message objects */
        for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
-               c_can_setup_receive_object(dev, IF_RX, i, 0, 0,
-                       (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
+               c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV);
 
        c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
-                       IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
+                                  IF_MCONT_RCV_EOB);
 }
 
 /*
@@ -612,30 +560,22 @@ static int c_can_chip_config(struct net_device *dev)
        struct c_can_priv *priv = netdev_priv(dev);
 
        /* enable automatic retransmission */
-       priv->write_reg(priv, C_CAN_CTRL_REG,
-                       CONTROL_ENABLE_AR);
+       priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
 
        if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
            (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
                /* loopback + silent mode : useful for hot self-test */
-               priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
-                               CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
-               priv->write_reg(priv, C_CAN_TEST_REG,
-                               TEST_LBACK | TEST_SILENT);
+               priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+               priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT);
        } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
                /* loopback mode : useful for self-test function */
-               priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
-                               CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+               priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
                priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
        } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
                /* silent mode : bus-monitoring mode */
-               priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
-                               CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+               priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
                priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
-       } else
-               /* normal mode*/
-               priv->write_reg(priv, C_CAN_CTRL_REG,
-                               CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
+       }
 
        /* configure message objects */
        c_can_configure_msg_objects(dev);
@@ -643,6 +583,11 @@ static int c_can_chip_config(struct net_device *dev)
        /* set a `lec` value so that we can check for updates later */
        priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
 
+       /* Clear all internal status */
+       atomic_set(&priv->tx_active, 0);
+       priv->rxmasked = 0;
+       priv->tx_dir = 0;
+
        /* set bittiming params */
        return c_can_set_bittiming(dev);
 }
@@ -657,13 +602,11 @@ static int c_can_start(struct net_device *dev)
        if (err)
                return err;
 
-       priv->can.state = CAN_STATE_ERROR_ACTIVE;
-
-       /* reset tx helper pointers */
-       priv->tx_next = priv->tx_echo = 0;
+       /* Setup the command for new messages */
+       priv->comm_rcv_high = priv->type != BOSCH_D_CAN ?
+               IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
 
-       /* enable status change, error and module interrupts */
-       c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
        return 0;
 }
@@ -672,15 +615,13 @@ static void c_can_stop(struct net_device *dev)
 {
        struct c_can_priv *priv = netdev_priv(dev);
 
-       /* disable all interrupts */
-       c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
-
-       /* set the state as STOPPED */
+       c_can_irq_control(priv, false);
        priv->can.state = CAN_STATE_STOPPED;
 }
 
 static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
 {
+       struct c_can_priv *priv = netdev_priv(dev);
        int err;
 
        switch (mode) {
@@ -689,6 +630,7 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
                if (err)
                        return err;
                netif_wake_queue(dev);
+               c_can_irq_control(priv, true);
                break;
        default:
                return -EOPNOTSUPP;
@@ -724,42 +666,29 @@ static int c_can_get_berr_counter(const struct net_device *dev,
        return err;
 }
 
-/*
- * priv->tx_echo holds the number of the oldest can_frame put for
- * transmission into the hardware, but not yet ACKed by the CAN tx
- * complete IRQ.
- *
- * We iterate from priv->tx_echo to priv->tx_next and check if the
- * packet has been transmitted, echo it back to the CAN framework.
- * If we discover a not yet transmitted packet, stop looking for more.
- */
 static void c_can_do_tx(struct net_device *dev)
 {
        struct c_can_priv *priv = netdev_priv(dev);
        struct net_device_stats *stats = &dev->stats;
-       u32 val, obj, pkts = 0, bytes = 0;
-
-       spin_lock_bh(&priv->xmit_lock);
+       u32 idx, obj, pkts = 0, bytes = 0, pend, clr;
 
-       for (; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
-               obj = get_tx_echo_msg_obj(priv->tx_echo);
-               val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
+       clr = pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
 
-               if (val & (1 << (obj - 1)))
-                       break;
-
-               can_get_echo_skb(dev, obj - C_CAN_MSG_OBJ_TX_FIRST);
-               bytes += priv->dlc[obj - C_CAN_MSG_OBJ_TX_FIRST];
+       while ((idx = ffs(pend))) {
+               idx--;
+               pend &= ~(1 << idx);
+               obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
+               c_can_inval_tx_object(dev, IF_RX, obj);
+               can_get_echo_skb(dev, idx);
+               bytes += priv->dlc[idx];
                pkts++;
-               c_can_inval_msg_object(dev, IF_TX, obj);
        }
 
-       /* restart queue if wrap-up or if queue stalled on last pkt */
-       if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
-                       ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
-               netif_wake_queue(dev);
+       /* Clear the bits in the tx_active mask */
+       atomic_sub(clr, &priv->tx_active);
 
-       spin_unlock_bh(&priv->xmit_lock);
+       if (clr & (1 << (C_CAN_MSG_OBJ_TX_NUM - 1)))
+               netif_wake_queue(dev);
 
        if (pkts) {
                stats->tx_bytes += bytes;
@@ -800,18 +729,42 @@ static u32 c_can_adjust_pending(u32 pend)
        return pend & ~((1 << lasts) - 1);
 }
 
+static inline void c_can_rx_object_get(struct net_device *dev,
+                                      struct c_can_priv *priv, u32 obj)
+{
+#ifdef CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING
+       if (obj < C_CAN_MSG_RX_LOW_LAST)
+               c_can_object_get(dev, IF_RX, obj, IF_COMM_RCV_LOW);
+       else
+#endif
+               c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high);
+}
+
+static inline void c_can_rx_finalize(struct net_device *dev,
+                                    struct c_can_priv *priv, u32 obj)
+{
+#ifdef CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING
+       if (obj < C_CAN_MSG_RX_LOW_LAST)
+               priv->rxmasked |= BIT(obj - 1);
+       else if (obj == C_CAN_MSG_RX_LOW_LAST) {
+               priv->rxmasked = 0;
+               /* activate all lower message objects */
+               c_can_activate_all_lower_rx_msg_obj(dev, IF_RX);
+       }
+#endif
+       if (priv->type != BOSCH_D_CAN)
+               c_can_object_get(dev, IF_RX, obj, IF_COMM_CLR_NEWDAT);
+}
+
 static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
                              u32 pend, int quota)
 {
-       u32 pkts = 0, ctrl, obj, mcmd;
+       u32 pkts = 0, ctrl, obj;
 
        while ((obj = ffs(pend)) && quota > 0) {
                pend &= ~BIT(obj - 1);
 
-               mcmd = obj < C_CAN_MSG_RX_LOW_LAST ?
-                       IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
-
-               c_can_object_get(dev, IF_RX, obj, mcmd);
+               c_can_rx_object_get(dev, priv, obj);
                ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX));
 
                if (ctrl & IF_MCONT_MSGLST) {
@@ -833,9 +786,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
                /* read the data from the message object */
                c_can_read_msg_object(dev, IF_RX, ctrl);
 
-               if (obj == C_CAN_MSG_RX_LOW_LAST)
-                       /* activate all lower message objects */
-                       c_can_activate_all_lower_rx_msg_obj(dev, IF_RX, ctrl);
+               c_can_rx_finalize(dev, priv, obj);
 
                pkts++;
                quota--;
@@ -844,6 +795,16 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
        return pkts;
 }
 
+static inline u32 c_can_get_pending(struct c_can_priv *priv)
+{
+       u32 pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
+
+#ifdef CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING
+       pend &= ~priv->rxmasked;
+#endif
+       return pend;
+}
+
 /*
  * theory of operation:
  *
@@ -853,6 +814,8 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
  * has arrived. To work-around this issue, we keep two groups of message
  * objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT.
  *
+ * If CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING = y
+ *
  * To ensure in-order frame reception we use the following
  * approach while re-activating a message object to receive further
  * frames:
@@ -865,6 +828,14 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
  * - if the current message object number is greater than
  *   C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
  *   only this message object.
+ *
+ * This can cause packet loss!
+ *
+ * If CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING = n
+ *
+ * We clear the newdat bit right away.
+ *
+ * This can result in packet reordering when the readout is slow.
  */
 static int c_can_do_rx_poll(struct net_device *dev, int quota)
 {
@@ -880,7 +851,7 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
 
        while (quota > 0) {
                if (!pend) {
-                       pend = priv->read_reg(priv, C_CAN_INTPND1_REG);
+                       pend = c_can_get_pending(priv);
                        if (!pend)
                                break;
                        /*
@@ -905,12 +876,6 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
        return pkts;
 }
 
-static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
-{
-       return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
-               (priv->current_status & LEC_UNUSED);
-}
-
 static int c_can_handle_state_change(struct net_device *dev,
                                enum c_can_bus_error_types error_type)
 {
@@ -922,6 +887,26 @@ static int c_can_handle_state_change(struct net_device *dev,
        struct sk_buff *skb;
        struct can_berr_counter bec;
 
+       switch (error_type) {
+       case C_CAN_ERROR_WARNING:
+               /* error warning state */
+               priv->can.can_stats.error_warning++;
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               break;
+       case C_CAN_ERROR_PASSIVE:
+               /* error passive state */
+               priv->can.can_stats.error_passive++;
+               priv->can.state = CAN_STATE_ERROR_PASSIVE;
+               break;
+       case C_CAN_BUS_OFF:
+               /* bus-off state */
+               priv->can.state = CAN_STATE_BUS_OFF;
+               can_bus_off(dev);
+               break;
+       default:
+               break;
+       }
+
        /* propagate the error condition to the CAN stack */
        skb = alloc_can_err_skb(dev, &cf);
        if (unlikely(!skb))
@@ -935,8 +920,6 @@ static int c_can_handle_state_change(struct net_device *dev,
        switch (error_type) {
        case C_CAN_ERROR_WARNING:
                /* error warning state */
-               priv->can.can_stats.error_warning++;
-               priv->can.state = CAN_STATE_ERROR_WARNING;
                cf->can_id |= CAN_ERR_CRTL;
                cf->data[1] = (bec.txerr > bec.rxerr) ?
                        CAN_ERR_CRTL_TX_WARNING :
@@ -947,8 +930,6 @@ static int c_can_handle_state_change(struct net_device *dev,
                break;
        case C_CAN_ERROR_PASSIVE:
                /* error passive state */
-               priv->can.can_stats.error_passive++;
-               priv->can.state = CAN_STATE_ERROR_PASSIVE;
                cf->can_id |= CAN_ERR_CRTL;
                if (rx_err_passive)
                        cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
@@ -960,22 +941,16 @@ static int c_can_handle_state_change(struct net_device *dev,
                break;
        case C_CAN_BUS_OFF:
                /* bus-off state */
-               priv->can.state = CAN_STATE_BUS_OFF;
                cf->can_id |= CAN_ERR_BUSOFF;
-               /*
-                * disable all interrupts in bus-off mode to ensure that
-                * the CPU is not hogged down
-                */
-               c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
                can_bus_off(dev);
                break;
        default:
                break;
        }
 
-       netif_receive_skb(skb);
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -996,6 +971,13 @@ static int c_can_handle_bus_err(struct net_device *dev,
        if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
                return 0;
 
+       if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
+               return 0;
+
+       /* common for all type of bus errors */
+       priv->can.can_stats.bus_error++;
+       stats->rx_errors++;
+
        /* propagate the error condition to the CAN stack */
        skb = alloc_can_err_skb(dev, &cf);
        if (unlikely(!skb))
@@ -1005,10 +987,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
         * check for 'last error code' which tells us the
         * type of the last error to occur on the CAN bus
         */
-
-       /* common for all type of bus errors */
-       priv->can.can_stats.bus_error++;
-       stats->rx_errors++;
        cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
        cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 
@@ -1043,95 +1021,64 @@ static int c_can_handle_bus_err(struct net_device *dev,
                break;
        }
 
-       /* set a `lec` value so that we can check for updates later */
-       priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
-
-       netif_receive_skb(skb);
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
-
+       netif_receive_skb(skb);
        return 1;
 }
 
 static int c_can_poll(struct napi_struct *napi, int quota)
 {
-       u16 irqstatus;
-       int lec_type = 0;
-       int work_done = 0;
        struct net_device *dev = napi->dev;
        struct c_can_priv *priv = netdev_priv(dev);
+       u16 curr, last = priv->last_status;
+       int work_done = 0;
 
-       irqstatus = priv->irqstatus;
-       if (!irqstatus)
-               goto end;
+       priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
+       /* Ack status on C_CAN. D_CAN is self clearing */
+       if (priv->type != BOSCH_D_CAN)
+               priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
 
-       /* status events have the highest priority */
-       if (irqstatus == STATUS_INTERRUPT) {
-               priv->current_status = priv->read_reg(priv,
-                                       C_CAN_STS_REG);
-
-               /* handle Tx/Rx events */
-               if (priv->current_status & STATUS_TXOK)
-                       priv->write_reg(priv, C_CAN_STS_REG,
-                                       priv->current_status & ~STATUS_TXOK);
-
-               if (priv->current_status & STATUS_RXOK)
-                       priv->write_reg(priv, C_CAN_STS_REG,
-                                       priv->current_status & ~STATUS_RXOK);
-
-               /* handle state changes */
-               if ((priv->current_status & STATUS_EWARN) &&
-                               (!(priv->last_status & STATUS_EWARN))) {
-                       netdev_dbg(dev, "entered error warning state\n");
-                       work_done += c_can_handle_state_change(dev,
-                                               C_CAN_ERROR_WARNING);
-               }
-               if ((priv->current_status & STATUS_EPASS) &&
-                               (!(priv->last_status & STATUS_EPASS))) {
-                       netdev_dbg(dev, "entered error passive state\n");
-                       work_done += c_can_handle_state_change(dev,
-                                               C_CAN_ERROR_PASSIVE);
-               }
-               if ((priv->current_status & STATUS_BOFF) &&
-                               (!(priv->last_status & STATUS_BOFF))) {
-                       netdev_dbg(dev, "entered bus off state\n");
-                       work_done += c_can_handle_state_change(dev,
-                                               C_CAN_BUS_OFF);
-               }
+       /* handle state changes */
+       if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING);
+       }
 
-               /* handle bus recovery events */
-               if ((!(priv->current_status & STATUS_BOFF)) &&
-                               (priv->last_status & STATUS_BOFF)) {
-                       netdev_dbg(dev, "left bus off state\n");
-                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
-               }
-               if ((!(priv->current_status & STATUS_EPASS)) &&
-                               (priv->last_status & STATUS_EPASS)) {
-                       netdev_dbg(dev, "left error passive state\n");
-                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
-               }
+       if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) {
+               netdev_dbg(dev, "entered error passive state\n");
+               work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
+       }
+
+       if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) {
+               netdev_dbg(dev, "entered bus off state\n");
+               work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF);
+               goto end;
+       }
 
-               priv->last_status = priv->current_status;
-
-               /* handle lec errors on the bus */
-               lec_type = c_can_has_and_handle_berr(priv);
-               if (lec_type)
-                       work_done += c_can_handle_bus_err(dev, lec_type);
-       } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
-                       (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
-               /* handle events corresponding to receive message objects */
-               work_done += c_can_do_rx_poll(dev, (quota - work_done));
-       } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
-                       (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
-               /* handle events corresponding to transmit message objects */
-               c_can_do_tx(dev);
+       /* handle bus recovery events */
+       if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) {
+               netdev_dbg(dev, "left bus off state\n");
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+       }
+       if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) {
+               netdev_dbg(dev, "left error passive state\n");
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
        }
 
+       /* handle lec errors on the bus */
+       work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);
+
+       /* Handle Tx/Rx events. We do this unconditionally */
+       work_done += c_can_do_rx_poll(dev, (quota - work_done));
+       c_can_do_tx(dev);
+
 end:
        if (work_done < quota) {
                napi_complete(napi);
-               /* enable all IRQs */
-               c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+               /* enable all IRQs if we are not in bus off state */
+               if (priv->can.state != CAN_STATE_BUS_OFF)
+                       c_can_irq_control(priv, true);
        }
 
        return work_done;
@@ -1142,12 +1089,11 @@ static irqreturn_t c_can_isr(int irq, void *dev_id)
        struct net_device *dev = (struct net_device *)dev_id;
        struct c_can_priv *priv = netdev_priv(dev);
 
-       priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
-       if (!priv->irqstatus)
+       if (!priv->read_reg(priv, C_CAN_INT_REG))
                return IRQ_NONE;
 
        /* disable all interrupts and schedule the NAPI */
-       c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+       c_can_irq_control(priv, false);
        napi_schedule(&priv->napi);
 
        return IRQ_HANDLED;
@@ -1184,6 +1130,8 @@ static int c_can_open(struct net_device *dev)
        can_led_event(dev, CAN_LED_EVENT_OPEN);
 
        napi_enable(&priv->napi);
+       /* enable status change, error and module interrupts */
+       c_can_irq_control(priv, true);
        netif_start_queue(dev);
 
        return 0;
@@ -1226,7 +1174,6 @@ struct net_device *alloc_c_can_dev(void)
                return NULL;
 
        priv = netdev_priv(dev);
-       spin_lock_init(&priv->xmit_lock);
        netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
 
        priv->dev = dev;
@@ -1281,6 +1228,7 @@ int c_can_power_up(struct net_device *dev)
        u32 val;
        unsigned long time_out;
        struct c_can_priv *priv = netdev_priv(dev);
+       int ret;
 
        if (!(dev->flags & IFF_UP))
                return 0;
@@ -1307,7 +1255,11 @@ int c_can_power_up(struct net_device *dev)
        if (time_after(jiffies, time_out))
                return -ETIMEDOUT;
 
-       return c_can_start(dev);
+       ret = c_can_start(dev);
+       if (!ret)
+               c_can_irq_control(priv, true);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(c_can_power_up);
 #endif
index faa8404162b397e4bd589c0b7b665c2f6ab1e4e4..c56f1b1c11cacde9e41c5cd663fd69ce802f2025 100644 (file)
 #ifndef C_CAN_H
 #define C_CAN_H
 
-/*
- * IFx register masks:
- * allow easy operation on 16-bit registers when the
- * argument is 32-bit instead
- */
-#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
-#define IFX_WRITE_HIGH_16BIT(x)        (((x) & 0xFFFF0000) >> 16)
-
 /* message object split */
 #define C_CAN_NO_OF_OBJECTS    32
 #define C_CAN_MSG_OBJ_RX_NUM   16
@@ -45,8 +37,6 @@
 
 #define C_CAN_MSG_OBJ_RX_SPLIT 9
 #define C_CAN_MSG_RX_LOW_LAST  (C_CAN_MSG_OBJ_RX_SPLIT - 1)
-
-#define C_CAN_NEXT_MSG_OBJ_MASK        (C_CAN_MSG_OBJ_TX_NUM - 1)
 #define RECEIVE_OBJECT_BITS    0x0000ffff
 
 enum reg {
@@ -183,23 +173,20 @@ struct c_can_priv {
        struct napi_struct napi;
        struct net_device *dev;
        struct device *device;
-       spinlock_t xmit_lock;
-       int tx_object;
-       int current_status;
+       atomic_t tx_active;
+       unsigned long tx_dir;
        int last_status;
        u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
        void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
        void __iomem *base;
        const u16 *regs;
-       unsigned long irq_flags; /* for request_irq() */
-       unsigned int tx_next;
-       unsigned int tx_echo;
        void *priv;             /* for board-specific data */
-       u16 irqstatus;
        enum c_can_dev_id type;
        u32 __iomem *raminit_ctrlreg;
-       unsigned int instance;
+       int instance;
        void (*raminit) (const struct c_can_priv *priv, bool enable);
+       u32 comm_rcv_high;
+       u32 rxmasked;
        u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
 };
 
index bce0be54c2f59587a2498d2f37821f2634b886d9..58f71e1fcc4e7bb48de89b13ec56dd6f95755dd6 100644 (file)
 
 #include "c_can.h"
 
+#define PCI_DEVICE_ID_PCH_CAN  0x8818
+#define PCH_PCI_SOFT_RESET     0x01fc
+
 enum c_can_pci_reg_align {
        C_CAN_REG_ALIGN_16,
        C_CAN_REG_ALIGN_32,
+       C_CAN_REG_32,
 };
 
 struct c_can_pci_data {
@@ -31,6 +35,10 @@ struct c_can_pci_data {
        enum c_can_pci_reg_align reg_align;
        /* Set the frequency */
        unsigned int freq;
+       /* PCI bar number */
+       int bar;
+       /* Callback for reset */
+       void (*init)(const struct c_can_priv *priv, bool enable);
 };
 
 /*
@@ -63,6 +71,29 @@ static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
        writew(val, priv->base + 2 * priv->regs[index]);
 }
 
+static u16 c_can_pci_read_reg_32bit(struct c_can_priv *priv,
+                                   enum reg index)
+{
+       return (u16)ioread32(priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_32bit(struct c_can_priv *priv,
+                                     enum reg index, u16 val)
+{
+       iowrite32((u32)val, priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable)
+{
+       if (enable) {
+               u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET;
+
+               /* write to sw reset register */
+               iowrite32(1, addr);
+               iowrite32(0, addr);
+       }
+}
+
 static int c_can_pci_probe(struct pci_dev *pdev,
                           const struct pci_device_id *ent)
 {
@@ -84,10 +115,14 @@ static int c_can_pci_probe(struct pci_dev *pdev,
                goto out_disable_device;
        }
 
-       pci_set_master(pdev);
-       pci_enable_msi(pdev);
+       ret = pci_enable_msi(pdev);
+       if (!ret) {
+               dev_info(&pdev->dev, "MSI enabled\n");
+               pci_set_master(pdev);
+       }
 
-       addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+       addr = pci_iomap(pdev, c_can_pci_data->bar,
+                        pci_resource_len(pdev, c_can_pci_data->bar));
        if (!addr) {
                dev_err(&pdev->dev,
                        "device has no PCI memory resources, "
@@ -132,6 +167,8 @@ static int c_can_pci_probe(struct pci_dev *pdev,
                goto out_free_c_can;
        }
 
+       priv->type = c_can_pci_data->type;
+
        /* Configure access to registers */
        switch (c_can_pci_data->reg_align) {
        case C_CAN_REG_ALIGN_32:
@@ -142,11 +179,17 @@ static int c_can_pci_probe(struct pci_dev *pdev,
                priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
                priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
                break;
+       case C_CAN_REG_32:
+               priv->read_reg = c_can_pci_read_reg_32bit;
+               priv->write_reg = c_can_pci_write_reg_32bit;
+               break;
        default:
                ret = -EINVAL;
                goto out_free_c_can;
        }
 
+       priv->raminit = c_can_pci_data->init;
+
        ret = register_c_can_dev(dev);
        if (ret) {
                dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
@@ -193,6 +236,15 @@ static struct c_can_pci_data c_can_sta2x11= {
        .type = BOSCH_C_CAN,
        .reg_align = C_CAN_REG_ALIGN_32,
        .freq = 52000000, /* 52 Mhz */
+       .bar = 0,
+};
+
+static struct c_can_pci_data c_can_pch = {
+       .type = BOSCH_C_CAN,
+       .reg_align = C_CAN_REG_32,
+       .freq = 50000000, /* 50 MHz */
+       .init = c_can_pci_reset_pch,
+       .bar = 1,
 };
 
 #define C_CAN_ID(_vend, _dev, _driverdata) {           \
@@ -202,6 +254,8 @@ static struct c_can_pci_data c_can_sta2x11= {
 static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
        C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
                 c_can_sta2x11),
+       C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,
+                c_can_pch),
        {},
 };
 static struct pci_driver c_can_pci_driver = {
index 806d92753427b619fe7241ac290a18aa7769240b..1df0b322d1e461ee69c4e74a499f425cda23d7bf 100644 (file)
@@ -222,7 +222,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
 
                res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
                priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(priv->raminit_ctrlreg) || (int)priv->instance < 0)
+               if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0)
                        dev_info(&pdev->dev, "control memory is not used for raminit\n");
                else
                        priv->raminit = c_can_hw_raminit;
index c7a260478749ad163ec133df88e7a0086b220a73..e318e87e2bfc00ba9e32aa08858de5f5c1629dcf 100644 (file)
@@ -256,7 +256,7 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
 
        /* Check if the CAN device has bit-timing parameters */
        if (!btc)
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        /*
         * Depending on the given can_bittiming parameter structure the CAN
index df136a2516c401a5d96aba3d7c0da2e9f511d1a8..014695d7e6a342c49e9c86ed66f59ba5cddc0335 100644 (file)
@@ -46,6 +46,7 @@ static int clk[MAXDEV];
 static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
 static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
 static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static spinlock_t indirect_lock[MAXDEV];  /* lock for indirect access mode */
 
 module_param_array(port, ulong, NULL, S_IRUGO);
 MODULE_PARM_DESC(port, "I/O port number");
@@ -101,19 +102,26 @@ static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
 static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
                                             int reg)
 {
-       unsigned long base = (unsigned long)priv->reg_base;
+       unsigned long flags, base = (unsigned long)priv->reg_base;
+       u8 readval;
 
+       spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
        outb(reg, base);
-       return inb(base + 1);
+       readval = inb(base + 1);
+       spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
+
+       return readval;
 }
 
 static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
                                                int reg, u8 val)
 {
-       unsigned long base = (unsigned long)priv->reg_base;
+       unsigned long flags, base = (unsigned long)priv->reg_base;
 
+       spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
        outb(reg, base);
        outb(val, base + 1);
+       spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
 }
 
 static int sja1000_isa_probe(struct platform_device *pdev)
@@ -169,6 +177,7 @@ static int sja1000_isa_probe(struct platform_device *pdev)
                if (iosize == SJA1000_IOSIZE_INDIRECT) {
                        priv->read_reg = sja1000_isa_port_read_reg_indirect;
                        priv->write_reg = sja1000_isa_port_write_reg_indirect;
+                       spin_lock_init(&indirect_lock[idx]);
                } else {
                        priv->read_reg = sja1000_isa_port_read_reg;
                        priv->write_reg = sja1000_isa_port_write_reg;
@@ -198,6 +207,7 @@ static int sja1000_isa_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
+       dev->dev_id = idx;
 
        err = register_sja1000dev(dev);
        if (err) {
index f5b16e0e3a125f4e38a93408e92b8218808339af..dcf9196f63164b0db099e17a8d1208d9ac158ac4 100644 (file)
@@ -322,13 +322,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);
+       spin_lock_bh(&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);
+               spin_unlock_bh(&sl->lock);
                netif_wake_queue(sl->dev);
                return;
        }
@@ -336,7 +336,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);
+       spin_unlock_bh(&sl->lock);
 }
 
 /* Send a can_frame to a TTY queue. */
index 7d8c8f3672dd993119a28f478e5cc43514aa131c..bacd236ce3064d357271ff67e3ccacbfedddd953 100644 (file)
@@ -556,15 +556,6 @@ failed:
 /*
  * netdev sysfs
  */
-static ssize_t show_channel(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct net_device *ndev = to_net_dev(dev);
-       struct softing_priv *priv = netdev2softing(ndev);
-
-       return sprintf(buf, "%i\n", priv->index);
-}
-
 static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
@@ -609,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
 static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
 static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
 
 static const struct attribute *const netdev_sysfs_attrs[] = {
-       &dev_attr_channel.attr,
        &dev_attr_chip.attr,
        &dev_attr_output.attr,
        NULL,
@@ -679,17 +668,20 @@ static int softing_netdev_register(struct net_device *netdev)
 {
        int ret;
 
-       netdev->sysfs_groups[0] = &netdev_sysfs_group;
        ret = register_candev(netdev);
        if (ret) {
                dev_alert(&netdev->dev, "register failed\n");
                return ret;
        }
+       if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0)
+               netdev_alert(netdev, "sysfs group failed\n");
+
        return 0;
 }
 
 static void softing_netdev_cleanup(struct net_device *netdev)
 {
+       sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group);
        unregister_candev(netdev);
        free_candev(netdev);
 }
@@ -721,8 +713,6 @@ DEV_ATTR_RO(firmware_version, id.fw_version);
 DEV_ATTR_RO_STR(hardware, pdat->name);
 DEV_ATTR_RO(hardware_version, id.hw_version);
 DEV_ATTR_RO(license, id.license);
-DEV_ATTR_RO(frequency, id.freq);
-DEV_ATTR_RO(txpending, tx.pending);
 
 static struct attribute *softing_pdev_attrs[] = {
        &dev_attr_serial.attr,
@@ -731,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = {
        &dev_attr_hardware.attr,
        &dev_attr_hardware_version.attr,
        &dev_attr_license.attr,
-       &dev_attr_frequency.attr,
-       &dev_attr_txpending.attr,
        NULL,
 };
 
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
new file mode 100644 (file)
index 0000000..148cae5
--- /dev/null
@@ -0,0 +1,10 @@
+menu "CAN SPI interfaces"
+       depends on SPI
+
+config CAN_MCP251X
+       tristate "Microchip MCP251x SPI CAN controllers"
+       depends on HAS_DMA
+       ---help---
+         Driver for the Microchip MCP251x SPI CAN controllers.
+
+endmenu
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
new file mode 100644 (file)
index 0000000..90bcacf
--- /dev/null
@@ -0,0 +1,8 @@
+#
+#  Makefile for the Linux Controller Area Network SPI drivers.
+#
+
+
+obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
similarity index 96%
rename from drivers/net/can/mcp251x.c
rename to drivers/net/can/spi/mcp251x.c
index 28c11f81524524fe521eb0c24177fffa76323885..bc235f9dc7543e0a382211dfe50ff6c00cae1b50 100644 (file)
 
 #define TX_ECHO_SKB_MAX        1
 
+#define MCP251X_OST_DELAY_MS   (5)
+
 #define DEVICE_NAME "mcp251x"
 
 static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
@@ -624,50 +626,45 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
 static int mcp251x_hw_reset(struct spi_device *spi)
 {
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
+       u8 reg;
        int ret;
-       unsigned long timeout;
+
+       /* Wait for oscillator startup timer after power up */
+       mdelay(MCP251X_OST_DELAY_MS);
 
        priv->spi_tx_buf[0] = INSTRUCTION_RESET;
-       ret = spi_write(spi, priv->spi_tx_buf, 1);
-       if (ret) {
-               dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
-               return -EIO;
-       }
+       ret = mcp251x_spi_trans(spi, 1);
+       if (ret)
+               return ret;
+
+       /* Wait for oscillator startup timer after reset */
+       mdelay(MCP251X_OST_DELAY_MS);
+       
+       reg = mcp251x_read_reg(spi, CANSTAT);
+       if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
+               return -ENODEV;
 
-       /* Wait for reset to finish */
-       timeout = jiffies + HZ;
-       mdelay(10);
-       while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)
-              != CANCTRL_REQOP_CONF) {
-               schedule();
-               if (time_after(jiffies, timeout)) {
-                       dev_err(&spi->dev, "MCP251x didn't"
-                               " enter in conf mode after reset\n");
-                       return -EBUSY;
-               }
-       }
        return 0;
 }
 
 static int mcp251x_hw_probe(struct spi_device *spi)
 {
-       int st1, st2;
+       u8 ctrl;
+       int ret;
 
-       mcp251x_hw_reset(spi);
+       ret = mcp251x_hw_reset(spi);
+       if (ret)
+               return ret;
 
-       /*
-        * Please note that these are "magic values" based on after
-        * reset defaults taken from data sheet which allows us to see
-        * if we really have a chip on the bus (we avoid common all
-        * zeroes or all ones situations)
-        */
-       st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
-       st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
+       ctrl = mcp251x_read_reg(spi, CANCTRL);
+
+       dev_dbg(&spi->dev, "CANCTRL 0x%02x\n", ctrl);
 
-       dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
+       /* Check for power up default value */
+       if ((ctrl & 0x17) != 0x07)
+               return -ENODEV;
 
-       /* Check for power up default values */
-       return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
+       return 0;
 }
 
 static int mcp251x_power_enable(struct regulator *reg, int enable)
@@ -776,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
 
        mutex_lock(&priv->mcp_lock);
        if (priv->after_suspend) {
-               mdelay(10);
                mcp251x_hw_reset(spi);
                mcp251x_setup(net, priv, spi);
                if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
@@ -1032,8 +1028,8 @@ static int mcp251x_can_probe(struct spi_device *spi)
        struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
        struct net_device *net;
        struct mcp251x_priv *priv;
-       int freq, ret = -ENODEV;
        struct clk *clk;
+       int freq, ret;
 
        clk = devm_clk_get(&spi->dev, NULL);
        if (IS_ERR(clk)) {
@@ -1076,6 +1072,18 @@ static int mcp251x_can_probe(struct spi_device *spi)
        priv->net = net;
        priv->clk = clk;
 
+       spi_set_drvdata(spi, priv);
+
+       /* Configure the SPI bus */
+       spi->bits_per_word = 8;
+       if (mcp251x_is_2510(spi))
+               spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
+       else
+               spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
+       ret = spi_setup(spi);
+       if (ret)
+               goto out_clk;
+
        priv->power = devm_regulator_get(&spi->dev, "vdd");
        priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
        if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
@@ -1088,8 +1096,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
        if (ret)
                goto out_clk;
 
-       spi_set_drvdata(spi, priv);
-
        priv->spi = spi;
        mutex_init(&priv->mcp_lock);
 
@@ -1134,20 +1140,11 @@ static int mcp251x_can_probe(struct spi_device *spi)
 
        SET_NETDEV_DEV(net, &spi->dev);
 
-       /* Configure the SPI bus */
-       spi->mode = spi->mode ? : SPI_MODE_0;
-       if (mcp251x_is_2510(spi))
-               spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
-       else
-               spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
-       spi->bits_per_word = 8;
-       spi_setup(spi);
-
        /* Here is OK to not lock the MCP, no one knows about it yet */
-       if (!mcp251x_hw_probe(spi)) {
-               ret = -ENODEV;
+       ret = mcp251x_hw_probe(spi);
+       if (ret)
                goto error_probe;
-       }
+
        mcp251x_hw_sleep(spi);
 
        ret = register_candev(net);
@@ -1156,7 +1153,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
 
        devm_can_led_init(net);
 
-       return ret;
+       return 0;
 
 error_probe:
        if (mcp251x_enable_dma)
index fc96a3d83ebecde338cdc5fd1d7b12f5ee9fbc25..0b918ebad76b2fb17a9bbf550b2fcbfbd08a95cd 100644 (file)
@@ -19,7 +19,7 @@ config CAN_KVASER_USB
          This driver adds support for Kvaser CAN/USB devices like Kvaser
          Leaf Light.
 
-         The driver gives support for the following devices:
+         The driver provides support for the following devices:
            - Kvaser Leaf Light
            - Kvaser Leaf Professional HS
            - Kvaser Leaf SemiPro HS
@@ -36,6 +36,8 @@ config CAN_KVASER_USB
            - Kvaser Leaf Light "China"
            - Kvaser BlackBird SemiPro
            - Kvaser USBcan R
+           - Kvaser Leaf Light v2
+           - Kvaser Mini PCI Express HS
 
          If unsure, say N.
 
index 4ca46edc061d761169a85fc58937dee449a4776f..541fb7a05625aaf889089704ec155956629e77c8 100644 (file)
@@ -53,6 +53,8 @@
 #define USB_OEM_MERCURY_PRODUCT_ID     34
 #define USB_OEM_LEAF_PRODUCT_ID                35
 #define USB_CAN_R_PRODUCT_ID           39
+#define USB_LEAF_LITE_V2_PRODUCT_ID    288
+#define USB_MINI_PCIE_HS_PRODUCT_ID    289
 
 /* USB devices features */
 #define KVASER_HAS_SILENT_MODE         BIT(0)
@@ -356,6 +358,8 @@ static const struct usb_device_id kvaser_usb_table[] = {
                .driver_info = KVASER_HAS_TXRX_ERRORS },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
                .driver_info = KVASER_HAS_TXRX_ERRORS },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -379,38 +383,43 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
        void *buf;
        int actual_len;
        int err;
-       int pos = 0;
+       int pos;
+       unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT);
 
        buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       err = usb_bulk_msg(dev->udev,
-                          usb_rcvbulkpipe(dev->udev,
-                                          dev->bulk_in->bEndpointAddress),
-                          buf, RX_BUFFER_SIZE, &actual_len,
-                          USB_RECV_TIMEOUT);
-       if (err < 0)
-               goto end;
+       do {
+               err = usb_bulk_msg(dev->udev,
+                                  usb_rcvbulkpipe(dev->udev,
+                                       dev->bulk_in->bEndpointAddress),
+                                  buf, RX_BUFFER_SIZE, &actual_len,
+                                  USB_RECV_TIMEOUT);
+               if (err < 0)
+                       goto end;
 
-       while (pos <= actual_len - MSG_HEADER_LEN) {
-               tmp = buf + pos;
+               pos = 0;
+               while (pos <= actual_len - MSG_HEADER_LEN) {
+                       tmp = buf + pos;
 
-               if (!tmp->len)
-                       break;
+                       if (!tmp->len)
+                               break;
 
-               if (pos + tmp->len > actual_len) {
-                       dev_err(dev->udev->dev.parent, "Format error\n");
-                       break;
-               }
+                       if (pos + tmp->len > actual_len) {
+                               dev_err(dev->udev->dev.parent,
+                                       "Format error\n");
+                               break;
+                       }
 
-               if (tmp->id == id) {
-                       memcpy(msg, tmp, tmp->len);
-                       goto end;
-               }
+                       if (tmp->id == id) {
+                               memcpy(msg, tmp, tmp->len);
+                               goto end;
+                       }
 
-               pos += tmp->len;
-       }
+                       pos += tmp->len;
+               }
+       } while (time_before(jiffies, to));
 
        err = -EINVAL;
 
index 41ee5b6ae91751239d81e4613f336aff02fbff84..69c42513dd724bb06ef40eaf4b5e4bbea800936d 100644 (file)
@@ -289,7 +289,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
 
 static int mv88e6123_61_65_setup(struct dsa_switch *ds)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int i;
        int ret;
 
index dadfafba64e9ac0aad3de55d84e5bdea3ceb00a0..953bc6a49e594471342270e7281a8e263f0086de 100644 (file)
@@ -155,7 +155,7 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
 
 static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int addr = REG_PORT(p);
        u16 val;
 
@@ -274,7 +274,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
 
 static int mv88e6131_setup(struct dsa_switch *ds)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int i;
        int ret;
 
index 17314ed9456d32c961aea31db10a650a2ffb1392..9ce2146346b6cda7175229d0f493f004730ab1b1 100644 (file)
@@ -74,7 +74,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
 
 int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int ret;
 
        mutex_lock(&ps->smi_mutex);
@@ -118,7 +118,7 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
 
 int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int ret;
 
        mutex_lock(&ps->smi_mutex);
@@ -256,7 +256,7 @@ static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
 
 static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int ret;
 
        mutex_lock(&ps->ppu_mutex);
@@ -283,7 +283,7 @@ static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
 
 static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
        /* Schedule a timer to re-enable the PHY polling unit. */
        mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
@@ -292,7 +292,7 @@ static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
 
 void mv88e6xxx_ppu_state_init(struct dsa_switch *ds)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
        mutex_init(&ps->ppu_mutex);
        INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
@@ -463,7 +463,7 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
                                 int nr_stats, struct mv88e6xxx_hw_stat *stats,
                                 int port, uint64_t *data)
 {
-       struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int ret;
        int i;
 
index 80c1ab74a4b8f36483ebe710aa56ffb3879d52bc..fdddba51473efce74edbf9c0befae1ebdfbe1824 100644 (file)
@@ -1,5 +1,6 @@
 config ALTERA_TSE
        tristate "Altera Triple-Speed Ethernet MAC support"
+       depends on HAS_DMA
        select PHYLIB
        ---help---
          This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
index 3df18669ea306580994cb877044a000aa4b7e6f9..38c500f95b9e97249dfd7b1e4b14dab0d6a12816 100644 (file)
@@ -18,6 +18,7 @@
 #include "altera_utils.h"
 #include "altera_tse.h"
 #include "altera_msgdmahw.h"
+#include "altera_msgdma.h"
 
 /* No initialization work to do for MSGDMA */
 int msgdma_initialize(struct altera_tse_private *priv)
@@ -29,13 +30,15 @@ void msgdma_uninitialize(struct altera_tse_private *priv)
 {
 }
 
+void msgdma_start_rxdma(struct altera_tse_private *priv)
+{
+}
+
 void msgdma_reset(struct altera_tse_private *priv)
 {
        int counter;
-       struct msgdma_csr *txcsr =
-               (struct msgdma_csr *)priv->tx_dma_csr;
-       struct msgdma_csr *rxcsr =
-               (struct msgdma_csr *)priv->rx_dma_csr;
+       struct msgdma_csr *txcsr = priv->tx_dma_csr;
+       struct msgdma_csr *rxcsr = priv->rx_dma_csr;
 
        /* Reset Rx mSGDMA */
        iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
@@ -133,8 +136,7 @@ u32 msgdma_tx_completions(struct altera_tse_private *priv)
        u32 ready = 0;
        u32 inuse;
        u32 status;
-       struct msgdma_csr *txcsr =
-               (struct msgdma_csr *)priv->tx_dma_csr;
+       struct msgdma_csr *txcsr = priv->tx_dma_csr;
 
        /* Get number of sent descriptors */
        inuse = ioread32(&txcsr->rw_fill_level) & 0xffff;
@@ -154,7 +156,7 @@ u32 msgdma_tx_completions(struct altera_tse_private *priv)
 
 /* Put buffer to the mSGDMA RX FIFO
  */
-int msgdma_add_rx_desc(struct altera_tse_private *priv,
+void msgdma_add_rx_desc(struct altera_tse_private *priv,
                        struct tse_buffer *rxbuffer)
 {
        struct msgdma_extended_desc *desc = priv->rx_dma_desc;
@@ -175,7 +177,6 @@ int msgdma_add_rx_desc(struct altera_tse_private *priv,
        iowrite32(0, &desc->burst_seq_num);
        iowrite32(0x00010001, &desc->stride);
        iowrite32(control, &desc->control);
-       return 1;
 }
 
 /* status is returned on upper 16 bits,
@@ -186,10 +187,8 @@ u32 msgdma_rx_status(struct altera_tse_private *priv)
        u32 rxstatus = 0;
        u32 pktlength;
        u32 pktstatus;
-       struct msgdma_csr *rxcsr =
-               (struct msgdma_csr *)priv->rx_dma_csr;
-       struct msgdma_response *rxresp =
-               (struct msgdma_response *)priv->rx_dma_resp;
+       struct msgdma_csr *rxcsr = priv->rx_dma_csr;
+       struct msgdma_response *rxresp = priv->rx_dma_resp;
 
        if (ioread32(&rxcsr->resp_fill_level) & 0xffff) {
                pktlength = ioread32(&rxresp->bytes_transferred);
index 7f0f5bf2bba2f42952ea69307c44a334f6784b59..42cf61c81057be8f4c3f2213dfdd9e89de7dee15 100644 (file)
@@ -25,10 +25,11 @@ void msgdma_disable_txirq(struct altera_tse_private *);
 void msgdma_clear_rxirq(struct altera_tse_private *);
 void msgdma_clear_txirq(struct altera_tse_private *);
 u32 msgdma_tx_completions(struct altera_tse_private *);
-int msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *);
+void msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *);
 int msgdma_tx_buffer(struct altera_tse_private *, struct tse_buffer *);
 u32 msgdma_rx_status(struct altera_tse_private *);
 int msgdma_initialize(struct altera_tse_private *);
 void msgdma_uninitialize(struct altera_tse_private *);
+void msgdma_start_rxdma(struct altera_tse_private *);
 
 #endif /*  __ALTERA_MSGDMA_H__ */
index 0ee96639ae44e7a238ac36682868443caa7c43c3..dbd40e15b5ccc291325cea972a0c250cc5a84a0e 100644 (file)
 #include "altera_sgdmahw.h"
 #include "altera_sgdma.h"
 
-static void sgdma_descrip(struct sgdma_descrip *desc,
-                         struct sgdma_descrip *ndesc,
-                         dma_addr_t ndesc_phys,
-                         dma_addr_t raddr,
-                         dma_addr_t waddr,
-                         u16 length,
-                         int generate_eop,
-                         int rfixed,
-                         int wfixed);
+static void sgdma_setup_descrip(struct sgdma_descrip *desc,
+                               struct sgdma_descrip *ndesc,
+                               dma_addr_t ndesc_phys,
+                               dma_addr_t raddr,
+                               dma_addr_t waddr,
+                               u16 length,
+                               int generate_eop,
+                               int rfixed,
+                               int wfixed);
 
 static int sgdma_async_write(struct altera_tse_private *priv,
                              struct sgdma_descrip *desc);
@@ -64,11 +64,15 @@ queue_rx_peekhead(struct altera_tse_private *priv);
 
 int sgdma_initialize(struct altera_tse_private *priv)
 {
-       priv->txctrlreg = SGDMA_CTRLREG_ILASTD;
+       priv->txctrlreg = SGDMA_CTRLREG_ILASTD |
+                     SGDMA_CTRLREG_INTEN;
 
        priv->rxctrlreg = SGDMA_CTRLREG_IDESCRIP |
+                     SGDMA_CTRLREG_INTEN |
                      SGDMA_CTRLREG_ILASTD;
 
+       priv->sgdmadesclen = sizeof(struct sgdma_descrip);
+
        INIT_LIST_HEAD(&priv->txlisthd);
        INIT_LIST_HEAD(&priv->rxlisthd);
 
@@ -93,6 +97,16 @@ int sgdma_initialize(struct altera_tse_private *priv)
                return -EINVAL;
        }
 
+       /* Initialize descriptor memory to all 0's, sync memory to cache */
+       memset(priv->tx_dma_desc, 0, priv->txdescmem);
+       memset(priv->rx_dma_desc, 0, priv->rxdescmem);
+
+       dma_sync_single_for_device(priv->device, priv->txdescphys,
+                                  priv->txdescmem, DMA_TO_DEVICE);
+
+       dma_sync_single_for_device(priv->device, priv->rxdescphys,
+                                  priv->rxdescmem, DMA_TO_DEVICE);
+
        return 0;
 }
 
@@ -112,12 +126,12 @@ void sgdma_uninitialize(struct altera_tse_private *priv)
  */
 void sgdma_reset(struct altera_tse_private *priv)
 {
-       u32 *ptxdescripmem = (u32 *)priv->tx_dma_desc;
+       u32 *ptxdescripmem = priv->tx_dma_desc;
        u32 txdescriplen   = priv->txdescmem;
-       u32 *prxdescripmem = (u32 *)priv->rx_dma_desc;
+       u32 *prxdescripmem = priv->rx_dma_desc;
        u32 rxdescriplen   = priv->rxdescmem;
-       struct sgdma_csr *ptxsgdma = (struct sgdma_csr *)priv->tx_dma_csr;
-       struct sgdma_csr *prxsgdma = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_csr *ptxsgdma = priv->tx_dma_csr;
+       struct sgdma_csr *prxsgdma = priv->rx_dma_csr;
 
        /* Initialize descriptor memory to 0 */
        memset(ptxdescripmem, 0, txdescriplen);
@@ -130,39 +144,36 @@ void sgdma_reset(struct altera_tse_private *priv)
        iowrite32(0, &prxsgdma->control);
 }
 
+/* For SGDMA, interrupts remain enabled after initially enabling,
+ * so no need to provide implementations for abstract enable
+ * and disable
+ */
+
 void sgdma_enable_rxirq(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
-       priv->rxctrlreg |= SGDMA_CTRLREG_INTEN;
-       tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
 }
 
 void sgdma_enable_txirq(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
-       priv->txctrlreg |= SGDMA_CTRLREG_INTEN;
-       tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
 }
 
-/* for SGDMA, RX interrupts remain enabled after enabling */
 void sgdma_disable_rxirq(struct altera_tse_private *priv)
 {
 }
 
-/* for SGDMA, TX interrupts remain enabled after enabling */
 void sgdma_disable_txirq(struct altera_tse_private *priv)
 {
 }
 
 void sgdma_clear_rxirq(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_csr *csr = priv->rx_dma_csr;
        tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
 }
 
 void sgdma_clear_txirq(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       struct sgdma_csr *csr = priv->tx_dma_csr;
        tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
 }
 
@@ -174,8 +185,7 @@ void sgdma_clear_txirq(struct altera_tse_private *priv)
 int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
 {
        int pktstx = 0;
-       struct sgdma_descrip *descbase =
-               (struct sgdma_descrip *)priv->tx_dma_desc;
+       struct sgdma_descrip *descbase = priv->tx_dma_desc;
 
        struct sgdma_descrip *cdesc = &descbase[0];
        struct sgdma_descrip *ndesc = &descbase[1];
@@ -184,15 +194,15 @@ int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
        if (sgdma_txbusy(priv))
                return 0;
 
-       sgdma_descrip(cdesc,                    /* current descriptor */
-                     ndesc,                    /* next descriptor */
-                     sgdma_txphysaddr(priv, ndesc),
-                     buffer->dma_addr,         /* address of packet to xmit */
-                     0,                        /* write addr 0 for tx dma */
-                     buffer->len,              /* length of packet */
-                     SGDMA_CONTROL_EOP,        /* Generate EOP */
-                     0,                        /* read fixed */
-                     SGDMA_CONTROL_WR_FIXED);  /* Generate SOP */
+       sgdma_setup_descrip(cdesc,                      /* current descriptor */
+                           ndesc,                      /* next descriptor */
+                           sgdma_txphysaddr(priv, ndesc),
+                           buffer->dma_addr,           /* address of packet to xmit */
+                           0,                          /* write addr 0 for tx dma */
+                           buffer->len,                /* length of packet */
+                           SGDMA_CONTROL_EOP,          /* Generate EOP */
+                           0,                          /* read fixed */
+                           SGDMA_CONTROL_WR_FIXED);    /* Generate SOP */
 
        pktstx = sgdma_async_write(priv, cdesc);
 
@@ -208,7 +218,7 @@ int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
 u32 sgdma_tx_completions(struct altera_tse_private *priv)
 {
        u32 ready = 0;
-       struct sgdma_descrip *desc = (struct sgdma_descrip *)priv->tx_dma_desc;
+       struct sgdma_descrip *desc = priv->tx_dma_desc;
 
        if (!sgdma_txbusy(priv) &&
            ((desc->control & SGDMA_CONTROL_HW_OWNED) == 0) &&
@@ -219,11 +229,15 @@ u32 sgdma_tx_completions(struct altera_tse_private *priv)
        return ready;
 }
 
-int sgdma_add_rx_desc(struct altera_tse_private *priv,
-                     struct tse_buffer *rxbuffer)
+void sgdma_start_rxdma(struct altera_tse_private *priv)
+{
+       sgdma_async_read(priv);
+}
+
+void sgdma_add_rx_desc(struct altera_tse_private *priv,
+                      struct tse_buffer *rxbuffer)
 {
        queue_rx(priv, rxbuffer);
-       return sgdma_async_read(priv);
 }
 
 /* status is returned on upper 16 bits,
@@ -231,8 +245,8 @@ int sgdma_add_rx_desc(struct altera_tse_private *priv,
  */
 u32 sgdma_rx_status(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
-       struct sgdma_descrip *base = (struct sgdma_descrip *)priv->rx_dma_desc;
+       struct sgdma_csr *csr = priv->rx_dma_csr;
+       struct sgdma_descrip *base = priv->rx_dma_desc;
        struct sgdma_descrip *desc = NULL;
        int pktsrx;
        unsigned int rxstatus = 0;
@@ -240,28 +254,52 @@ u32 sgdma_rx_status(struct altera_tse_private *priv)
        unsigned int pktstatus = 0;
        struct tse_buffer *rxbuffer = NULL;
 
-       dma_sync_single_for_cpu(priv->device,
-                               priv->rxdescphys,
-                               priv->rxdescmem,
-                               DMA_BIDIRECTIONAL);
+       u32 sts = ioread32(&csr->status);
 
        desc = &base[0];
-       if ((ioread32(&csr->status) & SGDMA_STSREG_EOP) ||
-           (desc->status & SGDMA_STATUS_EOP)) {
+       if (sts & SGDMA_STSREG_EOP) {
+               dma_sync_single_for_cpu(priv->device,
+                                       priv->rxdescphys,
+                                       priv->sgdmadesclen,
+                                       DMA_FROM_DEVICE);
+
                pktlength = desc->bytes_xferred;
                pktstatus = desc->status & 0x3f;
                rxstatus = pktstatus;
                rxstatus = rxstatus << 16;
                rxstatus |= (pktlength & 0xffff);
 
-               desc->status = 0;
+               if (rxstatus) {
+                       desc->status = 0;
 
-               rxbuffer = dequeue_rx(priv);
-               if (rxbuffer == NULL)
-                       netdev_err(priv->dev,
-                                  "sgdma rx and rx queue empty!\n");
+                       rxbuffer = dequeue_rx(priv);
+                       if (rxbuffer == NULL)
+                               netdev_info(priv->dev,
+                                           "sgdma rx and rx queue empty!\n");
+
+                       /* Clear control */
+                       iowrite32(0, &csr->control);
+                       /* clear status */
+                       iowrite32(0xf, &csr->status);
 
-               /* kick the rx sgdma after reaping this descriptor */
+                       /* kick the rx sgdma after reaping this descriptor */
+                       pktsrx = sgdma_async_read(priv);
+
+               } else {
+                       /* If the SGDMA indicated an end of packet on recv,
+                        * then it's expected that the rxstatus from the
+                        * descriptor is non-zero - meaning a valid packet
+                        * with a nonzero length, or an error has been
+                        * indicated. if not, then all we can do is signal
+                        * an error and return no packet received. Most likely
+                        * there is a system design error, or an error in the
+                        * underlying kernel (cache or cache management problem)
+                        */
+                       netdev_err(priv->dev,
+                                  "SGDMA RX Error Info: %x, %x, %x\n",
+                                  sts, desc->status, rxstatus);
+               }
+       } else if (sts == 0) {
                pktsrx = sgdma_async_read(priv);
        }
 
@@ -270,15 +308,15 @@ u32 sgdma_rx_status(struct altera_tse_private *priv)
 
 
 /* Private functions */
-static void sgdma_descrip(struct sgdma_descrip *desc,
-                         struct sgdma_descrip *ndesc,
-                         dma_addr_t ndesc_phys,
-                         dma_addr_t raddr,
-                         dma_addr_t waddr,
-                         u16 length,
-                         int generate_eop,
-                         int rfixed,
-                         int wfixed)
+static void sgdma_setup_descrip(struct sgdma_descrip *desc,
+                               struct sgdma_descrip *ndesc,
+                               dma_addr_t ndesc_phys,
+                               dma_addr_t raddr,
+                               dma_addr_t waddr,
+                               u16 length,
+                               int generate_eop,
+                               int rfixed,
+                               int wfixed)
 {
        /* Clear the next descriptor as not owned by hardware */
        u32 ctrl = ndesc->control;
@@ -312,42 +350,34 @@ static void sgdma_descrip(struct sgdma_descrip *desc,
  */
 static int sgdma_async_read(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
-       struct sgdma_descrip *descbase =
-               (struct sgdma_descrip *)priv->rx_dma_desc;
-
+       struct sgdma_csr *csr = priv->rx_dma_csr;
+       struct sgdma_descrip *descbase = priv->rx_dma_desc;
        struct sgdma_descrip *cdesc = &descbase[0];
        struct sgdma_descrip *ndesc = &descbase[1];
 
-       unsigned int sts = ioread32(&csr->status);
        struct tse_buffer *rxbuffer = NULL;
 
        if (!sgdma_rxbusy(priv)) {
                rxbuffer = queue_rx_peekhead(priv);
-               if (rxbuffer == NULL)
+               if (rxbuffer == NULL) {
+                       netdev_err(priv->dev, "no rx buffers available\n");
                        return 0;
-
-               sgdma_descrip(cdesc,            /* current descriptor */
-                             ndesc,            /* next descriptor */
-                             sgdma_rxphysaddr(priv, ndesc),
-                             0,                /* read addr 0 for rx dma */
-                             rxbuffer->dma_addr, /* write addr for rx dma */
-                             0,                /* read 'til EOP */
-                             0,                /* EOP: NA for rx dma */
-                             0,                /* read fixed: NA for rx dma */
-                             0);               /* SOP: NA for rx DMA */
-
-               /* clear control and status */
-               iowrite32(0, &csr->control);
-
-               /* If status available, clear those bits */
-               if (sts & 0xf)
-                       iowrite32(0xf, &csr->status);
+               }
+
+               sgdma_setup_descrip(cdesc,              /* current descriptor */
+                                   ndesc,              /* next descriptor */
+                                   sgdma_rxphysaddr(priv, ndesc),
+                                   0,                  /* read addr 0 for rx dma */
+                                   rxbuffer->dma_addr, /* write addr for rx dma */
+                                   0,                  /* read 'til EOP */
+                                   0,                  /* EOP: NA for rx dma */
+                                   0,                  /* read fixed: NA for rx dma */
+                                   0);                 /* SOP: NA for rx DMA */
 
                dma_sync_single_for_device(priv->device,
                                           priv->rxdescphys,
-                                          priv->rxdescmem,
-                                          DMA_BIDIRECTIONAL);
+                                          priv->sgdmadesclen,
+                                          DMA_TO_DEVICE);
 
                iowrite32(lower_32_bits(sgdma_rxphysaddr(priv, cdesc)),
                          &csr->next_descrip);
@@ -364,7 +394,7 @@ static int sgdma_async_read(struct altera_tse_private *priv)
 static int sgdma_async_write(struct altera_tse_private *priv,
                             struct sgdma_descrip *desc)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       struct sgdma_csr *csr = priv->tx_dma_csr;
 
        if (sgdma_txbusy(priv))
                return 0;
@@ -374,7 +404,7 @@ static int sgdma_async_write(struct altera_tse_private *priv,
        iowrite32(0x1f, &csr->status);
 
        dma_sync_single_for_device(priv->device, priv->txdescphys,
-                                  priv->txdescmem, DMA_TO_DEVICE);
+                                  priv->sgdmadesclen, DMA_TO_DEVICE);
 
        iowrite32(lower_32_bits(sgdma_txphysaddr(priv, desc)),
                  &csr->next_descrip);
@@ -485,7 +515,7 @@ queue_rx_peekhead(struct altera_tse_private *priv)
  */
 static int sgdma_rxbusy(struct altera_tse_private *priv)
 {
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_csr *csr = priv->rx_dma_csr;
        return ioread32(&csr->status) & SGDMA_STSREG_BUSY;
 }
 
@@ -495,7 +525,7 @@ static int sgdma_rxbusy(struct altera_tse_private *priv)
 static int sgdma_txbusy(struct altera_tse_private *priv)
 {
        int delay = 0;
-       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       struct sgdma_csr *csr = priv->tx_dma_csr;
 
        /* if DMA is busy, wait for current transactino to finish */
        while ((ioread32(&csr->status) & SGDMA_STSREG_BUSY) && (delay++ < 100))
index 07d471729dc4978deee7fc592962999ec1eff1f3..584977e29ef944e1132f3ec779d7cdf1f9572160 100644 (file)
@@ -26,10 +26,11 @@ void sgdma_clear_rxirq(struct altera_tse_private *);
 void sgdma_clear_txirq(struct altera_tse_private *);
 int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *);
 u32 sgdma_tx_completions(struct altera_tse_private *);
-int sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *);
+void sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *);
 void sgdma_status(struct altera_tse_private *);
 u32 sgdma_rx_status(struct altera_tse_private *);
 int sgdma_initialize(struct altera_tse_private *);
 void sgdma_uninitialize(struct altera_tse_private *);
+void sgdma_start_rxdma(struct altera_tse_private *);
 
 #endif /*  __ALTERA_SGDMA_H__ */
index 8feeed05de0e14829718a1bec85fbb94af6699e6..465c4aabebbd49d299cb266544c3469acd0f3b6b 100644 (file)
@@ -58,6 +58,8 @@
 /* MAC function configuration default settings */
 #define ALTERA_TSE_TX_IPG_LENGTH       12
 
+#define ALTERA_TSE_PAUSE_QUANTA                0xffff
+
 #define GET_BIT_VALUE(v, bit)          (((v) >> (bit)) & 0x1)
 
 /* MAC Command_Config Register Bit Definitions
@@ -390,10 +392,11 @@ struct altera_dmaops {
        void (*clear_rxirq)(struct altera_tse_private *);
        int (*tx_buffer)(struct altera_tse_private *, struct tse_buffer *);
        u32 (*tx_completions)(struct altera_tse_private *);
-       int (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *);
+       void (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *);
        u32 (*get_rx_status)(struct altera_tse_private *);
        int (*init_dma)(struct altera_tse_private *);
        void (*uninit_dma)(struct altera_tse_private *);
+       void (*start_rxdma)(struct altera_tse_private *);
 };
 
 /* This structure is private to each device.
@@ -453,6 +456,7 @@ struct altera_tse_private {
        u32 rxctrlreg;
        dma_addr_t rxdescphys;
        dma_addr_t txdescphys;
+       size_t sgdmadesclen;
 
        struct list_head txlisthd;
        struct list_head rxlisthd;
index 319ca74f5e7480b23bc0ce63f9dca0a25ce894b2..76133caffa78eb3b1e385525fdfc7fda142e77e1 100644 (file)
@@ -77,7 +77,7 @@ static void tse_get_drvinfo(struct net_device *dev,
        struct altera_tse_private *priv = netdev_priv(dev);
        u32 rev = ioread32(&priv->mac_dev->megacore_revision);
 
-       strcpy(info->driver, "Altera TSE MAC IP Driver");
+       strcpy(info->driver, "altera_tse");
        strcpy(info->version, "v8.0");
        snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",
                 rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
@@ -185,6 +185,12 @@ static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
         * how to do any special formatting of this data.
         * This version number will need to change if and
         * when this register table is changed.
+        *
+        * version[31:0] = 1: Dump the first 128 TSE Registers
+        *      Upper bits are all 0 by default
+        *
+        * Upper 16-bits will indicate feature presence for
+        * Ethtool register decoding in future version.
         */
 
        regs->version = 1;
index c70a29e0b9f79115cc697df95b52757830651ea3..e44a4aeb970142a6622d77c52b30a27c58a6e786 100644 (file)
@@ -224,6 +224,7 @@ static int tse_init_rx_buffer(struct altera_tse_private *priv,
                dev_kfree_skb_any(rxbuffer->skb);
                return -EINVAL;
        }
+       rxbuffer->dma_addr &= (dma_addr_t)~3;
        rxbuffer->len = len;
        return 0;
 }
@@ -425,9 +426,10 @@ static int tse_rx(struct altera_tse_private *priv, int limit)
                priv->dev->stats.rx_bytes += pktlength;
 
                entry = next_entry;
+
+               tse_rx_refill(priv);
        }
 
-       tse_rx_refill(priv);
        return count;
 }
 
@@ -520,7 +522,6 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
        struct altera_tse_private *priv;
        unsigned long int flags;
 
-
        if (unlikely(!dev)) {
                pr_err("%s: invalid dev pointer\n", __func__);
                return IRQ_NONE;
@@ -868,13 +869,13 @@ static int init_mac(struct altera_tse_private *priv)
        /* Disable RX/TX shift 16 for alignment of all received frames on 16-bit
         * start address
         */
-       tse_clear_bit(&mac->rx_cmd_stat, ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16);
+       tse_set_bit(&mac->rx_cmd_stat, ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16);
        tse_clear_bit(&mac->tx_cmd_stat, ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 |
                                         ALTERA_TSE_TX_CMD_STAT_OMIT_CRC);
 
        /* Set the MAC options */
        cmd = ioread32(&mac->command_config);
-       cmd |= MAC_CMDCFG_PAD_EN;       /* Padding Removal on Receive */
+       cmd &= ~MAC_CMDCFG_PAD_EN;      /* No padding Removal on Receive */
        cmd &= ~MAC_CMDCFG_CRC_FWD;     /* CRC Removal */
        cmd |= MAC_CMDCFG_RX_ERR_DISC;  /* Automatically discard frames
                                         * with CRC errors
@@ -882,8 +883,16 @@ static int init_mac(struct altera_tse_private *priv)
        cmd |= MAC_CMDCFG_CNTL_FRM_ENA;
        cmd &= ~MAC_CMDCFG_TX_ENA;
        cmd &= ~MAC_CMDCFG_RX_ENA;
+
+       /* Default speed and duplex setting, full/100 */
+       cmd &= ~MAC_CMDCFG_HD_ENA;
+       cmd &= ~MAC_CMDCFG_ETH_SPEED;
+       cmd &= ~MAC_CMDCFG_ENA_10;
+
        iowrite32(cmd, &mac->command_config);
 
+       iowrite32(ALTERA_TSE_PAUSE_QUANTA, &mac->pause_quanta);
+
        if (netif_msg_hw(priv))
                dev_dbg(priv->device,
                        "MAC post-initialization: CMD_CONFIG = 0x%08x\n", cmd);
@@ -1085,17 +1094,19 @@ static int tse_open(struct net_device *dev)
 
        spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
 
-       /* Start MAC Rx/Tx */
-       spin_lock(&priv->mac_cfg_lock);
-       tse_set_mac(priv, true);
-       spin_unlock(&priv->mac_cfg_lock);
-
        if (priv->phydev)
                phy_start(priv->phydev);
 
        napi_enable(&priv->napi);
        netif_start_queue(dev);
 
+       priv->dmaops->start_rxdma(priv);
+
+       /* Start MAC Rx/Tx */
+       spin_lock(&priv->mac_cfg_lock);
+       tse_set_mac(priv, true);
+       spin_unlock(&priv->mac_cfg_lock);
+
        return 0;
 
 tx_request_irq_error:
@@ -1167,7 +1178,6 @@ static struct net_device_ops altera_tse_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-
 static int request_and_map(struct platform_device *pdev, const char *name,
                           struct resource **res, void __iomem **ptr)
 {
@@ -1235,7 +1245,7 @@ static int altera_tse_probe(struct platform_device *pdev)
                /* Get the mapped address to the SGDMA descriptor memory */
                ret = request_and_map(pdev, "s1", &dma_res, &descmap);
                if (ret)
-                       goto out_free;
+                       goto err_free_netdev;
 
                /* Start of that memory is for transmit descriptors */
                priv->tx_dma_desc = descmap;
@@ -1254,24 +1264,24 @@ static int altera_tse_probe(struct platform_device *pdev)
                if (upper_32_bits(priv->rxdescmem_busaddr)) {
                        dev_dbg(priv->device,
                                "SGDMA bus addresses greater than 32-bits\n");
-                       goto out_free;
+                       goto err_free_netdev;
                }
                if (upper_32_bits(priv->txdescmem_busaddr)) {
                        dev_dbg(priv->device,
                                "SGDMA bus addresses greater than 32-bits\n");
-                       goto out_free;
+                       goto err_free_netdev;
                }
        } else if (priv->dmaops &&
                   priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) {
                ret = request_and_map(pdev, "rx_resp", &dma_res,
                                      &priv->rx_dma_resp);
                if (ret)
-                       goto out_free;
+                       goto err_free_netdev;
 
                ret = request_and_map(pdev, "tx_desc", &dma_res,
                                      &priv->tx_dma_desc);
                if (ret)
-                       goto out_free;
+                       goto err_free_netdev;
 
                priv->txdescmem = resource_size(dma_res);
                priv->txdescmem_busaddr = dma_res->start;
@@ -1279,13 +1289,13 @@ static int altera_tse_probe(struct platform_device *pdev)
                ret = request_and_map(pdev, "rx_desc", &dma_res,
                                      &priv->rx_dma_desc);
                if (ret)
-                       goto out_free;
+                       goto err_free_netdev;
 
                priv->rxdescmem = resource_size(dma_res);
                priv->rxdescmem_busaddr = dma_res->start;
 
        } else {
-               goto out_free;
+               goto err_free_netdev;
        }
 
        if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
@@ -1294,26 +1304,26 @@ static int altera_tse_probe(struct platform_device *pdev)
        else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
                dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
        else
-               goto out_free;
+               goto err_free_netdev;
 
        /* MAC address space */
        ret = request_and_map(pdev, "control_port", &control_port,
                              (void __iomem **)&priv->mac_dev);
        if (ret)
-               goto out_free;
+               goto err_free_netdev;
 
        /* xSGDMA Rx Dispatcher address space */
        ret = request_and_map(pdev, "rx_csr", &dma_res,
                              &priv->rx_dma_csr);
        if (ret)
-               goto out_free;
+               goto err_free_netdev;
 
 
        /* xSGDMA Tx Dispatcher address space */
        ret = request_and_map(pdev, "tx_csr", &dma_res,
                              &priv->tx_dma_csr);
        if (ret)
-               goto out_free;
+               goto err_free_netdev;
 
 
        /* Rx IRQ */
@@ -1321,7 +1331,7 @@ static int altera_tse_probe(struct platform_device *pdev)
        if (priv->rx_irq == -ENXIO) {
                dev_err(&pdev->dev, "cannot obtain Rx IRQ\n");
                ret = -ENXIO;
-               goto out_free;
+               goto err_free_netdev;
        }
 
        /* Tx IRQ */
@@ -1329,7 +1339,7 @@ static int altera_tse_probe(struct platform_device *pdev)
        if (priv->tx_irq == -ENXIO) {
                dev_err(&pdev->dev, "cannot obtain Tx IRQ\n");
                ret = -ENXIO;
-               goto out_free;
+               goto err_free_netdev;
        }
 
        /* get FIFO depths from device tree */
@@ -1337,14 +1347,14 @@ static int altera_tse_probe(struct platform_device *pdev)
                                 &priv->rx_fifo_depth)) {
                dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n");
                ret = -ENXIO;
-               goto out_free;
+               goto err_free_netdev;
        }
 
        if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
                                 &priv->rx_fifo_depth)) {
                dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
                ret = -ENXIO;
-               goto out_free;
+               goto err_free_netdev;
        }
 
        /* get hash filter settings for this instance */
@@ -1393,7 +1403,7 @@ static int altera_tse_probe(struct platform_device *pdev)
              ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) {
                dev_err(&pdev->dev, "invalid phy-addr specified %d\n",
                        priv->phy_addr);
-               goto out_free;
+               goto err_free_netdev;
        }
 
        /* Create/attach to MDIO bus */
@@ -1401,7 +1411,7 @@ static int altera_tse_probe(struct platform_device *pdev)
                                     atomic_add_return(1, &instance_count));
 
        if (ret)
-               goto out_free;
+               goto err_free_netdev;
 
        /* initialize netdev */
        ether_setup(ndev);
@@ -1438,7 +1448,7 @@ static int altera_tse_probe(struct platform_device *pdev)
        ret = register_netdev(ndev);
        if (ret) {
                dev_err(&pdev->dev, "failed to register TSE net device\n");
-               goto out_free_mdio;
+               goto err_register_netdev;
        }
 
        platform_set_drvdata(pdev, ndev);
@@ -1455,13 +1465,16 @@ static int altera_tse_probe(struct platform_device *pdev)
        ret = init_phy(ndev);
        if (ret != 0) {
                netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret);
-               goto out_free_mdio;
+               goto err_init_phy;
        }
        return 0;
 
-out_free_mdio:
+err_init_phy:
+       unregister_netdev(ndev);
+err_register_netdev:
+       netif_napi_del(&priv->napi);
        altera_tse_mdio_destroy(ndev);
-out_free:
+err_free_netdev:
        free_netdev(ndev);
        return ret;
 }
@@ -1496,6 +1509,7 @@ struct altera_dmaops altera_dtype_sgdma = {
        .get_rx_status = sgdma_rx_status,
        .init_dma = sgdma_initialize,
        .uninit_dma = sgdma_uninitialize,
+       .start_rxdma = sgdma_start_rxdma,
 };
 
 struct altera_dmaops altera_dtype_msgdma = {
@@ -1514,6 +1528,7 @@ struct altera_dmaops altera_dtype_msgdma = {
        .get_rx_status = msgdma_rx_status,
        .init_dma = msgdma_initialize,
        .uninit_dma = msgdma_uninitialize,
+       .start_rxdma = msgdma_start_rxdma,
 };
 
 static struct of_device_id altera_tse_ids[] = {
index 928fac6dd10a90dca66244dba99194c9c9e2924d..53f85bf715268db94d864695321e3890454719ce 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/phy.h>
+#include <linux/clk.h>
 
 /* STATUS and ENABLE Register bit masks */
 #define TXINT_MASK     (1<<0)  /* Transmit interrupt */
@@ -131,6 +132,7 @@ struct arc_emac_priv {
        struct mii_bus *bus;
 
        void __iomem *regs;
+       struct clk *clk;
 
        struct napi_struct napi;
        struct net_device_stats stats;
index eeecc29cf5b7d2695739d819fe900e798bf38996..d647a7d115acb2e7d40f72ee5010cd1e6ea79982 100644 (file)
@@ -574,6 +574,18 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
        return NETDEV_TX_OK;
 }
 
+static void arc_emac_set_address_internal(struct net_device *ndev)
+{
+       struct arc_emac_priv *priv = netdev_priv(ndev);
+       unsigned int addr_low, addr_hi;
+
+       addr_low = le32_to_cpu(*(__le32 *) &ndev->dev_addr[0]);
+       addr_hi = le16_to_cpu(*(__le16 *) &ndev->dev_addr[4]);
+
+       arc_reg_set(priv, R_ADDRL, addr_low);
+       arc_reg_set(priv, R_ADDRH, addr_hi);
+}
+
 /**
  * arc_emac_set_address - Set the MAC address for this device.
  * @ndev:      Pointer to net_device structure.
@@ -587,9 +599,7 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
  */
 static int arc_emac_set_address(struct net_device *ndev, void *p)
 {
-       struct arc_emac_priv *priv = netdev_priv(ndev);
        struct sockaddr *addr = p;
-       unsigned int addr_low, addr_hi;
 
        if (netif_running(ndev))
                return -EBUSY;
@@ -599,11 +609,7 @@ static int arc_emac_set_address(struct net_device *ndev, void *p)
 
        memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
 
-       addr_low = le32_to_cpu(*(__le32 *) &ndev->dev_addr[0]);
-       addr_hi = le16_to_cpu(*(__le16 *) &ndev->dev_addr[4]);
-
-       arc_reg_set(priv, R_ADDRL, addr_low);
-       arc_reg_set(priv, R_ADDRH, addr_hi);
+       arc_emac_set_address_internal(ndev);
 
        return 0;
 }
@@ -643,13 +649,6 @@ static int arc_emac_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       /* Get CPU clock frequency from device tree */
-       if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-                                &clock_frequency)) {
-               dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n");
-               return -EINVAL;
-       }
-
        /* Get IRQ from device tree */
        irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
        if (!irq) {
@@ -677,17 +676,36 @@ static int arc_emac_probe(struct platform_device *pdev)
        priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs);
        if (IS_ERR(priv->regs)) {
                err = PTR_ERR(priv->regs);
-               goto out;
+               goto out_netdev;
        }
        dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs);
 
+       priv->clk = of_clk_get(pdev->dev.of_node, 0);
+       if (IS_ERR(priv->clk)) {
+               /* Get CPU clock frequency from device tree */
+               if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                                       &clock_frequency)) {
+                       dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n");
+                       err = -EINVAL;
+                       goto out_netdev;
+               }
+       } else {
+               err = clk_prepare_enable(priv->clk);
+               if (err) {
+                       dev_err(&pdev->dev, "failed to enable clock\n");
+                       goto out_clkget;
+               }
+
+               clock_frequency = clk_get_rate(priv->clk);
+       }
+
        id = arc_reg_get(priv, R_ID);
 
        /* Check for EMAC revision 5 or 7, magic number */
        if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
                dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id);
                err = -ENODEV;
-               goto out;
+               goto out_clken;
        }
        dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id);
 
@@ -702,7 +720,7 @@ static int arc_emac_probe(struct platform_device *pdev)
                               ndev->name, ndev);
        if (err) {
                dev_err(&pdev->dev, "could not allocate IRQ\n");
-               goto out;
+               goto out_clken;
        }
 
        /* Get MAC address from device tree */
@@ -713,6 +731,7 @@ static int arc_emac_probe(struct platform_device *pdev)
        else
                eth_hw_addr_random(ndev);
 
+       arc_emac_set_address_internal(ndev);
        dev_info(&pdev->dev, "MAC address is now %pM\n", ndev->dev_addr);
 
        /* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
@@ -722,7 +741,7 @@ static int arc_emac_probe(struct platform_device *pdev)
        if (!priv->rxbd) {
                dev_err(&pdev->dev, "failed to allocate data buffers\n");
                err = -ENOMEM;
-               goto out;
+               goto out_clken;
        }
 
        priv->txbd = priv->rxbd + RX_BD_NUM;
@@ -734,7 +753,7 @@ static int arc_emac_probe(struct platform_device *pdev)
        err = arc_mdio_probe(pdev, priv);
        if (err) {
                dev_err(&pdev->dev, "failed to probe MII bus\n");
-               goto out;
+               goto out_clken;
        }
 
        priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
@@ -742,7 +761,7 @@ static int arc_emac_probe(struct platform_device *pdev)
        if (!priv->phy_dev) {
                dev_err(&pdev->dev, "of_phy_connect() failed\n");
                err = -ENODEV;
-               goto out;
+               goto out_mdio;
        }
 
        dev_info(&pdev->dev, "connected to %s phy with id 0x%x\n",
@@ -752,14 +771,25 @@ static int arc_emac_probe(struct platform_device *pdev)
 
        err = register_netdev(ndev);
        if (err) {
-               netif_napi_del(&priv->napi);
                dev_err(&pdev->dev, "failed to register network device\n");
-               goto out;
+               goto out_netif_api;
        }
 
        return 0;
 
-out:
+out_netif_api:
+       netif_napi_del(&priv->napi);
+       phy_disconnect(priv->phy_dev);
+       priv->phy_dev = NULL;
+out_mdio:
+       arc_mdio_remove(priv);
+out_clken:
+       if (!IS_ERR(priv->clk))
+               clk_disable_unprepare(priv->clk);
+out_clkget:
+       if (!IS_ERR(priv->clk))
+               clk_put(priv->clk);
+out_netdev:
        free_netdev(ndev);
        return err;
 }
@@ -774,6 +804,12 @@ static int arc_emac_remove(struct platform_device *pdev)
        arc_mdio_remove(priv);
        unregister_netdev(ndev);
        netif_napi_del(&priv->napi);
+
+       if (!IS_ERR(priv->clk)) {
+               clk_disable_unprepare(priv->clk);
+               clk_put(priv->clk);
+       }
+
        free_netdev(ndev);
 
        return 0;
index 85dbddd03722b20a861f53cba7fe00b6cb66f3db..3e488094b0731811459c66dcb0517d00cb7dfbbe 100644 (file)
@@ -150,4 +150,15 @@ config BGMAC
          In case of using this driver on BCM4706 it's also requires to enable
          BCMA_DRIVER_GMAC_CMN to make it work.
 
+config SYSTEMPORT
+       tristate "Broadcom SYSTEMPORT internal MAC support"
+       depends on OF
+       select MII
+       select PHYLIB
+       select FIXED_PHY if SYSTEMPORT=y
+       help
+         This driver supports the built-in Ethernet MACs found in the
+         Broadcom BCM7xxx Set Top Box family chipset using an internal
+         Ethernet switch.
+
 endif # NET_VENDOR_BROADCOM
index fd639a0d4c7d64b2b7db5eb084087502e3c6d63a..e2a958a657e0bb8f816d205e0792d3fdfbfc70a4 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_BNX2X) += bnx2x/
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BGMAC) += bgmac.o
+obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
index a7d11f5565d69342ad296471a9a5d44f8d7c51d5..8db34d3896758346a0dfeb24458f4a81119da720 100644 (file)
@@ -1315,8 +1315,7 @@ static const struct bcm_enet_stats bcm_enet_gstrings_stats[] = {
 
 };
 
-#define BCM_ENET_STATS_LEN     \
-       (sizeof(bcm_enet_gstrings_stats) / sizeof(struct bcm_enet_stats))
+#define BCM_ENET_STATS_LEN     ARRAY_SIZE(bcm_enet_gstrings_stats)
 
 static const u32 unused_mib_regs[] = {
        ETH_MIB_TX_ALL_OCTETS,
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
new file mode 100644 (file)
index 0000000..4dc8d1e
--- /dev/null
@@ -0,0 +1,1614 @@
+/*
+ * Broadcom BCM7xxx System Port Ethernet MAC driver
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+
+#include "bcmsysport.h"
+
+/* I/O accessors register helpers */
+#define BCM_SYSPORT_IO_MACRO(name, offset) \
+static inline u32 name##_readl(struct bcm_sysport_priv *priv, u32 off) \
+{                                                                      \
+       u32 reg = __raw_readl(priv->base + offset + off);               \
+       return reg;                                                     \
+}                                                                      \
+static inline void name##_writel(struct bcm_sysport_priv *priv,                \
+                                 u32 val, u32 off)                     \
+{                                                                      \
+       __raw_writel(val, priv->base + offset + off);                   \
+}                                                                      \
+
+BCM_SYSPORT_IO_MACRO(intrl2_0, SYS_PORT_INTRL2_0_OFFSET);
+BCM_SYSPORT_IO_MACRO(intrl2_1, SYS_PORT_INTRL2_1_OFFSET);
+BCM_SYSPORT_IO_MACRO(umac, SYS_PORT_UMAC_OFFSET);
+BCM_SYSPORT_IO_MACRO(tdma, SYS_PORT_TDMA_OFFSET);
+BCM_SYSPORT_IO_MACRO(rdma, SYS_PORT_RDMA_OFFSET);
+BCM_SYSPORT_IO_MACRO(rxchk, SYS_PORT_RXCHK_OFFSET);
+BCM_SYSPORT_IO_MACRO(txchk, SYS_PORT_TXCHK_OFFSET);
+BCM_SYSPORT_IO_MACRO(rbuf, SYS_PORT_RBUF_OFFSET);
+BCM_SYSPORT_IO_MACRO(tbuf, SYS_PORT_TBUF_OFFSET);
+BCM_SYSPORT_IO_MACRO(topctrl, SYS_PORT_TOPCTRL_OFFSET);
+
+/* L2-interrupt masking/unmasking helpers, does automatic saving of the applied
+ * mask in a software copy to avoid CPU_MASK_STATUS reads in hot-paths.
+  */
+#define BCM_SYSPORT_INTR_L2(which)     \
+static inline void intrl2_##which##_mask_clear(struct bcm_sysport_priv *priv, \
+                                               u32 mask)               \
+{                                                                      \
+       intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);     \
+       priv->irq##which##_mask &= ~(mask);                             \
+}                                                                      \
+static inline void intrl2_##which##_mask_set(struct bcm_sysport_priv *priv, \
+                                               u32 mask)               \
+{                                                                      \
+       intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET);      \
+       priv->irq##which##_mask |= (mask);                              \
+}                                                                      \
+
+BCM_SYSPORT_INTR_L2(0)
+BCM_SYSPORT_INTR_L2(1)
+
+/* Register accesses to GISB/RBUS registers are expensive (few hundred
+ * nanoseconds), so keep the check for 64-bits explicit here to save
+ * one register write per-packet on 32-bits platforms.
+ */
+static inline void dma_desc_set_addr(struct bcm_sysport_priv *priv,
+                                    void __iomem *d,
+                                    dma_addr_t addr)
+{
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       __raw_writel(upper_32_bits(addr) & DESC_ADDR_HI_MASK,
+                       d + DESC_ADDR_HI_STATUS_LEN);
+#endif
+       __raw_writel(lower_32_bits(addr), d + DESC_ADDR_LO);
+}
+
+static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv,
+                                               struct dma_desc *desc,
+                                               unsigned int port)
+{
+       /* Ports are latched, so write upper address first */
+       tdma_writel(priv, desc->addr_status_len, TDMA_WRITE_PORT_HI(port));
+       tdma_writel(priv, desc->addr_lo, TDMA_WRITE_PORT_LO(port));
+}
+
+/* Ethtool operations */
+static int bcm_sysport_set_settings(struct net_device *dev,
+                                   struct ethtool_cmd *cmd)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int bcm_sysport_get_settings(struct net_device *dev,
+                                       struct ethtool_cmd *cmd)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int bcm_sysport_set_rx_csum(struct net_device *dev,
+                                       netdev_features_t wanted)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       u32 reg;
+
+       priv->rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
+       reg = rxchk_readl(priv, RXCHK_CONTROL);
+       if (priv->rx_csum_en)
+               reg |= RXCHK_EN;
+       else
+               reg &= ~RXCHK_EN;
+
+       /* If UniMAC forwards CRC, we need to skip over it to get
+        * a valid CHK bit to be set in the per-packet status word
+        */
+       if (priv->rx_csum_en && priv->crc_fwd)
+               reg |= RXCHK_SKIP_FCS;
+       else
+               reg &= ~RXCHK_SKIP_FCS;
+
+       rxchk_writel(priv, reg, RXCHK_CONTROL);
+
+       return 0;
+}
+
+static int bcm_sysport_set_tx_csum(struct net_device *dev,
+                                       netdev_features_t wanted)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       u32 reg;
+
+       /* Hardware transmit checksum requires us to enable the Transmit status
+        * block prepended to the packet contents
+        */
+       priv->tsb_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM));
+       reg = tdma_readl(priv, TDMA_CONTROL);
+       if (priv->tsb_en)
+               reg |= TSB_EN;
+       else
+               reg &= ~TSB_EN;
+       tdma_writel(priv, reg, TDMA_CONTROL);
+
+       return 0;
+}
+
+static int bcm_sysport_set_features(struct net_device *dev,
+                                       netdev_features_t features)
+{
+       netdev_features_t changed = features ^ dev->features;
+       netdev_features_t wanted = dev->wanted_features;
+       int ret = 0;
+
+       if (changed & NETIF_F_RXCSUM)
+               ret = bcm_sysport_set_rx_csum(dev, wanted);
+       if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))
+               ret = bcm_sysport_set_tx_csum(dev, wanted);
+
+       return ret;
+}
+
+/* Hardware counters must be kept in sync because the order/offset
+ * is important here (order in structure declaration = order in hardware)
+ */
+static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
+       /* general stats */
+       STAT_NETDEV(rx_packets),
+       STAT_NETDEV(tx_packets),
+       STAT_NETDEV(rx_bytes),
+       STAT_NETDEV(tx_bytes),
+       STAT_NETDEV(rx_errors),
+       STAT_NETDEV(tx_errors),
+       STAT_NETDEV(rx_dropped),
+       STAT_NETDEV(tx_dropped),
+       STAT_NETDEV(multicast),
+       /* UniMAC RSV counters */
+       STAT_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64),
+       STAT_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127),
+       STAT_MIB_RX("rx_128_255_oct", mib.rx.pkt_cnt.cnt_255),
+       STAT_MIB_RX("rx_256_511_oct", mib.rx.pkt_cnt.cnt_511),
+       STAT_MIB_RX("rx_512_1023_oct", mib.rx.pkt_cnt.cnt_1023),
+       STAT_MIB_RX("rx_1024_1518_oct", mib.rx.pkt_cnt.cnt_1518),
+       STAT_MIB_RX("rx_vlan_1519_1522_oct", mib.rx.pkt_cnt.cnt_mgv),
+       STAT_MIB_RX("rx_1522_2047_oct", mib.rx.pkt_cnt.cnt_2047),
+       STAT_MIB_RX("rx_2048_4095_oct", mib.rx.pkt_cnt.cnt_4095),
+       STAT_MIB_RX("rx_4096_9216_oct", mib.rx.pkt_cnt.cnt_9216),
+       STAT_MIB_RX("rx_pkts", mib.rx.pkt),
+       STAT_MIB_RX("rx_bytes", mib.rx.bytes),
+       STAT_MIB_RX("rx_multicast", mib.rx.mca),
+       STAT_MIB_RX("rx_broadcast", mib.rx.bca),
+       STAT_MIB_RX("rx_fcs", mib.rx.fcs),
+       STAT_MIB_RX("rx_control", mib.rx.cf),
+       STAT_MIB_RX("rx_pause", mib.rx.pf),
+       STAT_MIB_RX("rx_unknown", mib.rx.uo),
+       STAT_MIB_RX("rx_align", mib.rx.aln),
+       STAT_MIB_RX("rx_outrange", mib.rx.flr),
+       STAT_MIB_RX("rx_code", mib.rx.cde),
+       STAT_MIB_RX("rx_carrier", mib.rx.fcr),
+       STAT_MIB_RX("rx_oversize", mib.rx.ovr),
+       STAT_MIB_RX("rx_jabber", mib.rx.jbr),
+       STAT_MIB_RX("rx_mtu_err", mib.rx.mtue),
+       STAT_MIB_RX("rx_good_pkts", mib.rx.pok),
+       STAT_MIB_RX("rx_unicast", mib.rx.uc),
+       STAT_MIB_RX("rx_ppp", mib.rx.ppp),
+       STAT_MIB_RX("rx_crc", mib.rx.rcrc),
+       /* UniMAC TSV counters */
+       STAT_MIB_TX("tx_64_octets", mib.tx.pkt_cnt.cnt_64),
+       STAT_MIB_TX("tx_65_127_oct", mib.tx.pkt_cnt.cnt_127),
+       STAT_MIB_TX("tx_128_255_oct", mib.tx.pkt_cnt.cnt_255),
+       STAT_MIB_TX("tx_256_511_oct", mib.tx.pkt_cnt.cnt_511),
+       STAT_MIB_TX("tx_512_1023_oct", mib.tx.pkt_cnt.cnt_1023),
+       STAT_MIB_TX("tx_1024_1518_oct", mib.tx.pkt_cnt.cnt_1518),
+       STAT_MIB_TX("tx_vlan_1519_1522_oct", mib.tx.pkt_cnt.cnt_mgv),
+       STAT_MIB_TX("tx_1522_2047_oct", mib.tx.pkt_cnt.cnt_2047),
+       STAT_MIB_TX("tx_2048_4095_oct", mib.tx.pkt_cnt.cnt_4095),
+       STAT_MIB_TX("tx_4096_9216_oct", mib.tx.pkt_cnt.cnt_9216),
+       STAT_MIB_TX("tx_pkts", mib.tx.pkts),
+       STAT_MIB_TX("tx_multicast", mib.tx.mca),
+       STAT_MIB_TX("tx_broadcast", mib.tx.bca),
+       STAT_MIB_TX("tx_pause", mib.tx.pf),
+       STAT_MIB_TX("tx_control", mib.tx.cf),
+       STAT_MIB_TX("tx_fcs_err", mib.tx.fcs),
+       STAT_MIB_TX("tx_oversize", mib.tx.ovr),
+       STAT_MIB_TX("tx_defer", mib.tx.drf),
+       STAT_MIB_TX("tx_excess_defer", mib.tx.edf),
+       STAT_MIB_TX("tx_single_col", mib.tx.scl),
+       STAT_MIB_TX("tx_multi_col", mib.tx.mcl),
+       STAT_MIB_TX("tx_late_col", mib.tx.lcl),
+       STAT_MIB_TX("tx_excess_col", mib.tx.ecl),
+       STAT_MIB_TX("tx_frags", mib.tx.frg),
+       STAT_MIB_TX("tx_total_col", mib.tx.ncl),
+       STAT_MIB_TX("tx_jabber", mib.tx.jbr),
+       STAT_MIB_TX("tx_bytes", mib.tx.bytes),
+       STAT_MIB_TX("tx_good_pkts", mib.tx.pok),
+       STAT_MIB_TX("tx_unicast", mib.tx.uc),
+       /* UniMAC RUNT counters */
+       STAT_RUNT("rx_runt_pkts", mib.rx_runt_cnt),
+       STAT_RUNT("rx_runt_valid_fcs", mib.rx_runt_fcs),
+       STAT_RUNT("rx_runt_inval_fcs_align", mib.rx_runt_fcs_align),
+       STAT_RUNT("rx_runt_bytes", mib.rx_runt_bytes),
+       /* RXCHK misc statistics */
+       STAT_RXCHK("rxchk_bad_csum", mib.rxchk_bad_csum, RXCHK_BAD_CSUM_CNTR),
+       STAT_RXCHK("rxchk_other_pkt_disc", mib.rxchk_other_pkt_disc,
+                       RXCHK_OTHER_DISC_CNTR),
+       /* RBUF misc statistics */
+       STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR),
+       STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR),
+};
+
+#define BCM_SYSPORT_STATS_LEN  ARRAY_SIZE(bcm_sysport_gstrings_stats)
+
+static void bcm_sysport_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, "0.1", sizeof(info->version));
+       strlcpy(info->bus_info, "platform", sizeof(info->bus_info));
+       info->n_stats = BCM_SYSPORT_STATS_LEN;
+}
+
+static u32 bcm_sysport_get_msglvl(struct net_device *dev)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+       return priv->msg_enable;
+}
+
+static void bcm_sysport_set_msglvl(struct net_device *dev, u32 enable)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+       priv->msg_enable = enable;
+}
+
+static int bcm_sysport_get_sset_count(struct net_device *dev, int string_set)
+{
+       switch (string_set) {
+       case ETH_SS_STATS:
+               return BCM_SYSPORT_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void bcm_sysport_get_strings(struct net_device *dev,
+                                       u32 stringset, u8 *data)
+{
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) {
+                       memcpy(data + i * ETH_GSTRING_LEN,
+                               bcm_sysport_gstrings_stats[i].stat_string,
+                               ETH_GSTRING_LEN);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
+{
+       int i, j = 0;
+
+       for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) {
+               const struct bcm_sysport_stats *s;
+               u8 offset = 0;
+               u32 val = 0;
+               char *p;
+
+               s = &bcm_sysport_gstrings_stats[i];
+               switch (s->type) {
+               case BCM_SYSPORT_STAT_NETDEV:
+                       continue;
+               case BCM_SYSPORT_STAT_MIB_RX:
+               case BCM_SYSPORT_STAT_MIB_TX:
+               case BCM_SYSPORT_STAT_RUNT:
+                       if (s->type != BCM_SYSPORT_STAT_MIB_RX)
+                               offset = UMAC_MIB_STAT_OFFSET;
+                       val = umac_readl(priv, UMAC_MIB_START + j + offset);
+                       break;
+               case BCM_SYSPORT_STAT_RXCHK:
+                       val = rxchk_readl(priv, s->reg_offset);
+                       if (val == ~0)
+                               rxchk_writel(priv, 0, s->reg_offset);
+                       break;
+               case BCM_SYSPORT_STAT_RBUF:
+                       val = rbuf_readl(priv, s->reg_offset);
+                       if (val == ~0)
+                               rbuf_writel(priv, 0, s->reg_offset);
+                       break;
+               }
+
+               j += s->stat_sizeof;
+               p = (char *)priv + s->stat_offset;
+               *(u32 *)p = val;
+       }
+
+       netif_dbg(priv, hw, priv->netdev, "updated MIB counters\n");
+}
+
+static void bcm_sysport_get_stats(struct net_device *dev,
+                                       struct ethtool_stats *stats, u64 *data)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       int i;
+
+       if (netif_running(dev))
+               bcm_sysport_update_mib_counters(priv);
+
+       for (i =  0; i < BCM_SYSPORT_STATS_LEN; i++) {
+               const struct bcm_sysport_stats *s;
+               char *p;
+
+               s = &bcm_sysport_gstrings_stats[i];
+               if (s->type == BCM_SYSPORT_STAT_NETDEV)
+                       p = (char *)&dev->stats;
+               else
+                       p = (char *)priv;
+               p += s->stat_offset;
+               data[i] = *(u32 *)p;
+       }
+}
+
+static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb)
+{
+       dev_kfree_skb_any(cb->skb);
+       cb->skb = NULL;
+       dma_unmap_addr_set(cb, dma_addr, 0);
+}
+
+static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv,
+                                struct bcm_sysport_cb *cb)
+{
+       struct device *kdev = &priv->pdev->dev;
+       struct net_device *ndev = priv->netdev;
+       dma_addr_t mapping;
+       int ret;
+
+       cb->skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH);
+       if (!cb->skb) {
+               netif_err(priv, rx_err, ndev, "SKB alloc failed\n");
+               return -ENOMEM;
+       }
+
+       mapping = dma_map_single(kdev, cb->skb->data,
+                               RX_BUF_LENGTH, DMA_FROM_DEVICE);
+       ret = dma_mapping_error(kdev, mapping);
+       if (ret) {
+               bcm_sysport_free_cb(cb);
+               netif_err(priv, rx_err, ndev, "DMA mapping failure\n");
+               return ret;
+       }
+
+       dma_unmap_addr_set(cb, dma_addr, mapping);
+       dma_desc_set_addr(priv, priv->rx_bd_assign_ptr, mapping);
+
+       priv->rx_bd_assign_index++;
+       priv->rx_bd_assign_index &= (priv->num_rx_bds - 1);
+       priv->rx_bd_assign_ptr = priv->rx_bds +
+               (priv->rx_bd_assign_index * DESC_SIZE);
+
+       netif_dbg(priv, rx_status, ndev, "RX refill\n");
+
+       return 0;
+}
+
+static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv)
+{
+       struct bcm_sysport_cb *cb;
+       int ret = 0;
+       unsigned int i;
+
+       for (i = 0; i < priv->num_rx_bds; i++) {
+               cb = &priv->rx_cbs[priv->rx_bd_assign_index];
+               if (cb->skb)
+                       continue;
+
+               ret = bcm_sysport_rx_refill(priv, cb);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/* Poll the hardware for up to budget packets to process */
+static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
+                                       unsigned int budget)
+{
+       struct device *kdev = &priv->pdev->dev;
+       struct net_device *ndev = priv->netdev;
+       unsigned int processed = 0, to_process;
+       struct bcm_sysport_cb *cb;
+       struct sk_buff *skb;
+       unsigned int p_index;
+       u16 len, status;
+       struct rsb *rsb;
+
+       /* Determine how much we should process since last call */
+       p_index = rdma_readl(priv, RDMA_PROD_INDEX);
+       p_index &= RDMA_PROD_INDEX_MASK;
+
+       if (p_index < priv->rx_c_index)
+               to_process = (RDMA_CONS_INDEX_MASK + 1) -
+                       priv->rx_c_index + p_index;
+       else
+               to_process = p_index - priv->rx_c_index;
+
+       netif_dbg(priv, rx_status, ndev,
+                       "p_index=%d rx_c_index=%d to_process=%d\n",
+                       p_index, priv->rx_c_index, to_process);
+
+       while ((processed < to_process) &&
+               (processed < budget)) {
+
+               cb = &priv->rx_cbs[priv->rx_read_ptr];
+               skb = cb->skb;
+               dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
+                               dma_unmap_len(cb, dma_len), DMA_FROM_DEVICE);
+
+               /* Extract the Receive Status Block prepended */
+               rsb = (struct rsb *)skb->data;
+               len = (rsb->rx_status_len >> DESC_LEN_SHIFT) & DESC_LEN_MASK;
+               status = (rsb->rx_status_len >> DESC_STATUS_SHIFT) &
+                       DESC_STATUS_MASK;
+
+               processed++;
+               priv->rx_read_ptr++;
+               if (priv->rx_read_ptr == priv->num_rx_bds)
+                       priv->rx_read_ptr = 0;
+
+               netif_dbg(priv, rx_status, ndev,
+                               "p=%d, c=%d, rd_ptr=%d, len=%d, flag=0x%04x\n",
+                               p_index, priv->rx_c_index, priv->rx_read_ptr,
+                               len, status);
+
+               if (unlikely(!skb)) {
+                       netif_err(priv, rx_err, ndev, "out of memory!\n");
+                       ndev->stats.rx_dropped++;
+                       ndev->stats.rx_errors++;
+                       goto refill;
+               }
+
+               if (unlikely(!(status & DESC_EOP) || !(status & DESC_SOP))) {
+                       netif_err(priv, rx_status, ndev, "fragmented packet!\n");
+                       ndev->stats.rx_dropped++;
+                       ndev->stats.rx_errors++;
+                       bcm_sysport_free_cb(cb);
+                       goto refill;
+               }
+
+               if (unlikely(status & (RX_STATUS_ERR | RX_STATUS_OVFLOW))) {
+                       netif_err(priv, rx_err, ndev, "error packet\n");
+                       if (RX_STATUS_OVFLOW)
+                               ndev->stats.rx_over_errors++;
+                       ndev->stats.rx_dropped++;
+                       ndev->stats.rx_errors++;
+                       bcm_sysport_free_cb(cb);
+                       goto refill;
+               }
+
+               skb_put(skb, len);
+
+               /* Hardware validated our checksum */
+               if (likely(status & DESC_L4_CSUM))
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+               /* Hardware pre-pends packets with 2bytes between Ethernet
+                * and IP header plus we have the Receive Status Block, strip
+                * off all of this from the SKB.
+                */
+               skb_pull(skb, sizeof(*rsb) + 2);
+               len -= (sizeof(*rsb) + 2);
+
+               /* UniMAC may forward CRC */
+               if (priv->crc_fwd) {
+                       skb_trim(skb, len - ETH_FCS_LEN);
+                       len -= ETH_FCS_LEN;
+               }
+
+               skb->protocol = eth_type_trans(skb, ndev);
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += len;
+
+               napi_gro_receive(&priv->napi, skb);
+refill:
+               bcm_sysport_rx_refill(priv, cb);
+       }
+
+       return processed;
+}
+
+static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv,
+                                       struct bcm_sysport_cb *cb,
+                                       unsigned int *bytes_compl,
+                                       unsigned int *pkts_compl)
+{
+       struct device *kdev = &priv->pdev->dev;
+       struct net_device *ndev = priv->netdev;
+
+       if (cb->skb) {
+               ndev->stats.tx_bytes += cb->skb->len;
+               *bytes_compl += cb->skb->len;
+               dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
+                               dma_unmap_len(cb, dma_len),
+                               DMA_TO_DEVICE);
+               ndev->stats.tx_packets++;
+               (*pkts_compl)++;
+               bcm_sysport_free_cb(cb);
+       /* SKB fragment */
+       } else if (dma_unmap_addr(cb, dma_addr)) {
+               ndev->stats.tx_bytes += dma_unmap_len(cb, dma_len);
+               dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr),
+                               dma_unmap_len(cb, dma_len), DMA_TO_DEVICE);
+               dma_unmap_addr_set(cb, dma_addr, 0);
+       }
+}
+
+/* Reclaim queued SKBs for transmission completion, lockless version */
+static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
+                                            struct bcm_sysport_tx_ring *ring)
+{
+       struct net_device *ndev = priv->netdev;
+       unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs;
+       unsigned int pkts_compl = 0, bytes_compl = 0;
+       struct bcm_sysport_cb *cb;
+       struct netdev_queue *txq;
+       u32 hw_ind;
+
+       txq = netdev_get_tx_queue(ndev, ring->index);
+
+       /* Compute how many descriptors have been processed since last call */
+       hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index));
+       c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK;
+       ring->p_index = (hw_ind & RING_PROD_INDEX_MASK);
+
+       last_c_index = ring->c_index;
+       num_tx_cbs = ring->size;
+
+       c_index &= (num_tx_cbs - 1);
+
+       if (c_index >= last_c_index)
+               last_tx_cn = c_index - last_c_index;
+       else
+               last_tx_cn = num_tx_cbs - last_c_index + c_index;
+
+       netif_dbg(priv, tx_done, ndev,
+                       "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n",
+                       ring->index, c_index, last_tx_cn, last_c_index);
+
+       while (last_tx_cn-- > 0) {
+               cb = ring->cbs + last_c_index;
+               bcm_sysport_tx_reclaim_one(priv, cb, &bytes_compl, &pkts_compl);
+
+               ring->desc_count++;
+               last_c_index++;
+               last_c_index &= (num_tx_cbs - 1);
+       }
+
+       ring->c_index = c_index;
+
+       if (netif_tx_queue_stopped(txq) && pkts_compl)
+               netif_tx_wake_queue(txq);
+
+       netif_dbg(priv, tx_done, ndev,
+                       "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n",
+                       ring->index, ring->c_index, pkts_compl, bytes_compl);
+
+       return pkts_compl;
+}
+
+/* Locked version of the per-ring TX reclaim routine */
+static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
+                                          struct bcm_sysport_tx_ring *ring)
+{
+       unsigned int released;
+
+       spin_lock(&ring->lock);
+       released = __bcm_sysport_tx_reclaim(priv, ring);
+       spin_unlock(&ring->lock);
+
+       return released;
+}
+
+static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
+{
+       struct bcm_sysport_tx_ring *ring =
+               container_of(napi, struct bcm_sysport_tx_ring, napi);
+       unsigned int work_done = 0;
+
+       work_done = bcm_sysport_tx_reclaim(ring->priv, ring);
+
+       if (work_done < budget) {
+               napi_complete(napi);
+               /* re-enable TX interrupt */
+               intrl2_1_mask_clear(ring->priv, BIT(ring->index));
+       }
+
+       return work_done;
+}
+
+static void bcm_sysport_tx_reclaim_all(struct bcm_sysport_priv *priv)
+{
+       unsigned int q;
+
+       for (q = 0; q < priv->netdev->num_tx_queues; q++)
+               bcm_sysport_tx_reclaim(priv, &priv->tx_rings[q]);
+}
+
+static int bcm_sysport_poll(struct napi_struct *napi, int budget)
+{
+       struct bcm_sysport_priv *priv =
+               container_of(napi, struct bcm_sysport_priv, napi);
+       unsigned int work_done = 0;
+
+       work_done = bcm_sysport_desc_rx(priv, budget);
+
+       priv->rx_c_index += work_done;
+       priv->rx_c_index &= RDMA_CONS_INDEX_MASK;
+       rdma_writel(priv, priv->rx_c_index, RDMA_CONS_INDEX);
+
+       if (work_done < budget) {
+               napi_complete(napi);
+               /* re-enable RX interrupts */
+               intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE);
+       }
+
+       return work_done;
+}
+
+
+/* RX and misc interrupt routine */
+static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+       priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
+                         ~intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
+       intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+       if (unlikely(priv->irq0_stat == 0)) {
+               netdev_warn(priv->netdev, "spurious RX interrupt\n");
+               return IRQ_NONE;
+       }
+
+       if (priv->irq0_stat & INTRL2_0_RDMA_MBDONE) {
+               if (likely(napi_schedule_prep(&priv->napi))) {
+                       /* disable RX interrupts */
+                       intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE);
+                       __napi_schedule(&priv->napi);
+               }
+       }
+
+       /* TX ring is full, perform a full reclaim since we do not know
+        * which one would trigger this interrupt
+        */
+       if (priv->irq0_stat & INTRL2_0_TX_RING_FULL)
+               bcm_sysport_tx_reclaim_all(priv);
+
+       return IRQ_HANDLED;
+}
+
+/* TX interrupt service routine */
+static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       struct bcm_sysport_tx_ring *txr;
+       unsigned int ring;
+
+       priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
+                               ~intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+
+       if (unlikely(priv->irq1_stat == 0)) {
+               netdev_warn(priv->netdev, "spurious TX interrupt\n");
+               return IRQ_NONE;
+       }
+
+       for (ring = 0; ring < dev->num_tx_queues; ring++) {
+               if (!(priv->irq1_stat & BIT(ring)))
+                       continue;
+
+               txr = &priv->tx_rings[ring];
+
+               if (likely(napi_schedule_prep(&txr->napi))) {
+                       intrl2_1_mask_set(priv, BIT(ring));
+                       __napi_schedule(&txr->napi);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff *nskb;
+       struct tsb *tsb;
+       u32 csum_info;
+       u8 ip_proto;
+       u16 csum_start;
+       u16 ip_ver;
+
+       /* Re-allocate SKB if needed */
+       if (unlikely(skb_headroom(skb) < sizeof(*tsb))) {
+               nskb = skb_realloc_headroom(skb, sizeof(*tsb));
+               dev_kfree_skb(skb);
+               if (!nskb) {
+                       dev->stats.tx_errors++;
+                       dev->stats.tx_dropped++;
+                       return -ENOMEM;
+               }
+               skb = nskb;
+       }
+
+       tsb = (struct tsb *)skb_push(skb, sizeof(*tsb));
+       /* Zero-out TSB by default */
+       memset(tsb, 0, sizeof(*tsb));
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               ip_ver = htons(skb->protocol);
+               switch (ip_ver) {
+               case ETH_P_IP:
+                       ip_proto = ip_hdr(skb)->protocol;
+                       break;
+               case ETH_P_IPV6:
+                       ip_proto = ipv6_hdr(skb)->nexthdr;
+                       break;
+               default:
+                       return 0;
+               }
+
+               /* Get the checksum offset and the L4 (transport) offset */
+               csum_start = skb_checksum_start_offset(skb) - sizeof(*tsb);
+               csum_info = (csum_start + skb->csum_offset) & L4_CSUM_PTR_MASK;
+               csum_info |= (csum_start << L4_PTR_SHIFT);
+
+               if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) {
+                       csum_info |= L4_LENGTH_VALID;
+                       if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
+                               csum_info |= L4_UDP;
+               } else
+                       csum_info = 0;
+
+               tsb->l4_ptr_dest_map = csum_info;
+       }
+
+       return 0;
+}
+
+static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       struct device *kdev = &priv->pdev->dev;
+       struct bcm_sysport_tx_ring *ring;
+       struct bcm_sysport_cb *cb;
+       struct netdev_queue *txq;
+       struct dma_desc *desc;
+       dma_addr_t mapping;
+       u32 len_status;
+       u16 queue;
+       int ret;
+
+       queue = skb_get_queue_mapping(skb);
+       txq = netdev_get_tx_queue(dev, queue);
+       ring = &priv->tx_rings[queue];
+
+       /* lock against tx reclaim in BH context */
+       spin_lock(&ring->lock);
+       if (unlikely(ring->desc_count == 0)) {
+               netif_tx_stop_queue(txq);
+               netdev_err(dev, "queue %d awake and ring full!\n", queue);
+               ret = NETDEV_TX_BUSY;
+               goto out;
+       }
+
+       /* Insert TSB and checksum infos */
+       if (priv->tsb_en) {
+               ret = bcm_sysport_insert_tsb(skb, dev);
+               if (ret) {
+                       ret = NETDEV_TX_OK;
+                       goto out;
+               }
+       }
+
+       mapping = dma_map_single(kdev, skb->data, skb->len, DMA_TO_DEVICE);
+       if (dma_mapping_error(kdev, mapping)) {
+               netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n",
+                               skb->data, skb->len);
+               ret = NETDEV_TX_OK;
+               goto out;
+       }
+
+       /* Remember the SKB for future freeing */
+       cb = &ring->cbs[ring->curr_desc];
+       cb->skb = skb;
+       dma_unmap_addr_set(cb, dma_addr, mapping);
+       dma_unmap_len_set(cb, dma_len, skb->len);
+
+       /* Fetch a descriptor entry from our pool */
+       desc = ring->desc_cpu;
+
+       desc->addr_lo = lower_32_bits(mapping);
+       len_status = upper_32_bits(mapping) & DESC_ADDR_HI_MASK;
+       len_status |= (skb->len << DESC_LEN_SHIFT);
+       len_status |= (DESC_SOP | DESC_EOP | TX_STATUS_APP_CRC) <<
+                       DESC_STATUS_SHIFT;
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               len_status |= (DESC_L4_CSUM << DESC_STATUS_SHIFT);
+
+       ring->curr_desc++;
+       if (ring->curr_desc == ring->size)
+               ring->curr_desc = 0;
+       ring->desc_count--;
+
+       /* Ensure write completion of the descriptor status/length
+        * in DRAM before the System Port WRITE_PORT register latches
+        * the value
+        */
+       wmb();
+       desc->addr_status_len = len_status;
+       wmb();
+
+       /* Write this descriptor address to the RING write port */
+       tdma_port_write_desc_addr(priv, desc, ring->index);
+
+       /* Check ring space and update SW control flow */
+       if (ring->desc_count == 0)
+               netif_tx_stop_queue(txq);
+
+       netif_dbg(priv, tx_queued, dev, "ring=%d desc_count=%d, curr_desc=%d\n",
+                       ring->index, ring->desc_count, ring->curr_desc);
+
+       ret = NETDEV_TX_OK;
+out:
+       spin_unlock(&ring->lock);
+       return ret;
+}
+
+static void bcm_sysport_tx_timeout(struct net_device *dev)
+{
+       netdev_warn(dev, "transmit timeout!\n");
+
+       dev->trans_start = jiffies;
+       dev->stats.tx_errors++;
+
+       netif_tx_wake_all_queues(dev);
+}
+
+/* phylib adjust link callback */
+static void bcm_sysport_adj_link(struct net_device *dev)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       unsigned int changed = 0;
+       u32 cmd_bits = 0, reg;
+
+       if (priv->old_link != phydev->link) {
+               changed = 1;
+               priv->old_link = phydev->link;
+       }
+
+       if (priv->old_duplex != phydev->duplex) {
+               changed = 1;
+               priv->old_duplex = phydev->duplex;
+       }
+
+       switch (phydev->speed) {
+       case SPEED_2500:
+               cmd_bits = CMD_SPEED_2500;
+               break;
+       case SPEED_1000:
+               cmd_bits = CMD_SPEED_1000;
+               break;
+       case SPEED_100:
+               cmd_bits = CMD_SPEED_100;
+               break;
+       case SPEED_10:
+               cmd_bits = CMD_SPEED_10;
+               break;
+       default:
+               break;
+       }
+       cmd_bits <<= CMD_SPEED_SHIFT;
+
+       if (phydev->duplex == DUPLEX_HALF)
+               cmd_bits |= CMD_HD_EN;
+
+       if (priv->old_pause != phydev->pause) {
+               changed = 1;
+               priv->old_pause = phydev->pause;
+       }
+
+       if (!phydev->pause)
+               cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
+
+       reg = umac_readl(priv, UMAC_CMD);
+       reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
+                       CMD_HD_EN | CMD_RX_PAUSE_IGNORE |
+                       CMD_TX_PAUSE_IGNORE);
+       reg |= cmd_bits;
+       umac_writel(priv, reg, UMAC_CMD);
+
+       if (changed)
+               phy_print_status(priv->phydev);
+}
+
+static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
+                                   unsigned int index)
+{
+       struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index];
+       struct device *kdev = &priv->pdev->dev;
+       size_t size;
+       void *p;
+       u32 reg;
+
+       /* Simple descriptors partitioning for now */
+       size = 256;
+
+       /* We just need one DMA descriptor which is DMA-able, since writing to
+        * the port will allocate a new descriptor in its internal linked-list
+        */
+       p = dma_zalloc_coherent(kdev, 1, &ring->desc_dma, GFP_KERNEL);
+       if (!p) {
+               netif_err(priv, hw, priv->netdev, "DMA alloc failed\n");
+               return -ENOMEM;
+       }
+
+       ring->cbs = kzalloc(sizeof(struct bcm_sysport_cb) * size, GFP_KERNEL);
+       if (!ring->cbs) {
+               netif_err(priv, hw, priv->netdev, "CB allocation failed\n");
+               return -ENOMEM;
+       }
+
+       /* Initialize SW view of the ring */
+       spin_lock_init(&ring->lock);
+       ring->priv = priv;
+       netif_napi_add(priv->netdev, &ring->napi, bcm_sysport_tx_poll, 64);
+       ring->index = index;
+       ring->size = size;
+       ring->alloc_size = ring->size;
+       ring->desc_cpu = p;
+       ring->desc_count = ring->size;
+       ring->curr_desc = 0;
+
+       /* Initialize HW ring */
+       tdma_writel(priv, RING_EN, TDMA_DESC_RING_HEAD_TAIL_PTR(index));
+       tdma_writel(priv, 0, TDMA_DESC_RING_COUNT(index));
+       tdma_writel(priv, 1, TDMA_DESC_RING_INTR_CONTROL(index));
+       tdma_writel(priv, 0, TDMA_DESC_RING_PROD_CONS_INDEX(index));
+       tdma_writel(priv, RING_IGNORE_STATUS, TDMA_DESC_RING_MAPPING(index));
+       tdma_writel(priv, 0, TDMA_DESC_RING_PCP_DEI_VID(index));
+
+       /* Program the number of descriptors as MAX_THRESHOLD and half of
+        * its size for the hysteresis trigger
+        */
+       tdma_writel(priv, ring->size |
+                       1 << RING_HYST_THRESH_SHIFT,
+                       TDMA_DESC_RING_MAX_HYST(index));
+
+       /* Enable the ring queue in the arbiter */
+       reg = tdma_readl(priv, TDMA_TIER1_ARB_0_QUEUE_EN);
+       reg |= (1 << index);
+       tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN);
+
+       napi_enable(&ring->napi);
+
+       netif_dbg(priv, hw, priv->netdev,
+                       "TDMA cfg, size=%d, desc_cpu=%p\n",
+                       ring->size, ring->desc_cpu);
+
+       return 0;
+}
+
+static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
+                                       unsigned int index)
+{
+       struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index];
+       struct device *kdev = &priv->pdev->dev;
+       u32 reg;
+
+       /* Caller should stop the TDMA engine */
+       reg = tdma_readl(priv, TDMA_STATUS);
+       if (!(reg & TDMA_DISABLED))
+               netdev_warn(priv->netdev, "TDMA not stopped!\n");
+
+       napi_disable(&ring->napi);
+       netif_napi_del(&ring->napi);
+
+       bcm_sysport_tx_reclaim(priv, ring);
+
+       kfree(ring->cbs);
+       ring->cbs = NULL;
+
+       if (ring->desc_dma) {
+               dma_free_coherent(kdev, 1, ring->desc_cpu, ring->desc_dma);
+               ring->desc_dma = 0;
+       }
+       ring->size = 0;
+       ring->alloc_size = 0;
+
+       netif_dbg(priv, hw, priv->netdev, "TDMA fini done\n");
+}
+
+/* RDMA helper */
+static inline int rdma_enable_set(struct bcm_sysport_priv *priv,
+                                       unsigned int enable)
+{
+       unsigned int timeout = 1000;
+       u32 reg;
+
+       reg = rdma_readl(priv, RDMA_CONTROL);
+       if (enable)
+               reg |= RDMA_EN;
+       else
+               reg &= ~RDMA_EN;
+       rdma_writel(priv, reg, RDMA_CONTROL);
+
+       /* Poll for RMDA disabling completion */
+       do {
+               reg = rdma_readl(priv, RDMA_STATUS);
+               if (!!(reg & RDMA_DISABLED) == !enable)
+                       return 0;
+               usleep_range(1000, 2000);
+       } while (timeout-- > 0);
+
+       netdev_err(priv->netdev, "timeout waiting for RDMA to finish\n");
+
+       return -ETIMEDOUT;
+}
+
+/* TDMA helper */
+static inline int tdma_enable_set(struct bcm_sysport_priv *priv,
+                                       unsigned int enable)
+{
+       unsigned int timeout = 1000;
+       u32 reg;
+
+       reg = tdma_readl(priv, TDMA_CONTROL);
+       if (enable)
+               reg |= TDMA_EN;
+       else
+               reg &= ~TDMA_EN;
+       tdma_writel(priv, reg, TDMA_CONTROL);
+
+       /* Poll for TMDA disabling completion */
+       do {
+               reg = tdma_readl(priv, TDMA_STATUS);
+               if (!!(reg & TDMA_DISABLED) == !enable)
+                       return 0;
+
+               usleep_range(1000, 2000);
+       } while (timeout-- > 0);
+
+       netdev_err(priv->netdev, "timeout waiting for TDMA to finish\n");
+
+       return -ETIMEDOUT;
+}
+
+static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
+{
+       u32 reg;
+       int ret;
+
+       /* Initialize SW view of the RX ring */
+       priv->num_rx_bds = NUM_RX_DESC;
+       priv->rx_bds = priv->base + SYS_PORT_RDMA_OFFSET;
+       priv->rx_bd_assign_ptr = priv->rx_bds;
+       priv->rx_bd_assign_index = 0;
+       priv->rx_c_index = 0;
+       priv->rx_read_ptr = 0;
+       priv->rx_cbs = kzalloc(priv->num_rx_bds *
+                               sizeof(struct bcm_sysport_cb), GFP_KERNEL);
+       if (!priv->rx_cbs) {
+               netif_err(priv, hw, priv->netdev, "CB allocation failed\n");
+               return -ENOMEM;
+       }
+
+       ret = bcm_sysport_alloc_rx_bufs(priv);
+       if (ret) {
+               netif_err(priv, hw, priv->netdev, "SKB allocation failed\n");
+               return ret;
+       }
+
+       /* Initialize HW, ensure RDMA is disabled */
+       reg = rdma_readl(priv, RDMA_STATUS);
+       if (!(reg & RDMA_DISABLED))
+               rdma_enable_set(priv, 0);
+
+       rdma_writel(priv, 0, RDMA_WRITE_PTR_LO);
+       rdma_writel(priv, 0, RDMA_WRITE_PTR_HI);
+       rdma_writel(priv, 0, RDMA_PROD_INDEX);
+       rdma_writel(priv, 0, RDMA_CONS_INDEX);
+       rdma_writel(priv, priv->num_rx_bds << RDMA_RING_SIZE_SHIFT |
+                         RX_BUF_LENGTH, RDMA_RING_BUF_SIZE);
+       /* Operate the queue in ring mode */
+       rdma_writel(priv, 0, RDMA_START_ADDR_HI);
+       rdma_writel(priv, 0, RDMA_START_ADDR_LO);
+       rdma_writel(priv, 0, RDMA_END_ADDR_HI);
+       rdma_writel(priv, NUM_HW_RX_DESC_WORDS - 1, RDMA_END_ADDR_LO);
+
+       rdma_writel(priv, 1, RDMA_MBDONE_INTR);
+
+       netif_dbg(priv, hw, priv->netdev,
+                       "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n",
+                       priv->num_rx_bds, priv->rx_bds);
+
+       return 0;
+}
+
+static void bcm_sysport_fini_rx_ring(struct bcm_sysport_priv *priv)
+{
+       struct bcm_sysport_cb *cb;
+       unsigned int i;
+       u32 reg;
+
+       /* Caller should ensure RDMA is disabled */
+       reg = rdma_readl(priv, RDMA_STATUS);
+       if (!(reg & RDMA_DISABLED))
+               netdev_warn(priv->netdev, "RDMA not stopped!\n");
+
+       for (i = 0; i < priv->num_rx_bds; i++) {
+               cb = &priv->rx_cbs[i];
+               if (dma_unmap_addr(cb, dma_addr))
+                       dma_unmap_single(&priv->pdev->dev,
+                                       dma_unmap_addr(cb, dma_addr),
+                                       RX_BUF_LENGTH, DMA_FROM_DEVICE);
+               bcm_sysport_free_cb(cb);
+       }
+
+       kfree(priv->rx_cbs);
+       priv->rx_cbs = NULL;
+
+       netif_dbg(priv, hw, priv->netdev, "RDMA fini done\n");
+}
+
+static void bcm_sysport_set_rx_mode(struct net_device *dev)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       u32 reg;
+
+       reg = umac_readl(priv, UMAC_CMD);
+       if (dev->flags & IFF_PROMISC)
+               reg |= CMD_PROMISC;
+       else
+               reg &= ~CMD_PROMISC;
+       umac_writel(priv, reg, UMAC_CMD);
+
+       /* No support for ALLMULTI */
+       if (dev->flags & IFF_ALLMULTI)
+               return;
+}
+
+static inline void umac_enable_set(struct bcm_sysport_priv *priv,
+                                       unsigned int enable)
+{
+       u32 reg;
+
+       reg = umac_readl(priv, UMAC_CMD);
+       if (enable)
+               reg |= CMD_RX_EN | CMD_TX_EN;
+       else
+               reg &= ~(CMD_RX_EN | CMD_TX_EN);
+       umac_writel(priv, reg, UMAC_CMD);
+}
+
+static inline int umac_reset(struct bcm_sysport_priv *priv)
+{
+       unsigned int timeout = 0;
+       u32 reg;
+       int ret = 0;
+
+       umac_writel(priv, 0, UMAC_CMD);
+       while (timeout++ < 1000) {
+               reg = umac_readl(priv, UMAC_CMD);
+               if (!(reg & CMD_SW_RESET))
+                       break;
+
+               udelay(1);
+       }
+
+       if (timeout == 1000) {
+               dev_err(&priv->pdev->dev,
+                       "timeout waiting for MAC to come out of reset\n");
+               ret = -ETIMEDOUT;
+       }
+
+       return ret;
+}
+
+static void umac_set_hw_addr(struct bcm_sysport_priv *priv,
+                               unsigned char *addr)
+{
+       umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) |
+                       (addr[2] << 8) | addr[3], UMAC_MAC0);
+       umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1);
+}
+
+static void topctrl_flush(struct bcm_sysport_priv *priv)
+{
+       topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL);
+       topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL);
+       mdelay(1);
+       topctrl_writel(priv, 0, RX_FLUSH_CNTL);
+       topctrl_writel(priv, 0, TX_FLUSH_CNTL);
+}
+
+static int bcm_sysport_open(struct net_device *dev)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       unsigned int i;
+       u32 reg;
+       int ret;
+
+       /* Reset UniMAC */
+       ret = umac_reset(priv);
+       if (ret) {
+               netdev_err(dev, "UniMAC reset failed\n");
+               return ret;
+       }
+
+       /* Flush TX and RX FIFOs at TOPCTRL level */
+       topctrl_flush(priv);
+
+       /* Disable the UniMAC RX/TX */
+       umac_enable_set(priv, 0);
+
+       /* Enable RBUF 2bytes alignment and Receive Status Block */
+       reg = rbuf_readl(priv, RBUF_CONTROL);
+       reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
+       rbuf_writel(priv, reg, RBUF_CONTROL);
+
+       /* Set maximum frame length */
+       umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
+
+       /* Set MAC address */
+       umac_set_hw_addr(priv, dev->dev_addr);
+
+       /* Read CRC forward */
+       priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD);
+
+       priv->phydev = of_phy_connect_fixed_link(dev, bcm_sysport_adj_link,
+                                                       priv->phy_interface);
+       if (!priv->phydev) {
+               netdev_err(dev, "could not attach to PHY\n");
+               return -ENODEV;
+       }
+
+       /* Reset house keeping link status */
+       priv->old_duplex = -1;
+       priv->old_link = -1;
+       priv->old_pause = -1;
+
+       /* mask all interrupts and request them */
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+       ret = request_irq(priv->irq0, bcm_sysport_rx_isr, 0, dev->name, dev);
+       if (ret) {
+               netdev_err(dev, "failed to request RX interrupt\n");
+               goto out_phy_disconnect;
+       }
+
+       ret = request_irq(priv->irq1, bcm_sysport_tx_isr, 0, dev->name, dev);
+       if (ret) {
+               netdev_err(dev, "failed to request TX interrupt\n");
+               goto out_free_irq0;
+       }
+
+       /* Initialize both hardware and software ring */
+       for (i = 0; i < dev->num_tx_queues; i++) {
+               ret = bcm_sysport_init_tx_ring(priv, i);
+               if (ret) {
+                       netdev_err(dev, "failed to initialize TX ring %d\n",
+                                       i);
+                       goto out_free_tx_ring;
+               }
+       }
+
+       /* Initialize linked-list */
+       tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS);
+
+       /* Initialize RX ring */
+       ret = bcm_sysport_init_rx_ring(priv);
+       if (ret) {
+               netdev_err(dev, "failed to initialize RX ring\n");
+               goto out_free_rx_ring;
+       }
+
+       /* Turn on RDMA */
+       ret = rdma_enable_set(priv, 1);
+       if (ret)
+               goto out_free_rx_ring;
+
+       /* Enable RX interrupt and TX ring full interrupt */
+       intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
+
+       /* Turn on TDMA */
+       ret = tdma_enable_set(priv, 1);
+       if (ret)
+               goto out_clear_rx_int;
+
+       /* Enable NAPI */
+       napi_enable(&priv->napi);
+
+       /* Turn on UniMAC TX/RX */
+       umac_enable_set(priv, 1);
+
+       phy_start(priv->phydev);
+
+       /* Enable TX interrupts for the 32 TXQs */
+       intrl2_1_mask_clear(priv, 0xffffffff);
+
+       /* Last call before we start the real business */
+       netif_tx_start_all_queues(dev);
+
+       return 0;
+
+out_clear_rx_int:
+       intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
+out_free_rx_ring:
+       bcm_sysport_fini_rx_ring(priv);
+out_free_tx_ring:
+       for (i = 0; i < dev->num_tx_queues; i++)
+               bcm_sysport_fini_tx_ring(priv, i);
+       free_irq(priv->irq1, dev);
+out_free_irq0:
+       free_irq(priv->irq0, dev);
+out_phy_disconnect:
+       phy_disconnect(priv->phydev);
+       return ret;
+}
+
+static int bcm_sysport_stop(struct net_device *dev)
+{
+       struct bcm_sysport_priv *priv = netdev_priv(dev);
+       unsigned int i;
+       u32 reg;
+       int ret;
+
+       /* stop all software from updating hardware */
+       netif_tx_stop_all_queues(dev);
+       napi_disable(&priv->napi);
+       phy_stop(priv->phydev);
+
+       /* mask all interrupts */
+       intrl2_0_mask_set(priv, 0xffffffff);
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_1_mask_set(priv, 0xffffffff);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+
+       /* Disable UniMAC RX */
+       reg = umac_readl(priv, UMAC_CMD);
+       reg &= ~CMD_RX_EN;
+       umac_writel(priv, reg, UMAC_CMD);
+
+       ret = tdma_enable_set(priv, 0);
+       if (ret) {
+               netdev_err(dev, "timeout disabling RDMA\n");
+               return ret;
+       }
+
+       /* Wait for a maximum packet size to be drained */
+       usleep_range(2000, 3000);
+
+       ret = rdma_enable_set(priv, 0);
+       if (ret) {
+               netdev_err(dev, "timeout disabling TDMA\n");
+               return ret;
+       }
+
+       /* Disable UniMAC TX */
+       reg = umac_readl(priv, UMAC_CMD);
+       reg &= ~CMD_TX_EN;
+       umac_writel(priv, reg, UMAC_CMD);
+
+       /* Free RX/TX rings SW structures */
+       for (i = 0; i < dev->num_tx_queues; i++)
+               bcm_sysport_fini_tx_ring(priv, i);
+       bcm_sysport_fini_rx_ring(priv);
+
+       free_irq(priv->irq0, dev);
+       free_irq(priv->irq1, dev);
+
+       /* Disconnect from PHY */
+       phy_disconnect(priv->phydev);
+
+       return 0;
+}
+
+static struct ethtool_ops bcm_sysport_ethtool_ops = {
+       .get_settings           = bcm_sysport_get_settings,
+       .set_settings           = bcm_sysport_set_settings,
+       .get_drvinfo            = bcm_sysport_get_drvinfo,
+       .get_msglevel           = bcm_sysport_get_msglvl,
+       .set_msglevel           = bcm_sysport_set_msglvl,
+       .get_link               = ethtool_op_get_link,
+       .get_strings            = bcm_sysport_get_strings,
+       .get_ethtool_stats      = bcm_sysport_get_stats,
+       .get_sset_count         = bcm_sysport_get_sset_count,
+};
+
+static const struct net_device_ops bcm_sysport_netdev_ops = {
+       .ndo_start_xmit         = bcm_sysport_xmit,
+       .ndo_tx_timeout         = bcm_sysport_tx_timeout,
+       .ndo_open               = bcm_sysport_open,
+       .ndo_stop               = bcm_sysport_stop,
+       .ndo_set_features       = bcm_sysport_set_features,
+       .ndo_set_rx_mode        = bcm_sysport_set_rx_mode,
+};
+
+#define REV_FMT        "v%2x.%02x"
+
+static int bcm_sysport_probe(struct platform_device *pdev)
+{
+       struct bcm_sysport_priv *priv;
+       struct device_node *dn;
+       struct net_device *dev;
+       const void *macaddr;
+       struct resource *r;
+       u32 txq, rxq;
+       int ret;
+
+       dn = pdev->dev.of_node;
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       /* Read the Transmit/Receive Queue properties */
+       if (of_property_read_u32(dn, "systemport,num-txq", &txq))
+               txq = TDMA_NUM_RINGS;
+       if (of_property_read_u32(dn, "systemport,num-rxq", &rxq))
+               rxq = 1;
+
+       dev = alloc_etherdev_mqs(sizeof(*priv), txq, rxq);
+       if (!dev)
+               return -ENOMEM;
+
+       /* Initialize private members */
+       priv = netdev_priv(dev);
+
+       priv->irq0 = platform_get_irq(pdev, 0);
+       priv->irq1 = platform_get_irq(pdev, 1);
+       if (priv->irq0 <= 0 || priv->irq1 <= 0) {
+               dev_err(&pdev->dev, "invalid interrupts\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       priv->base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!priv->base) {
+               dev_err(&pdev->dev, "register remap failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       priv->netdev = dev;
+       priv->pdev = pdev;
+
+       priv->phy_interface = of_get_phy_mode(dn);
+       /* Default to GMII interface mode */
+       if (priv->phy_interface < 0)
+               priv->phy_interface = PHY_INTERFACE_MODE_GMII;
+
+       /* Initialize netdevice members */
+       macaddr = of_get_mac_address(dn);
+       if (!macaddr || !is_valid_ether_addr(macaddr)) {
+               dev_warn(&pdev->dev, "using random Ethernet MAC\n");
+               random_ether_addr(dev->dev_addr);
+       } else {
+               ether_addr_copy(dev->dev_addr, macaddr);
+       }
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       dev_set_drvdata(&pdev->dev, dev);
+       SET_ETHTOOL_OPS(dev, &bcm_sysport_ethtool_ops);
+       dev->netdev_ops = &bcm_sysport_netdev_ops;
+       netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64);
+
+       /* HW supported features, none enabled by default */
+       dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA |
+                               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+
+       /* Set the needed headroom once and for all */
+       BUILD_BUG_ON(sizeof(struct tsb) != 8);
+       dev->needed_headroom += sizeof(struct tsb);
+
+       /* We are interfaced to a switch which handles the multicast
+        * filtering for us, so we do not support programming any
+        * multicast hash table in this Ethernet MAC.
+        */
+       dev->flags &= ~IFF_MULTICAST;
+
+       ret = register_netdev(dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register net_device\n");
+               goto err;
+       }
+
+       priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK;
+       dev_info(&pdev->dev,
+               "Broadcom SYSTEMPORT" REV_FMT
+               " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n",
+               (priv->rev >> 8) & 0xff, priv->rev & 0xff,
+               priv->base, priv->irq0, priv->irq1, txq, rxq);
+
+       return 0;
+err:
+       free_netdev(dev);
+       return ret;
+}
+
+static int bcm_sysport_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = dev_get_drvdata(&pdev->dev);
+
+       /* Not much to do, ndo_close has been called
+        * and we use managed allocations
+        */
+       unregister_netdev(dev);
+       free_netdev(dev);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id bcm_sysport_of_match[] = {
+       { .compatible = "brcm,systemport-v1.00" },
+       { .compatible = "brcm,systemport" },
+       { /* sentinel */ }
+};
+
+static struct platform_driver bcm_sysport_driver = {
+       .probe  = bcm_sysport_probe,
+       .remove = bcm_sysport_remove,
+       .driver =  {
+               .name = "brcm-systemport",
+               .owner = THIS_MODULE,
+               .of_match_table = bcm_sysport_of_match,
+       },
+};
+module_platform_driver(bcm_sysport_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom System Port Ethernet MAC driver");
+MODULE_ALIAS("platform:brcm-systemport");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
new file mode 100644 (file)
index 0000000..a0441e7
--- /dev/null
@@ -0,0 +1,677 @@
+/*
+ * Broadcom BCM7xxx System Port Ethernet MAC driver
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __BCM_SYSPORT_H
+#define __BCM_SYSPORT_H
+
+#include <linux/if_vlan.h>
+
+/* Receive/transmit descriptor format */
+#define DESC_ADDR_HI_STATUS_LEN        0x00
+#define  DESC_ADDR_HI_SHIFT    0
+#define  DESC_ADDR_HI_MASK     0xff
+#define  DESC_STATUS_SHIFT     8
+#define  DESC_STATUS_MASK      0x3ff
+#define  DESC_LEN_SHIFT                18
+#define  DESC_LEN_MASK         0x7fff
+#define DESC_ADDR_LO           0x04
+
+/* HW supports 40-bit addressing hence the */
+#define DESC_SIZE              (WORDS_PER_DESC * sizeof(u32))
+
+/* Default RX buffer allocation size */
+#define RX_BUF_LENGTH          2048
+
+/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528.
+ * 1536 is multiple of 256 bytes
+ */
+#define ENET_BRCM_TAG_LEN      6
+#define ENET_PAD               8
+#define UMAC_MAX_MTU_SIZE      (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
+                                ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
+
+/* Transmit status block */
+struct tsb {
+       u32 pcp_dei_vid;
+#define PCP_DEI_MASK           0xf
+#define VID_SHIFT              4
+#define VID_MASK               0xfff
+       u32 l4_ptr_dest_map;
+#define L4_CSUM_PTR_MASK       0x1ff
+#define L4_PTR_SHIFT           9
+#define L4_PTR_MASK            0x1ff
+#define L4_UDP                 (1 << 18)
+#define L4_LENGTH_VALID                (1 << 19)
+#define DEST_MAP_SHIFT         20
+#define DEST_MAP_MASK          0x1ff
+};
+
+/* Receive status block uses the same
+ * definitions as the DMA descriptor
+ */
+struct rsb {
+       u32 rx_status_len;
+       u32 brcm_egress_tag;
+};
+
+/* Common Receive/Transmit status bits */
+#define DESC_L4_CSUM           (1 << 7)
+#define DESC_SOP               (1 << 8)
+#define DESC_EOP               (1 << 9)
+
+/* Receive Status bits */
+#define RX_STATUS_UCAST                        0
+#define RX_STATUS_BCAST                        0x04
+#define RX_STATUS_MCAST                        0x08
+#define RX_STATUS_L2_MCAST             0x0c
+#define RX_STATUS_ERR                  (1 << 4)
+#define RX_STATUS_OVFLOW               (1 << 5)
+#define RX_STATUS_PARSE_FAIL           (1 << 6)
+
+/* Transmit Status bits */
+#define TX_STATUS_VLAN_NO_ACT          0x00
+#define TX_STATUS_VLAN_PCP_TSB         0x01
+#define TX_STATUS_VLAN_QUEUE           0x02
+#define TX_STATUS_VLAN_VID_TSB         0x03
+#define TX_STATUS_OWR_CRC              (1 << 2)
+#define TX_STATUS_APP_CRC              (1 << 3)
+#define TX_STATUS_BRCM_TAG_NO_ACT      0
+#define TX_STATUS_BRCM_TAG_ZERO                0x10
+#define TX_STATUS_BRCM_TAG_ONE_QUEUE   0x20
+#define TX_STATUS_BRCM_TAG_ONE_TSB     0x30
+#define TX_STATUS_SKIP_BYTES           (1 << 6)
+
+/* Specific register definitions */
+#define SYS_PORT_TOPCTRL_OFFSET                0
+#define REV_CNTL                       0x00
+#define  REV_MASK                      0xffff
+
+#define RX_FLUSH_CNTL                  0x04
+#define  RX_FLUSH                      (1 << 0)
+
+#define TX_FLUSH_CNTL                  0x08
+#define  TX_FLUSH                      (1 << 0)
+
+#define MISC_CNTL                      0x0c
+#define  SYS_CLK_SEL                   (1 << 0)
+#define  TDMA_EOP_SEL                  (1 << 1)
+
+/* Level-2 Interrupt controller offsets and defines */
+#define SYS_PORT_INTRL2_0_OFFSET       0x200
+#define SYS_PORT_INTRL2_1_OFFSET       0x240
+#define INTRL2_CPU_STATUS              0x00
+#define INTRL2_CPU_SET                 0x04
+#define INTRL2_CPU_CLEAR               0x08
+#define INTRL2_CPU_MASK_STATUS         0x0c
+#define INTRL2_CPU_MASK_SET            0x10
+#define INTRL2_CPU_MASK_CLEAR          0x14
+
+/* Level-2 instance 0 interrupt bits */
+#define INTRL2_0_GISB_ERR              (1 << 0)
+#define INTRL2_0_RBUF_OVFLOW           (1 << 1)
+#define INTRL2_0_TBUF_UNDFLOW          (1 << 2)
+#define INTRL2_0_MPD                   (1 << 3)
+#define INTRL2_0_BRCM_MATCH_TAG                (1 << 4)
+#define INTRL2_0_RDMA_MBDONE           (1 << 5)
+#define INTRL2_0_OVER_MAX_THRESH       (1 << 6)
+#define INTRL2_0_BELOW_HYST_THRESH     (1 << 7)
+#define INTRL2_0_FREE_LIST_EMPTY       (1 << 8)
+#define INTRL2_0_TX_RING_FULL          (1 << 9)
+#define INTRL2_0_DESC_ALLOC_ERR                (1 << 10)
+#define INTRL2_0_UNEXP_PKTSIZE_ACK     (1 << 11)
+
+/* RXCHK offset and defines */
+#define SYS_PORT_RXCHK_OFFSET          0x300
+
+#define RXCHK_CONTROL                  0x00
+#define  RXCHK_EN                      (1 << 0)
+#define  RXCHK_SKIP_FCS                        (1 << 1)
+#define  RXCHK_BAD_CSUM_DIS            (1 << 2)
+#define  RXCHK_BRCM_TAG_EN             (1 << 3)
+#define  RXCHK_BRCM_TAG_MATCH_SHIFT    4
+#define  RXCHK_BRCM_TAG_MATCH_MASK     0xff
+#define  RXCHK_PARSE_TNL               (1 << 12)
+#define  RXCHK_VIOL_EN                 (1 << 13)
+#define  RXCHK_VIOL_DIS                        (1 << 14)
+#define  RXCHK_INCOM_PKT               (1 << 15)
+#define  RXCHK_V6_DUPEXT_EN            (1 << 16)
+#define  RXCHK_V6_DUPEXT_DIS           (1 << 17)
+#define  RXCHK_ETHERTYPE_DIS           (1 << 18)
+#define  RXCHK_L2_HDR_DIS              (1 << 19)
+#define  RXCHK_L3_HDR_DIS              (1 << 20)
+#define  RXCHK_MAC_RX_ERR_DIS          (1 << 21)
+#define  RXCHK_PARSE_AUTH              (1 << 22)
+
+#define RXCHK_BRCM_TAG0                        0x04
+#define RXCHK_BRCM_TAG(i)              ((i) * RXCHK_BRCM_TAG0)
+#define RXCHK_BRCM_TAG0_MASK           0x24
+#define RXCHK_BRCM_TAG_MASK(i)         ((i) * RXCHK_BRCM_TAG0_MASK)
+#define RXCHK_BRCM_TAG_MATCH_STATUS    0x44
+#define RXCHK_ETHERTYPE                        0x48
+#define RXCHK_BAD_CSUM_CNTR            0x4C
+#define RXCHK_OTHER_DISC_CNTR          0x50
+
+/* TXCHCK offsets and defines */
+#define SYS_PORT_TXCHK_OFFSET          0x380
+#define TXCHK_PKT_RDY_THRESH           0x00
+
+/* Receive buffer offset and defines */
+#define SYS_PORT_RBUF_OFFSET           0x400
+
+#define RBUF_CONTROL                   0x00
+#define  RBUF_RSB_EN                   (1 << 0)
+#define  RBUF_4B_ALGN                  (1 << 1)
+#define  RBUF_BRCM_TAG_STRIP           (1 << 2)
+#define  RBUF_BAD_PKT_DISC             (1 << 3)
+#define  RBUF_RESUME_THRESH_SHIFT      4
+#define  RBUF_RESUME_THRESH_MASK       0xff
+#define  RBUF_OK_TO_SEND_SHIFT         12
+#define  RBUF_OK_TO_SEND_MASK          0xff
+#define  RBUF_CRC_REPLACE              (1 << 20)
+#define  RBUF_OK_TO_SEND_MODE          (1 << 21)
+#define  RBUF_RSB_SWAP                 (1 << 22)
+#define  RBUF_ACPI_EN                  (1 << 23)
+
+#define RBUF_PKT_RDY_THRESH            0x04
+
+#define RBUF_STATUS                    0x08
+#define  RBUF_WOL_MODE                 (1 << 0)
+#define  RBUF_MPD                      (1 << 1)
+#define  RBUF_ACPI                     (1 << 2)
+
+#define RBUF_OVFL_DISC_CNTR            0x0c
+#define RBUF_ERR_PKT_CNTR              0x10
+
+/* Transmit buffer offset and defines */
+#define SYS_PORT_TBUF_OFFSET           0x600
+
+#define TBUF_CONTROL                   0x00
+#define  TBUF_BP_EN                    (1 << 0)
+#define  TBUF_MAX_PKT_THRESH_SHIFT     1
+#define  TBUF_MAX_PKT_THRESH_MASK      0x1f
+#define  TBUF_FULL_THRESH_SHIFT                8
+#define  TBUF_FULL_THRESH_MASK         0x1f
+
+/* UniMAC offset and defines */
+#define SYS_PORT_UMAC_OFFSET           0x800
+
+#define UMAC_CMD                       0x008
+#define  CMD_TX_EN                     (1 << 0)
+#define  CMD_RX_EN                     (1 << 1)
+#define  CMD_SPEED_SHIFT               2
+#define  CMD_SPEED_10                  0
+#define  CMD_SPEED_100                 1
+#define  CMD_SPEED_1000                        2
+#define  CMD_SPEED_2500                        3
+#define  CMD_SPEED_MASK                        3
+#define  CMD_PROMISC                   (1 << 4)
+#define  CMD_PAD_EN                    (1 << 5)
+#define  CMD_CRC_FWD                   (1 << 6)
+#define  CMD_PAUSE_FWD                 (1 << 7)
+#define  CMD_RX_PAUSE_IGNORE           (1 << 8)
+#define  CMD_TX_ADDR_INS               (1 << 9)
+#define  CMD_HD_EN                     (1 << 10)
+#define  CMD_SW_RESET                  (1 << 13)
+#define  CMD_LCL_LOOP_EN               (1 << 15)
+#define  CMD_AUTO_CONFIG               (1 << 22)
+#define  CMD_CNTL_FRM_EN               (1 << 23)
+#define  CMD_NO_LEN_CHK                        (1 << 24)
+#define  CMD_RMT_LOOP_EN               (1 << 25)
+#define  CMD_PRBL_EN                   (1 << 27)
+#define  CMD_TX_PAUSE_IGNORE           (1 << 28)
+#define  CMD_TX_RX_EN                  (1 << 29)
+#define  CMD_RUNT_FILTER_DIS           (1 << 30)
+
+#define UMAC_MAC0                      0x00c
+#define UMAC_MAC1                      0x010
+#define UMAC_MAX_FRAME_LEN             0x014
+
+#define UMAC_TX_FLUSH                  0x334
+
+#define UMAC_MIB_START                 0x400
+
+/* There is a 0xC gap between the end of RX and beginning of TX stats and then
+ * between the end of TX stats and the beginning of the RX RUNT
+ */
+#define UMAC_MIB_STAT_OFFSET           0xc
+
+#define UMAC_MIB_CTRL                  0x580
+#define  MIB_RX_CNT_RST                        (1 << 0)
+#define  MIB_RUNT_CNT_RST              (1 << 1)
+#define  MIB_TX_CNT_RST                        (1 << 2)
+#define UMAC_MDF_CTRL                  0x650
+#define UMAC_MDF_ADDR                  0x654
+
+/* Receive DMA offset and defines */
+#define SYS_PORT_RDMA_OFFSET           0x2000
+
+#define RDMA_CONTROL                   0x1000
+#define  RDMA_EN                       (1 << 0)
+#define  RDMA_RING_CFG                 (1 << 1)
+#define  RDMA_DISC_EN                  (1 << 2)
+#define  RDMA_BUF_DATA_OFFSET_SHIFT    4
+#define  RDMA_BUF_DATA_OFFSET_MASK     0x3ff
+
+#define RDMA_STATUS                    0x1004
+#define  RDMA_DISABLED                 (1 << 0)
+#define  RDMA_DESC_RAM_INIT_BUSY       (1 << 1)
+#define  RDMA_BP_STATUS                        (1 << 2)
+
+#define RDMA_SCB_BURST_SIZE            0x1008
+
+#define RDMA_RING_BUF_SIZE             0x100c
+#define  RDMA_RING_SIZE_SHIFT          16
+
+#define RDMA_WRITE_PTR_HI              0x1010
+#define RDMA_WRITE_PTR_LO              0x1014
+#define RDMA_PROD_INDEX                        0x1018
+#define  RDMA_PROD_INDEX_MASK          0xffff
+
+#define RDMA_CONS_INDEX                        0x101c
+#define  RDMA_CONS_INDEX_MASK          0xffff
+
+#define RDMA_START_ADDR_HI             0x1020
+#define RDMA_START_ADDR_LO             0x1024
+#define RDMA_END_ADDR_HI               0x1028
+#define RDMA_END_ADDR_LO               0x102c
+
+#define RDMA_MBDONE_INTR               0x1030
+#define  RDMA_INTR_THRESH_MASK         0xff
+#define  RDMA_TIMEOUT_SHIFT            16
+#define  RDMA_TIMEOUT_MASK             0xffff
+
+#define RDMA_XON_XOFF_THRESH           0x1034
+#define  RDMA_XON_XOFF_THRESH_MASK     0xffff
+#define  RDMA_XOFF_THRESH_SHIFT                16
+
+#define RDMA_READ_PTR_HI               0x1038
+#define RDMA_READ_PTR_LO               0x103c
+
+#define RDMA_OVERRIDE                  0x1040
+#define  RDMA_LE_MODE                  (1 << 0)
+#define  RDMA_REG_MODE                 (1 << 1)
+
+#define RDMA_TEST                      0x1044
+#define  RDMA_TP_OUT_SEL               (1 << 0)
+#define  RDMA_MEM_SEL                  (1 << 1)
+
+#define RDMA_DEBUG                     0x1048
+
+/* Transmit DMA offset and defines */
+#define TDMA_NUM_RINGS                 32      /* rings = queues */
+#define TDMA_PORT_SIZE                 DESC_SIZE /* two 32-bits words */
+
+#define SYS_PORT_TDMA_OFFSET           0x4000
+#define TDMA_WRITE_PORT_OFFSET         0x0000
+#define TDMA_WRITE_PORT_HI(i)          (TDMA_WRITE_PORT_OFFSET + \
+                                       (i) * TDMA_PORT_SIZE)
+#define TDMA_WRITE_PORT_LO(i)          (TDMA_WRITE_PORT_OFFSET + \
+                                       sizeof(u32) + (i) * TDMA_PORT_SIZE)
+
+#define TDMA_READ_PORT_OFFSET          (TDMA_WRITE_PORT_OFFSET + \
+                                       (TDMA_NUM_RINGS * TDMA_PORT_SIZE))
+#define TDMA_READ_PORT_HI(i)           (TDMA_READ_PORT_OFFSET + \
+                                       (i) * TDMA_PORT_SIZE)
+#define TDMA_READ_PORT_LO(i)           (TDMA_READ_PORT_OFFSET + \
+                                       sizeof(u32) + (i) * TDMA_PORT_SIZE)
+
+#define TDMA_READ_PORT_CMD_OFFSET      (TDMA_READ_PORT_OFFSET + \
+                                       (TDMA_NUM_RINGS * TDMA_PORT_SIZE))
+#define TDMA_READ_PORT_CMD(i)          (TDMA_READ_PORT_CMD_OFFSET + \
+                                       (i) * sizeof(u32))
+
+#define TDMA_DESC_RING_00_BASE         (TDMA_READ_PORT_CMD_OFFSET + \
+                                       (TDMA_NUM_RINGS * sizeof(u32)))
+
+/* Register offsets and defines relatives to a specific ring number */
+#define RING_HEAD_TAIL_PTR             0x00
+#define  RING_HEAD_MASK                        0x7ff
+#define  RING_TAIL_SHIFT               11
+#define  RING_TAIL_MASK                        0x7ff
+#define  RING_FLUSH                    (1 << 24)
+#define  RING_EN                       (1 << 25)
+
+#define RING_COUNT                     0x04
+#define  RING_COUNT_MASK               0x7ff
+#define  RING_BUFF_DONE_SHIFT          11
+#define  RING_BUFF_DONE_MASK           0x7ff
+
+#define RING_MAX_HYST                  0x08
+#define  RING_MAX_THRESH_MASK          0x7ff
+#define  RING_HYST_THRESH_SHIFT                11
+#define  RING_HYST_THRESH_MASK         0x7ff
+
+#define RING_INTR_CONTROL              0x0c
+#define  RING_INTR_THRESH_MASK         0x7ff
+#define  RING_EMPTY_INTR_EN            (1 << 15)
+#define  RING_TIMEOUT_SHIFT            16
+#define  RING_TIMEOUT_MASK             0xffff
+
+#define RING_PROD_CONS_INDEX           0x10
+#define  RING_PROD_INDEX_MASK          0xffff
+#define  RING_CONS_INDEX_SHIFT         16
+#define  RING_CONS_INDEX_MASK          0xffff
+
+#define RING_MAPPING                   0x14
+#define  RING_QID_MASK                 0x3
+#define  RING_PORT_ID_SHIFT            3
+#define  RING_PORT_ID_MASK             0x7
+#define  RING_IGNORE_STATUS            (1 << 6)
+#define  RING_FAILOVER_EN              (1 << 7)
+#define  RING_CREDIT_SHIFT             8
+#define  RING_CREDIT_MASK              0xffff
+
+#define RING_PCP_DEI_VID               0x18
+#define  RING_VID_MASK                 0x7ff
+#define  RING_DEI                      (1 << 12)
+#define  RING_PCP_SHIFT                        13
+#define  RING_PCP_MASK                 0x7
+#define  RING_PKT_SIZE_ADJ_SHIFT       16
+#define  RING_PKT_SIZE_ADJ_MASK                0xf
+
+#define TDMA_DESC_RING_SIZE            28
+
+/* Defininition for a given TX ring base address */
+#define TDMA_DESC_RING_BASE(i)         (TDMA_DESC_RING_00_BASE + \
+                                       ((i) * TDMA_DESC_RING_SIZE))
+
+/* Ring indexed register addreses */
+#define TDMA_DESC_RING_HEAD_TAIL_PTR(i)        (TDMA_DESC_RING_BASE(i) + \
+                                       RING_HEAD_TAIL_PTR)
+#define TDMA_DESC_RING_COUNT(i)                (TDMA_DESC_RING_BASE(i) + \
+                                       RING_COUNT)
+#define TDMA_DESC_RING_MAX_HYST(i)     (TDMA_DESC_RING_BASE(i) + \
+                                       RING_MAX_HYST)
+#define TDMA_DESC_RING_INTR_CONTROL(i) (TDMA_DESC_RING_BASE(i) + \
+                                       RING_INTR_CONTROL)
+#define TDMA_DESC_RING_PROD_CONS_INDEX(i) \
+                                       (TDMA_DESC_RING_BASE(i) + \
+                                       RING_PROD_CONS_INDEX)
+#define TDMA_DESC_RING_MAPPING(i)      (TDMA_DESC_RING_BASE(i) + \
+                                       RING_MAPPING)
+#define TDMA_DESC_RING_PCP_DEI_VID(i)  (TDMA_DESC_RING_BASE(i) + \
+                                       RING_PCP_DEI_VID)
+
+#define TDMA_CONTROL                   0x600
+#define  TDMA_EN                       (1 << 0)
+#define  TSB_EN                                (1 << 1)
+#define  TSB_SWAP                      (1 << 2)
+#define  ACB_ALGO                      (1 << 3)
+#define  BUF_DATA_OFFSET_SHIFT         4
+#define  BUF_DATA_OFFSET_MASK          0x3ff
+#define  VLAN_EN                       (1 << 14)
+#define  SW_BRCM_TAG                   (1 << 15)
+#define  WNC_KPT_SIZE_UPDATE           (1 << 16)
+#define  SYNC_PKT_SIZE                 (1 << 17)
+#define  ACH_TXDONE_DELAY_SHIFT                18
+#define  ACH_TXDONE_DELAY_MASK         0xff
+
+#define TDMA_STATUS                    0x604
+#define  TDMA_DISABLED                 (1 << 0)
+#define  TDMA_LL_RAM_INIT_BUSY         (1 << 1)
+
+#define TDMA_SCB_BURST_SIZE            0x608
+#define TDMA_OVER_MAX_THRESH_STATUS    0x60c
+#define TDMA_OVER_HYST_THRESH_STATUS   0x610
+#define TDMA_TPID                      0x614
+
+#define TDMA_FREE_LIST_HEAD_TAIL_PTR   0x618
+#define  TDMA_FREE_HEAD_MASK           0x7ff
+#define  TDMA_FREE_TAIL_SHIFT          11
+#define  TDMA_FREE_TAIL_MASK           0x7ff
+
+#define TDMA_FREE_LIST_COUNT           0x61c
+#define  TDMA_FREE_LIST_COUNT_MASK     0x7ff
+
+#define TDMA_TIER2_ARB_CTRL            0x620
+#define  TDMA_ARB_MODE_RR              0
+#define  TDMA_ARB_MODE_WEIGHT_RR       0x1
+#define  TDMA_ARB_MODE_STRICT          0x2
+#define  TDMA_ARB_MODE_DEFICIT_RR      0x3
+#define  TDMA_CREDIT_SHIFT             4
+#define  TDMA_CREDIT_MASK              0xffff
+
+#define TDMA_TIER1_ARB_0_CTRL          0x624
+#define  TDMA_ARB_EN                   (1 << 0)
+
+#define TDMA_TIER1_ARB_0_QUEUE_EN      0x628
+#define TDMA_TIER1_ARB_1_CTRL          0x62c
+#define TDMA_TIER1_ARB_1_QUEUE_EN      0x630
+#define TDMA_TIER1_ARB_2_CTRL          0x634
+#define TDMA_TIER1_ARB_2_QUEUE_EN      0x638
+#define TDMA_TIER1_ARB_3_CTRL          0x63c
+#define TDMA_TIER1_ARB_3_QUEUE_EN      0x640
+
+#define TDMA_SCB_ENDIAN_OVERRIDE       0x644
+#define  TDMA_LE_MODE                  (1 << 0)
+#define  TDMA_REG_MODE                 (1 << 1)
+
+#define TDMA_TEST                      0x648
+#define  TDMA_TP_OUT_SEL               (1 << 0)
+#define  TDMA_MEM_TM                   (1 << 1)
+
+#define TDMA_DEBUG                     0x64c
+
+/* Transmit/Receive descriptor */
+struct dma_desc {
+       u32     addr_status_len;
+       u32     addr_lo;
+};
+
+/* Number of Receive hardware descriptor words */
+#define NUM_HW_RX_DESC_WORDS           1024
+/* Real number of usable descriptors */
+#define NUM_RX_DESC                    (NUM_HW_RX_DESC_WORDS / WORDS_PER_DESC)
+
+/* Internal linked-list RAM has up to 1536 entries */
+#define NUM_TX_DESC                    1536
+
+#define WORDS_PER_DESC                 (sizeof(struct dma_desc) / sizeof(u32))
+
+/* Rx/Tx common counter group.*/
+struct bcm_sysport_pkt_counters {
+       u32     cnt_64;         /* RO Received/Transmited 64 bytes packet */
+       u32     cnt_127;        /* RO Rx/Tx 127 bytes packet */
+       u32     cnt_255;        /* RO Rx/Tx 65-255 bytes packet */
+       u32     cnt_511;        /* RO Rx/Tx 256-511 bytes packet */
+       u32     cnt_1023;       /* RO Rx/Tx 512-1023 bytes packet */
+       u32     cnt_1518;       /* RO Rx/Tx 1024-1518 bytes packet */
+       u32     cnt_mgv;        /* RO Rx/Tx 1519-1522 good VLAN packet */
+       u32     cnt_2047;       /* RO Rx/Tx 1522-2047 bytes packet*/
+       u32     cnt_4095;       /* RO Rx/Tx 2048-4095 bytes packet*/
+       u32     cnt_9216;       /* RO Rx/Tx 4096-9216 bytes packet*/
+};
+
+/* RSV, Receive Status Vector */
+struct bcm_sysport_rx_counters {
+       struct  bcm_sysport_pkt_counters pkt_cnt;
+       u32     pkt;            /* RO (0x428) Received pkt count*/
+       u32     bytes;          /* RO Received byte count */
+       u32     mca;            /* RO # of Received multicast pkt */
+       u32     bca;            /* RO # of Receive broadcast pkt */
+       u32     fcs;            /* RO # of Received FCS error  */
+       u32     cf;             /* RO # of Received control frame pkt*/
+       u32     pf;             /* RO # of Received pause frame pkt */
+       u32     uo;             /* RO # of unknown op code pkt */
+       u32     aln;            /* RO # of alignment error count */
+       u32     flr;            /* RO # of frame length out of range count */
+       u32     cde;            /* RO # of code error pkt */
+       u32     fcr;            /* RO # of carrier sense error pkt */
+       u32     ovr;            /* RO # of oversize pkt*/
+       u32     jbr;            /* RO # of jabber count */
+       u32     mtue;           /* RO # of MTU error pkt*/
+       u32     pok;            /* RO # of Received good pkt */
+       u32     uc;             /* RO # of unicast pkt */
+       u32     ppp;            /* RO # of PPP pkt */
+       u32     rcrc;           /* RO (0x470),# of CRC match pkt */
+};
+
+/* TSV, Transmit Status Vector */
+struct bcm_sysport_tx_counters {
+       struct bcm_sysport_pkt_counters pkt_cnt;
+       u32     pkts;           /* RO (0x4a8) Transmited pkt */
+       u32     mca;            /* RO # of xmited multicast pkt */
+       u32     bca;            /* RO # of xmited broadcast pkt */
+       u32     pf;             /* RO # of xmited pause frame count */
+       u32     cf;             /* RO # of xmited control frame count */
+       u32     fcs;            /* RO # of xmited FCS error count */
+       u32     ovr;            /* RO # of xmited oversize pkt */
+       u32     drf;            /* RO # of xmited deferral pkt */
+       u32     edf;            /* RO # of xmited Excessive deferral pkt*/
+       u32     scl;            /* RO # of xmited single collision pkt */
+       u32     mcl;            /* RO # of xmited multiple collision pkt*/
+       u32     lcl;            /* RO # of xmited late collision pkt */
+       u32     ecl;            /* RO # of xmited excessive collision pkt*/
+       u32     frg;            /* RO # of xmited fragments pkt*/
+       u32     ncl;            /* RO # of xmited total collision count */
+       u32     jbr;            /* RO # of xmited jabber count*/
+       u32     bytes;          /* RO # of xmited byte count */
+       u32     pok;            /* RO # of xmited good pkt */
+       u32     uc;             /* RO (0x0x4f0)# of xmited unitcast pkt */
+};
+
+struct bcm_sysport_mib {
+       struct bcm_sysport_rx_counters rx;
+       struct bcm_sysport_tx_counters tx;
+       u32 rx_runt_cnt;
+       u32 rx_runt_fcs;
+       u32 rx_runt_fcs_align;
+       u32 rx_runt_bytes;
+       u32 rxchk_bad_csum;
+       u32 rxchk_other_pkt_disc;
+       u32 rbuf_ovflow_cnt;
+       u32 rbuf_err_cnt;
+};
+
+/* HW maintains a large list of counters */
+enum bcm_sysport_stat_type {
+       BCM_SYSPORT_STAT_NETDEV = -1,
+       BCM_SYSPORT_STAT_MIB_RX,
+       BCM_SYSPORT_STAT_MIB_TX,
+       BCM_SYSPORT_STAT_RUNT,
+       BCM_SYSPORT_STAT_RXCHK,
+       BCM_SYSPORT_STAT_RBUF,
+};
+
+/* Macros to help define ethtool statistics */
+#define STAT_NETDEV(m) { \
+       .stat_string = __stringify(m), \
+       .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \
+       .stat_offset = offsetof(struct net_device_stats, m), \
+       .type = BCM_SYSPORT_STAT_NETDEV, \
+}
+
+#define STAT_MIB(str, m, _type) { \
+       .stat_string = str, \
+       .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \
+       .stat_offset = offsetof(struct bcm_sysport_priv, m), \
+       .type = _type, \
+}
+
+#define STAT_MIB_RX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_RX)
+#define STAT_MIB_TX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_TX)
+#define STAT_RUNT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_RUNT)
+
+#define STAT_RXCHK(str, m, ofs) { \
+       .stat_string = str, \
+       .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \
+       .stat_offset = offsetof(struct bcm_sysport_priv, m), \
+       .type = BCM_SYSPORT_STAT_RXCHK, \
+       .reg_offset = ofs, \
+}
+
+#define STAT_RBUF(str, m, ofs) { \
+       .stat_string = str, \
+       .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \
+       .stat_offset = offsetof(struct bcm_sysport_priv, m), \
+       .type = BCM_SYSPORT_STAT_RBUF, \
+       .reg_offset = ofs, \
+}
+
+struct bcm_sysport_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int stat_sizeof;
+       int stat_offset;
+       enum bcm_sysport_stat_type type;
+       /* reg offset from UMAC base for misc counters */
+       u16 reg_offset;
+};
+
+/* Software house keeping helper structure */
+struct bcm_sysport_cb {
+       struct sk_buff  *skb;           /* SKB for RX packets */
+       void __iomem    *bd_addr;       /* Buffer descriptor PHYS addr */
+
+       DEFINE_DMA_UNMAP_ADDR(dma_addr);
+       DEFINE_DMA_UNMAP_LEN(dma_len);
+};
+
+/* Software view of the TX ring */
+struct bcm_sysport_tx_ring {
+       spinlock_t      lock;           /* Ring lock for tx reclaim/xmit */
+       struct napi_struct napi;        /* NAPI per tx queue */
+       dma_addr_t      desc_dma;       /* DMA cookie */
+       unsigned int    index;          /* Ring index */
+       unsigned int    size;           /* Ring current size */
+       unsigned int    alloc_size;     /* Ring one-time allocated size */
+       unsigned int    desc_count;     /* Number of descriptors */
+       unsigned int    curr_desc;      /* Current descriptor */
+       unsigned int    c_index;        /* Last consumer index */
+       unsigned int    p_index;        /* Current producer index */
+       struct bcm_sysport_cb *cbs;     /* Transmit control blocks */
+       struct dma_desc *desc_cpu;      /* CPU view of the descriptor */
+       struct bcm_sysport_priv *priv;  /* private context backpointer */
+};
+
+/* Driver private structure */
+struct bcm_sysport_priv {
+       void __iomem            *base;
+       u32                     irq0_stat;
+       u32                     irq0_mask;
+       u32                     irq1_stat;
+       u32                     irq1_mask;
+       struct napi_struct      napi ____cacheline_aligned;
+       struct net_device       *netdev;
+       struct platform_device  *pdev;
+       int                     irq0;
+       int                     irq1;
+
+       /* Transmit rings */
+       struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS];
+
+       /* Receive queue */
+       void __iomem            *rx_bds;
+       void __iomem            *rx_bd_assign_ptr;
+       unsigned int            rx_bd_assign_index;
+       struct bcm_sysport_cb   *rx_cbs;
+       unsigned int            num_rx_bds;
+       unsigned int            rx_read_ptr;
+       unsigned int            rx_c_index;
+
+       /* PHY device */
+       struct phy_device       *phydev;
+       phy_interface_t         phy_interface;
+       int                     old_pause;
+       int                     old_link;
+       int                     old_duplex;
+
+       /* Misc fields */
+       unsigned int            rx_csum_en:1;
+       unsigned int            tsb_en:1;
+       unsigned int            crc_fwd:1;
+       u16                     rev;
+
+       /* MIB related fields */
+       struct bcm_sysport_mib  mib;
+
+       /* Ethtool */
+       u32                     msg_enable;
+};
+#endif /* __BCM_SYSPORT_H */
index a78edaccceee92d8f2439ac40f3b3ba887ec0000..b260913db23609ba34daf1f0e7d2165a7c2cc867 100644 (file)
@@ -13233,6 +13233,8 @@ static void __bnx2x_remove(struct pci_dev *pdev,
                                iounmap(bp->doorbells);
 
                        bnx2x_release_firmware(bp);
+               } else {
+                       bnx2x_vf_pci_dealloc(bp);
                }
                bnx2x_free_mem_bp(bp);
 
index 5c523b32db70126720dbf0b2914dcbb1a3391a2b..81cc2d9831c2192edcf414fa90dd4aa5962285aa 100644 (file)
@@ -427,7 +427,9 @@ static int bnx2x_vf_mac_vlan_config(struct bnx2x *bp,
        if (filter->add && filter->type == BNX2X_VF_FILTER_VLAN &&
            (atomic_read(&bnx2x_vfq(vf, qid, vlan_count)) >=
             vf_vlan_rules_cnt(vf))) {
-               BNX2X_ERR("No credits for vlan\n");
+               BNX2X_ERR("No credits for vlan [%d >= %d]\n",
+                         atomic_read(&bnx2x_vfq(vf, qid, vlan_count)),
+                         vf_vlan_rules_cnt(vf));
                return -ENOMEM;
        }
 
@@ -610,6 +612,7 @@ int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
                }
 
                /* add new mcasts */
+               mcast.mcast_list_len = mc_num;
                rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_ADD);
                if (rc)
                        BNX2X_ERR("Faled to add multicasts\n");
@@ -837,6 +840,29 @@ int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
        return 0;
 }
 
+static void bnx2x_iov_re_set_vlan_filters(struct bnx2x *bp,
+                                         struct bnx2x_virtf *vf,
+                                         int new)
+{
+       int num = vf_vlan_rules_cnt(vf);
+       int diff = new - num;
+       bool rc = true;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] - %d vlan filter credits [previously %d]\n",
+          vf->abs_vfid, new, num);
+
+       if (diff > 0)
+               rc = bp->vlans_pool.get(&bp->vlans_pool, diff);
+       else if (diff < 0)
+               rc = bp->vlans_pool.put(&bp->vlans_pool, -diff);
+
+       if (rc)
+               vf_vlan_rules_cnt(vf) = new;
+       else
+               DP(BNX2X_MSG_IOV, "vf[%d] - Failed to configure vlan filter credits change\n",
+                  vf->abs_vfid);
+}
+
 /* must be called after the number of PF queues and the number of VFs are
  * both known
  */
@@ -854,9 +880,11 @@ bnx2x_iov_static_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
        resc->num_mac_filters = 1;
 
        /* divvy up vlan rules */
+       bnx2x_iov_re_set_vlan_filters(bp, vf, 0);
        vlan_count = bp->vlans_pool.check(&bp->vlans_pool);
        vlan_count = 1 << ilog2(vlan_count);
-       resc->num_vlan_filters = vlan_count / BNX2X_NR_VIRTFN(bp);
+       bnx2x_iov_re_set_vlan_filters(bp, vf,
+                                     vlan_count / BNX2X_NR_VIRTFN(bp));
 
        /* no real limitation */
        resc->num_mc_filters = 0;
@@ -1478,10 +1506,6 @@ int bnx2x_iov_nic_init(struct bnx2x *bp)
                bnx2x_iov_static_resc(bp, vf);
 
                /* queues are initialized during VF-ACQUIRE */
-
-               /* reserve the vf vlan credit */
-               bp->vlans_pool.get(&bp->vlans_pool, vf_vlan_rules_cnt(vf));
-
                vf->filter_state = 0;
                vf->sp_cl_id = bnx2x_fp(bp, 0, cl_id);
 
@@ -1912,11 +1936,12 @@ int bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf,
        u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
        u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
 
+       /* Save a vlan filter for the Hypervisor */
        return ((req_resc->num_rxqs <= rxq_cnt) &&
                (req_resc->num_txqs <= txq_cnt) &&
                (req_resc->num_sbs <= vf_sb_count(vf))   &&
                (req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) &&
-               (req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf)));
+               (req_resc->num_vlan_filters <= vf_vlan_rules_visible_cnt(vf)));
 }
 
 /* CORE VF API */
@@ -1972,14 +1997,14 @@ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
        vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
        if (resc->num_mac_filters)
                vf_mac_rules_cnt(vf) = resc->num_mac_filters;
-       if (resc->num_vlan_filters)
-               vf_vlan_rules_cnt(vf) = resc->num_vlan_filters;
+       /* Add an additional vlan filter credit for the hypervisor */
+       bnx2x_iov_re_set_vlan_filters(bp, vf, resc->num_vlan_filters + 1);
 
        DP(BNX2X_MSG_IOV,
           "Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n",
           vf_sb_count(vf), vf_rxq_count(vf),
           vf_txq_count(vf), vf_mac_rules_cnt(vf),
-          vf_vlan_rules_cnt(vf));
+          vf_vlan_rules_visible_cnt(vf));
 
        /* Initialize the queues */
        if (!vf->vfqs) {
@@ -2896,6 +2921,14 @@ void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
        return bp->regview + PXP_VF_ADDR_DB_START;
 }
 
+void bnx2x_vf_pci_dealloc(struct bnx2x *bp)
+{
+       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+                      sizeof(struct bnx2x_vf_mbx_msg));
+       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->pf2vf_bulletin_mapping,
+                      sizeof(union pf_vf_bulletin));
+}
+
 int bnx2x_vf_pci_alloc(struct bnx2x *bp)
 {
        mutex_init(&bp->vf2pf_mutex);
@@ -2915,10 +2948,7 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
        return 0;
 
 alloc_mem_err:
-       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
-                      sizeof(struct bnx2x_vf_mbx_msg));
-       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->pf2vf_bulletin_mapping,
-                      sizeof(union pf_vf_bulletin));
+       bnx2x_vf_pci_dealloc(bp);
        return -ENOMEM;
 }
 
index 8bf764570eef773eafa87ffd0fca26592e4d64ef..6929adba52f97029cf1b0e4fa44b0838bef7046d 100644 (file)
@@ -159,6 +159,8 @@ struct bnx2x_virtf {
 #define vf_mac_rules_cnt(vf)           ((vf)->alloc_resc.num_mac_filters)
 #define vf_vlan_rules_cnt(vf)          ((vf)->alloc_resc.num_vlan_filters)
 #define vf_mc_rules_cnt(vf)            ((vf)->alloc_resc.num_mc_filters)
+       /* Hide a single vlan filter credit for the hypervisor */
+#define vf_vlan_rules_visible_cnt(vf)  (vf_vlan_rules_cnt(vf) - 1)
 
        u8 sb_count;    /* actual number of SBs */
        u8 igu_base_id; /* base igu status block id */
@@ -502,6 +504,7 @@ static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
 enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
 void bnx2x_timer_sriov(struct bnx2x *bp);
 void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp);
+void bnx2x_vf_pci_dealloc(struct bnx2x *bp);
 int bnx2x_vf_pci_alloc(struct bnx2x *bp);
 int bnx2x_enable_sriov(struct bnx2x *bp);
 void bnx2x_disable_sriov(struct bnx2x *bp);
@@ -568,6 +571,7 @@ static inline void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
        return NULL;
 }
 
+static inline void bnx2x_vf_pci_dealloc(struct bnx2 *bp) {return 0; }
 static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
 static inline void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) {}
 static inline int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs) {return 0; }
index 0622884596b2f478ec4a2789c17fdd0938544995..0c067e8564dd4e15e43a7e22f3e064091234b99a 100644 (file)
@@ -1163,7 +1163,7 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
                        bnx2x_vf_max_queue_cnt(bp, vf);
                resc->num_sbs = vf_sb_count(vf);
                resc->num_mac_filters = vf_mac_rules_cnt(vf);
-               resc->num_vlan_filters = vf_vlan_rules_cnt(vf);
+               resc->num_vlan_filters = vf_vlan_rules_visible_cnt(vf);
                resc->num_mc_filters = 0;
 
                if (status == PFVF_STATUS_SUCCESS) {
index 7e49c43b7af3501f953cac4796e4769da542c29d..9e089d24466e65fb6c8b01c08f2ece882e23aaaa 100644 (file)
@@ -4,7 +4,7 @@
 
 config NET_CADENCE
        bool "Cadence devices"
-       depends on HAS_IOMEM && (ARM || AVR32 || COMPILE_TEST)
+       depends on HAS_IOMEM && (ARM || AVR32 || MICROBLAZE || COMPILE_TEST)
        default y
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
@@ -30,7 +30,7 @@ config ARM_AT91_ETHER
 
 config MACB
        tristate "Cadence MACB/GEM support"
-       depends on HAS_DMA && (PLATFORM_AT32AP || ARCH_AT91 || ARCH_PICOXCELL || ARCH_ZYNQ || COMPILE_TEST)
+       depends on HAS_DMA && (PLATFORM_AT32AP || ARCH_AT91 || ARCH_PICOXCELL || ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST)
        select PHYLIB
        ---help---
          The Cadence MACB ethernet interface is found on many Atmel AT32 and
index ca97005e24b41217849beaf4b9a578fbaf1f2027..e9daa072ebb4f2c03af453255a9c374bde6ff47c 100644 (file)
@@ -599,25 +599,16 @@ static void gem_rx_refill(struct macb *bp)
 {
        unsigned int            entry;
        struct sk_buff          *skb;
-       struct macb_dma_desc    *desc;
        dma_addr_t              paddr;
 
        while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail, RX_RING_SIZE) > 0) {
-               u32 addr, ctrl;
-
                entry = macb_rx_ring_wrap(bp->rx_prepared_head);
-               desc = &bp->rx_ring[entry];
 
                /* Make hw descriptor updates visible to CPU */
                rmb();
 
-               addr = desc->addr;
-               ctrl = desc->ctrl;
                bp->rx_prepared_head++;
 
-               if ((addr & MACB_BIT(RX_USED)))
-                       continue;
-
                if (bp->rx_skbuff[entry] == NULL) {
                        /* allocate sk_buff for this free entry in ring */
                        skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size);
@@ -698,7 +689,6 @@ static int gem_rx(struct macb *bp, int budget)
                if (!(addr & MACB_BIT(RX_USED)))
                        break;
 
-               desc->addr &= ~MACB_BIT(RX_USED);
                bp->rx_tail++;
                count++;
 
@@ -891,16 +881,15 @@ static int macb_poll(struct napi_struct *napi, int budget)
        if (work_done < budget) {
                napi_complete(napi);
 
-               /*
-                * We've done what we can to clean the buffers. Make sure we
-                * get notified when new packets arrive.
-                */
-               macb_writel(bp, IER, MACB_RX_INT_FLAGS);
-
                /* Packets received while interrupts were disabled */
                status = macb_readl(bp, RSR);
-               if (unlikely(status))
+               if (status) {
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               macb_writel(bp, ISR, MACB_BIT(RCOMP));
                        napi_reschedule(napi);
+               } else {
+                       macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+               }
        }
 
        /* TODO: Handle errors */
@@ -951,6 +940,10 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                if (unlikely(status & (MACB_TX_ERR_FLAGS))) {
                        macb_writel(bp, IDR, MACB_TX_INT_FLAGS);
                        schedule_work(&bp->tx_error_task);
+
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               macb_writel(bp, ISR, MACB_TX_ERR_FLAGS);
+
                        break;
                }
 
@@ -968,6 +961,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                                bp->hw_stats.gem.rx_overruns++;
                        else
                                bp->hw_stats.macb.rx_overruns++;
+
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               macb_writel(bp, ISR, MACB_BIT(ISR_ROVR));
                }
 
                if (status & MACB_BIT(HRESP)) {
@@ -977,6 +973,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                         * (work queue?)
                         */
                        netdev_err(dev, "DMA bus error: HRESP not OK\n");
+
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               macb_writel(bp, ISR, MACB_BIT(HRESP));
                }
 
                status = macb_readl(bp, ISR);
@@ -1113,7 +1112,7 @@ static void gem_free_rx_buffers(struct macb *bp)
 
                desc = &bp->rx_ring[i];
                addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
-               dma_unmap_single(&bp->pdev->dev, addr, skb->len,
+               dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size,
                                 DMA_FROM_DEVICE);
                dev_kfree_skb_any(skb);
                skb = NULL;
index d40c994a4f6a2c807965e44eaf81f2be0053fb50..570222c3341070445b3b0c224205872f286a3cfd 100644 (file)
@@ -67,13 +67,13 @@ config CHELSIO_T3
          will be called cxgb3.
 
 config CHELSIO_T4
-       tristate "Chelsio Communications T4 Ethernet support"
+       tristate "Chelsio Communications T4/T5 Ethernet support"
        depends on PCI
        select FW_LOADER
        select MDIO
        ---help---
-         This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
-         adapters.
+         This driver supports Chelsio T4 and T5 based gigabit, 10Gb Ethernet
+         adapter and T5 based 40Gb Ethernet adapter.
 
          For general information about Chelsio and our products, visit
          our website at <http://www.chelsio.com>.
@@ -87,11 +87,12 @@ config CHELSIO_T4
          will be called cxgb4.
 
 config CHELSIO_T4VF
-       tristate "Chelsio Communications T4 Virtual Function Ethernet support"
+       tristate "Chelsio Communications T4/T5 Virtual Function Ethernet support"
        depends on PCI
        ---help---
-         This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
-         adapters with PCI-E SR-IOV Virtual Functions.
+         This driver supports Chelsio T4 and T5 based gigabit, 10Gb Ethernet
+         adapters and T5 based 40Gb Ethernet adapters with PCI-E SR-IOV Virtual
+         Functions.
 
          For general information about Chelsio and our products, visit
          our website at <http://www.chelsio.com>.
index 6fe58913403ab24f61ddf7f7e8d02714e040d250..24e16e3301e086d6cff3f28181d3c97a153bf343 100644 (file)
@@ -5870,6 +5870,8 @@ static void print_port_info(const struct net_device *dev)
                spd = " 2.5 GT/s";
        else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_5_0GB)
                spd = " 5 GT/s";
+       else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_8_0GB)
+               spd = " 8 GT/s";
 
        if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
                bufp += sprintf(bufp, "100/");
index 97db5a7179df1c6c733bed5e25e5be3d44d39fa1..2f67c7c8d41337ba5240f087b56606f842360936 100644 (file)
@@ -120,6 +120,9 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define MAX_VFS                        30 /* Max VFs supported by BE3 FW */
 #define FW_VER_LEN             32
 
+#define        RSS_INDIR_TABLE_LEN     128
+#define RSS_HASH_KEY_LEN       40
+
 struct be_dma_mem {
        void *va;
        dma_addr_t dma;
@@ -409,6 +412,13 @@ struct be_resources {
        u32 if_cap_flags;
 };
 
+struct rss_info {
+       u64 rss_flags;
+       u8 rsstable[RSS_INDIR_TABLE_LEN];
+       u8 rss_queue[RSS_INDIR_TABLE_LEN];
+       u8 rss_hkey[RSS_HASH_KEY_LEN];
+};
+
 struct be_adapter {
        struct pci_dev *pdev;
        struct net_device *netdev;
@@ -507,7 +517,7 @@ struct be_adapter {
        u32 msg_enable;
        int be_get_temp_freq;
        u8 pf_number;
-       u64 rss_flags;
+       struct rss_info rss_info;
 };
 
 #define be_physfn(adapter)             (!adapter->virtfn)
index d1ec15af0d2482f46c425bb7d2f6c99976c16329..07e78e89a348ecc1d84bff5f1767c48be9a12b00 100644 (file)
@@ -2020,13 +2020,10 @@ int be_cmd_reset_function(struct be_adapter *adapter)
 }
 
 int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
-                       u32 rss_hash_opts, u16 table_size)
+                       u32 rss_hash_opts, u16 table_size, u8 *rss_hkey)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_rss_config *req;
-       u32 myhash[10] = {0x15d43fa5, 0x2534685a, 0x5f87693a, 0x5668494e,
-                       0x33cf6a53, 0x383334c6, 0x76ac4257, 0x59b242b2,
-                       0x3ea83c02, 0x4a110304};
        int status;
 
        if (!(be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS))
@@ -2049,7 +2046,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
                req->hdr.version = 1;
 
        memcpy(req->cpu_table, rsstable, table_size);
-       memcpy(req->hash, myhash, sizeof(myhash));
+       memcpy(req->hash, rss_hkey, RSS_HASH_KEY_LEN);
        be_dws_cpu_to_le(req->hash, sizeof(req->hash));
 
        status = be_mbox_notify_wait(adapter);
index b60e4d53c1c9a9f29be9d1c2c07099dab28b378a..4ea79b9c67e934e9db0b414486aada60c8f959af 100644 (file)
@@ -2068,7 +2068,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
                        u32 *function_mode, u32 *function_caps, u16 *asic_rev);
 int be_cmd_reset_function(struct be_adapter *adapter);
 int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
-                     u32 rss_hash_opts, u16 table_size);
+                     u32 rss_hash_opts, u16 table_size, u8 *rss_hkey);
 int be_process_mcc(struct be_adapter *adapter);
 int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon,
                            u8 status, u8 state);
index 15ba96cba65df1ba051cc3b2e49b72640d92c217..6f3494e41511f67918c68e550a70d355ad99bc2f 100644 (file)
@@ -933,27 +933,27 @@ static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type)
 
        switch (flow_type) {
        case TCP_V4_FLOW:
-               if (adapter->rss_flags & RSS_ENABLE_IPV4)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4)
                        data |= RXH_IP_DST | RXH_IP_SRC;
-               if (adapter->rss_flags & RSS_ENABLE_TCP_IPV4)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV4)
                        data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
                break;
        case UDP_V4_FLOW:
-               if (adapter->rss_flags & RSS_ENABLE_IPV4)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4)
                        data |= RXH_IP_DST | RXH_IP_SRC;
-               if (adapter->rss_flags & RSS_ENABLE_UDP_IPV4)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV4)
                        data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
                break;
        case TCP_V6_FLOW:
-               if (adapter->rss_flags & RSS_ENABLE_IPV6)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6)
                        data |= RXH_IP_DST | RXH_IP_SRC;
-               if (adapter->rss_flags & RSS_ENABLE_TCP_IPV6)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV6)
                        data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
                break;
        case UDP_V6_FLOW:
-               if (adapter->rss_flags & RSS_ENABLE_IPV6)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6)
                        data |= RXH_IP_DST | RXH_IP_SRC;
-               if (adapter->rss_flags & RSS_ENABLE_UDP_IPV6)
+               if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV6)
                        data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
                break;
        }
@@ -992,7 +992,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,
        struct be_rx_obj *rxo;
        int status = 0, i, j;
        u8 rsstable[128];
-       u32 rss_flags = adapter->rss_flags;
+       u32 rss_flags = adapter->rss_info.rss_flags;
 
        if (cmd->data != L3_RSS_FLAGS &&
            cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS))
@@ -1039,7 +1039,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,
                return -EINVAL;
        }
 
-       if (rss_flags == adapter->rss_flags)
+       if (rss_flags == adapter->rss_info.rss_flags)
                return status;
 
        if (be_multi_rxq(adapter)) {
@@ -1051,9 +1051,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,
                        }
                }
        }
-       status = be_cmd_rss_config(adapter, rsstable, rss_flags, 128);
+
+       status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable,
+                                  rss_flags, 128, adapter->rss_info.rss_hkey);
        if (!status)
-               adapter->rss_flags = rss_flags;
+               adapter->rss_info.rss_flags = rss_flags;
 
        return status;
 }
@@ -1103,6 +1105,68 @@ static int be_set_channels(struct net_device  *netdev,
        return be_update_queues(adapter);
 }
 
+static u32 be_get_rxfh_indir_size(struct net_device *netdev)
+{
+       return RSS_INDIR_TABLE_LEN;
+}
+
+static u32 be_get_rxfh_key_size(struct net_device *netdev)
+{
+       return RSS_HASH_KEY_LEN;
+}
+
+static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       int i;
+       struct rss_info *rss = &adapter->rss_info;
+
+       if (indir) {
+               for (i = 0; i < RSS_INDIR_TABLE_LEN; i++)
+                       indir[i] = rss->rss_queue[i];
+       }
+
+       if (hkey)
+               memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN);
+
+       return 0;
+}
+
+static int be_set_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey)
+{
+       int rc = 0, i, j;
+       struct be_adapter *adapter = netdev_priv(netdev);
+       u8 rsstable[RSS_INDIR_TABLE_LEN];
+
+       if (indir) {
+               struct be_rx_obj *rxo;
+               for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) {
+                       j = indir[i];
+                       rxo = &adapter->rx_obj[j];
+                       rsstable[i] = rxo->rss_id;
+                       adapter->rss_info.rss_queue[i] = j;
+               }
+       } else {
+               memcpy(rsstable, adapter->rss_info.rsstable,
+                      RSS_INDIR_TABLE_LEN);
+       }
+
+       if (!hkey)
+               hkey =  adapter->rss_info.rss_hkey;
+
+       rc = be_cmd_rss_config(adapter, rsstable,
+                       adapter->rss_info.rss_flags,
+                       RSS_INDIR_TABLE_LEN, hkey);
+       if (rc) {
+               adapter->rss_info.rss_flags = RSS_ENABLE_NONE;
+               return -EIO;
+       }
+       memcpy(adapter->rss_info.rss_hkey, hkey, RSS_HASH_KEY_LEN);
+       memcpy(adapter->rss_info.rsstable, rsstable,
+              RSS_INDIR_TABLE_LEN);
+       return 0;
+}
+
 const struct ethtool_ops be_ethtool_ops = {
        .get_settings = be_get_settings,
        .get_drvinfo = be_get_drvinfo,
@@ -1129,6 +1193,10 @@ const struct ethtool_ops be_ethtool_ops = {
        .self_test = be_self_test,
        .get_rxnfc = be_get_rxnfc,
        .set_rxnfc = be_set_rxnfc,
+       .get_rxfh_indir_size = be_get_rxfh_indir_size,
+       .get_rxfh_key_size = be_get_rxfh_key_size,
+       .get_rxfh = be_get_rxfh,
+       .set_rxfh = be_set_rxfh,
        .get_channels = be_get_channels,
        .set_channels = be_set_channels
 };
index a18645407d2152b43353a50b76ccf6317ef90151..a3c6a27d13fa59f29563e61602a47a1fd1863f0b 100644 (file)
@@ -2774,7 +2774,8 @@ static int be_rx_qs_create(struct be_adapter *adapter)
 {
        struct be_rx_obj *rxo;
        int rc, i, j;
-       u8 rsstable[128];
+       u8 rss_hkey[RSS_HASH_KEY_LEN];
+       struct rss_info *rss = &adapter->rss_info;
 
        for_all_rx_queues(adapter, rxo, i) {
                rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN,
@@ -2799,31 +2800,37 @@ static int be_rx_qs_create(struct be_adapter *adapter)
        }
 
        if (be_multi_rxq(adapter)) {
-               for (j = 0; j < 128; j += adapter->num_rx_qs - 1) {
+               for (j = 0; j < RSS_INDIR_TABLE_LEN;
+                       j += adapter->num_rx_qs - 1) {
                        for_all_rss_queues(adapter, rxo, i) {
-                               if ((j + i) >= 128)
+                               if ((j + i) >= RSS_INDIR_TABLE_LEN)
                                        break;
-                               rsstable[j + i] = rxo->rss_id;
+                               rss->rsstable[j + i] = rxo->rss_id;
+                               rss->rss_queue[j + i] = i;
                        }
                }
-               adapter->rss_flags = RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 |
-                                       RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6;
+               rss->rss_flags = RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 |
+                       RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6;
 
                if (!BEx_chip(adapter))
-                       adapter->rss_flags |= RSS_ENABLE_UDP_IPV4 |
-                                               RSS_ENABLE_UDP_IPV6;
+                       rss->rss_flags |= RSS_ENABLE_UDP_IPV4 |
+                               RSS_ENABLE_UDP_IPV6;
        } else {
                /* Disable RSS, if only default RX Q is created */
-               adapter->rss_flags = RSS_ENABLE_NONE;
+               rss->rss_flags = RSS_ENABLE_NONE;
        }
 
-       rc = be_cmd_rss_config(adapter, rsstable, adapter->rss_flags,
-                              128);
+       get_random_bytes(rss_hkey, RSS_HASH_KEY_LEN);
+       rc = be_cmd_rss_config(adapter, rss->rsstable,
+                              rss->rss_flags,
+                              128, rss_hkey);
        if (rc) {
-               adapter->rss_flags = RSS_ENABLE_NONE;
+               rss->rss_flags = RSS_ENABLE_NONE;
                return rc;
        }
 
+       memcpy(rss->rss_hkey, rss_hkey, RSS_HASH_KEY_LEN);
+
        /* First time posting */
        for_all_rx_queues(adapter, rxo, i)
                be_post_rx_frags(rxo, GFP_KERNEL);
index 8b70ca7e342b6f16a8d6624293ee1b940bcff3d5..f3658bdb64cc4265de972cfc2bbd25157e95a680 100644 (file)
@@ -769,11 +769,6 @@ static int ethoc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return phy_mii_ioctl(phy, ifr, cmd);
 }
 
-static int ethoc_config(struct net_device *dev, struct ifmap *map)
-{
-       return -ENOSYS;
-}
-
 static void ethoc_do_set_mac_address(struct net_device *dev)
 {
        struct ethoc *priv = netdev_priv(dev);
@@ -995,7 +990,6 @@ static const struct net_device_ops ethoc_netdev_ops = {
        .ndo_open = ethoc_open,
        .ndo_stop = ethoc_stop,
        .ndo_do_ioctl = ethoc_ioctl,
-       .ndo_set_config = ethoc_config,
        .ndo_set_mac_address = ethoc_set_mac_address,
        .ndo_set_rx_mode = ethoc_set_multicast_list,
        .ndo_change_mtu = ethoc_change_mtu,
index 9125d9abf0998d31e3179bd9c712af487855d5a9..e2d42475b006aa7a79f16b48ad618580d64c7593 100644 (file)
@@ -121,6 +121,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id);
 static irqreturn_t gfar_transmit(int irq, void *dev_id);
 static irqreturn_t gfar_interrupt(int irq, void *dev_id);
 static void adjust_link(struct net_device *dev);
+static noinline void gfar_update_link_state(struct gfar_private *priv);
 static int init_phy(struct net_device *dev);
 static int gfar_probe(struct platform_device *ofdev);
 static int gfar_remove(struct platform_device *ofdev);
@@ -3076,41 +3077,6 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id)
        return IRQ_HANDLED;
 }
 
-static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv)
-{
-       struct phy_device *phydev = priv->phydev;
-       u32 val = 0;
-
-       if (!phydev->duplex)
-               return val;
-
-       if (!priv->pause_aneg_en) {
-               if (priv->tx_pause_en)
-                       val |= MACCFG1_TX_FLOW;
-               if (priv->rx_pause_en)
-                       val |= MACCFG1_RX_FLOW;
-       } else {
-               u16 lcl_adv, rmt_adv;
-               u8 flowctrl;
-               /* get link partner capabilities */
-               rmt_adv = 0;
-               if (phydev->pause)
-                       rmt_adv = LPA_PAUSE_CAP;
-               if (phydev->asym_pause)
-                       rmt_adv |= LPA_PAUSE_ASYM;
-
-               lcl_adv = mii_advertise_flowctrl(phydev->advertising);
-
-               flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
-               if (flowctrl & FLOW_CTRL_TX)
-                       val |= MACCFG1_TX_FLOW;
-               if (flowctrl & FLOW_CTRL_RX)
-                       val |= MACCFG1_RX_FLOW;
-       }
-
-       return val;
-}
-
 /* Called every time the controller might need to be made
  * aware of new link state.  The PHY code conveys this
  * information through variables in the phydev structure, and this
@@ -3120,83 +3086,12 @@ static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv)
 static void adjust_link(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
        struct phy_device *phydev = priv->phydev;
-       int new_state = 0;
 
-       if (test_bit(GFAR_RESETTING, &priv->state))
-               return;
-
-       if (phydev->link) {
-               u32 tempval1 = gfar_read(&regs->maccfg1);
-               u32 tempval = gfar_read(&regs->maccfg2);
-               u32 ecntrl = gfar_read(&regs->ecntrl);
-
-               /* Now we make sure that we can be in full duplex mode.
-                * If not, we operate in half-duplex mode.
-                */
-               if (phydev->duplex != priv->oldduplex) {
-                       new_state = 1;
-                       if (!(phydev->duplex))
-                               tempval &= ~(MACCFG2_FULL_DUPLEX);
-                       else
-                               tempval |= MACCFG2_FULL_DUPLEX;
-
-                       priv->oldduplex = phydev->duplex;
-               }
-
-               if (phydev->speed != priv->oldspeed) {
-                       new_state = 1;
-                       switch (phydev->speed) {
-                       case 1000:
-                               tempval =
-                                   ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
-
-                               ecntrl &= ~(ECNTRL_R100);
-                               break;
-                       case 100:
-                       case 10:
-                               tempval =
-                                   ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
-
-                               /* Reduced mode distinguishes
-                                * between 10 and 100
-                                */
-                               if (phydev->speed == SPEED_100)
-                                       ecntrl |= ECNTRL_R100;
-                               else
-                                       ecntrl &= ~(ECNTRL_R100);
-                               break;
-                       default:
-                               netif_warn(priv, link, dev,
-                                          "Ack!  Speed (%d) is not 10/100/1000!\n",
-                                          phydev->speed);
-                               break;
-                       }
-
-                       priv->oldspeed = phydev->speed;
-               }
-
-               tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
-               tempval1 |= gfar_get_flowctrl_cfg(priv);
-
-               gfar_write(&regs->maccfg1, tempval1);
-               gfar_write(&regs->maccfg2, tempval);
-               gfar_write(&regs->ecntrl, ecntrl);
-
-               if (!priv->oldlink) {
-                       new_state = 1;
-                       priv->oldlink = 1;
-               }
-       } else if (priv->oldlink) {
-               new_state = 1;
-               priv->oldlink = 0;
-               priv->oldspeed = 0;
-               priv->oldduplex = -1;
-       }
-
-       if (new_state && netif_msg_link(priv))
-               phy_print_status(phydev);
+       if (unlikely(phydev->link != priv->oldlink ||
+                    phydev->duplex != priv->oldduplex ||
+                    phydev->speed != priv->oldspeed))
+               gfar_update_link_state(priv);
 }
 
 /* Update the hash table based on the current list of multicast
@@ -3442,6 +3337,114 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
        return IRQ_HANDLED;
 }
 
+static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv)
+{
+       struct phy_device *phydev = priv->phydev;
+       u32 val = 0;
+
+       if (!phydev->duplex)
+               return val;
+
+       if (!priv->pause_aneg_en) {
+               if (priv->tx_pause_en)
+                       val |= MACCFG1_TX_FLOW;
+               if (priv->rx_pause_en)
+                       val |= MACCFG1_RX_FLOW;
+       } else {
+               u16 lcl_adv, rmt_adv;
+               u8 flowctrl;
+               /* get link partner capabilities */
+               rmt_adv = 0;
+               if (phydev->pause)
+                       rmt_adv = LPA_PAUSE_CAP;
+               if (phydev->asym_pause)
+                       rmt_adv |= LPA_PAUSE_ASYM;
+
+               lcl_adv = mii_advertise_flowctrl(phydev->advertising);
+
+               flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+               if (flowctrl & FLOW_CTRL_TX)
+                       val |= MACCFG1_TX_FLOW;
+               if (flowctrl & FLOW_CTRL_RX)
+                       val |= MACCFG1_RX_FLOW;
+       }
+
+       return val;
+}
+
+static noinline void gfar_update_link_state(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       struct phy_device *phydev = priv->phydev;
+
+       if (unlikely(test_bit(GFAR_RESETTING, &priv->state)))
+               return;
+
+       if (phydev->link) {
+               u32 tempval1 = gfar_read(&regs->maccfg1);
+               u32 tempval = gfar_read(&regs->maccfg2);
+               u32 ecntrl = gfar_read(&regs->ecntrl);
+
+               if (phydev->duplex != priv->oldduplex) {
+                       if (!(phydev->duplex))
+                               tempval &= ~(MACCFG2_FULL_DUPLEX);
+                       else
+                               tempval |= MACCFG2_FULL_DUPLEX;
+
+                       priv->oldduplex = phydev->duplex;
+               }
+
+               if (phydev->speed != priv->oldspeed) {
+                       switch (phydev->speed) {
+                       case 1000:
+                               tempval =
+                                   ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
+
+                               ecntrl &= ~(ECNTRL_R100);
+                               break;
+                       case 100:
+                       case 10:
+                               tempval =
+                                   ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
+
+                               /* Reduced mode distinguishes
+                                * between 10 and 100
+                                */
+                               if (phydev->speed == SPEED_100)
+                                       ecntrl |= ECNTRL_R100;
+                               else
+                                       ecntrl &= ~(ECNTRL_R100);
+                               break;
+                       default:
+                               netif_warn(priv, link, priv->ndev,
+                                          "Ack!  Speed (%d) is not 10/100/1000!\n",
+                                          phydev->speed);
+                               break;
+                       }
+
+                       priv->oldspeed = phydev->speed;
+               }
+
+               tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
+               tempval1 |= gfar_get_flowctrl_cfg(priv);
+
+               gfar_write(&regs->maccfg1, tempval1);
+               gfar_write(&regs->maccfg2, tempval);
+               gfar_write(&regs->ecntrl, ecntrl);
+
+               if (!priv->oldlink)
+                       priv->oldlink = 1;
+
+       } else if (priv->oldlink) {
+               priv->oldlink = 0;
+               priv->oldspeed = 0;
+               priv->oldduplex = -1;
+       }
+
+       if (netif_msg_link(priv))
+               phy_print_status(phydev);
+}
+
 static struct of_device_id gfar_match[] =
 {
        {
index 891dbee6e6c14d2394cc2dff00092f448faf3dc2..76d70708f864af66b4a525e671f021e0d30a2b7d 100644 (file)
@@ -533,6 +533,9 @@ static int gfar_spauseparam(struct net_device *dev,
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 oldadv, newadv;
 
+       if (!phydev)
+               return -ENODEV;
+
        if (!(phydev->supported & SUPPORTED_Pause) ||
            (!(phydev->supported & SUPPORTED_Asym_Pause) &&
             (epause->rx_pause != epause->tx_pause)))
index 1471c5464a89e72d87aa571d4a1b15d791a3f015..e27e60910949c95a5217cad20bfc722e35527cc5 100644 (file)
@@ -265,10 +265,10 @@ struct e1000_adapter {
        u32 tx_hwtstamp_timeouts;
 
        /* Rx */
-       bool (*clean_rx) (struct e1000_ring *ring, int *work_done,
-                         int work_to_do) ____cacheline_aligned_in_smp;
-       void (*alloc_rx_buf) (struct e1000_ring *ring, int cleaned_count,
-                             gfp_t gfp);
+       bool (*clean_rx)(struct e1000_ring *ring, int *work_done,
+                        int work_to_do) ____cacheline_aligned_in_smp;
+       void (*alloc_rx_buf)(struct e1000_ring *ring, int cleaned_count,
+                            gfp_t gfp);
        struct e1000_ring *rx_ring;
 
        u32 rx_int_delay;
index cad250bc1b99fc81d51fb8956eee74c9acc3bc7e..4e5ad7ebe1f24b4f4b256f5de519eaa1e75d9cb4 100644 (file)
@@ -169,6 +169,7 @@ static int e1000_get_settings(struct net_device *netdev,
                }
        } else if (!pm_runtime_suspended(netdev->dev.parent)) {
                u32 status = er32(STATUS);
+
                if (status & E1000_STATUS_LU) {
                        if (status & E1000_STATUS_SPEED_1000)
                                speed = SPEED_1000;
@@ -783,25 +784,26 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data,
                              reg + (offset << 2), val,
                              (test[pat] & write & mask));
                        *data = reg;
-                       return 1;
+                       return true;
                }
        }
-       return 0;
+       return false;
 }
 
 static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data,
                              int reg, u32 mask, u32 write)
 {
        u32 val;
+
        __ew32(&adapter->hw, reg, write & mask);
        val = __er32(&adapter->hw, reg);
        if ((write & mask) != (val & mask)) {
                e_err("set/check test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
                      reg, (val & mask), (write & mask));
                *data = reg;
-               return 1;
+               return true;
        }
-       return 0;
+       return false;
 }
 
 #define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write)                       \
@@ -1717,6 +1719,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
        *data = 0;
        if (hw->phy.media_type == e1000_media_type_internal_serdes) {
                int i = 0;
+
                hw->mac.serdes_has_link = false;
 
                /* On some blade server designs, link establishment
index 9866f264f55e33a8e564757730ada0d6ab7c6a92..5f55395616612d843b10a9b7f6ad0345f15344fb 100644 (file)
@@ -186,7 +186,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
 {
        u16 phy_reg = 0;
        u32 phy_id = 0;
-       s32 ret_val;
+       s32 ret_val = 0;
        u16 retry_count;
        u32 mac_reg = 0;
 
@@ -217,11 +217,13 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
        /* In case the PHY needs to be in mdio slow mode,
         * set slow mode and try to get the PHY id again.
         */
-       hw->phy.ops.release(hw);
-       ret_val = e1000_set_mdio_slow_mode_hv(hw);
-       if (!ret_val)
-               ret_val = e1000e_get_phy_id(hw);
-       hw->phy.ops.acquire(hw);
+       if (hw->mac.type < e1000_pch_lpt) {
+               hw->phy.ops.release(hw);
+               ret_val = e1000_set_mdio_slow_mode_hv(hw);
+               if (!ret_val)
+                       ret_val = e1000e_get_phy_id(hw);
+               hw->phy.ops.acquire(hw);
+       }
 
        if (ret_val)
                return false;
@@ -842,6 +844,17 @@ s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
                }
        }
 
+       if (hw->phy.type == e1000_phy_82579) {
+               ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
+                                                   &data);
+               if (ret_val)
+                       goto release;
+
+               data &= ~I82579_LPI_100_PLL_SHUT;
+               ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
+                                                    data);
+       }
+
        /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
        ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
        if (ret_val)
@@ -1314,14 +1327,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                        return ret_val;
        }
 
-       /* When connected at 10Mbps half-duplex, 82579 parts are excessively
+       /* When connected at 10Mbps half-duplex, some parts are excessively
         * aggressive resulting in many collisions. To avoid this, increase
         * the IPG and reduce Rx latency in the PHY.
         */
-       if ((hw->mac.type == e1000_pch2lan) && link) {
+       if (((hw->mac.type == e1000_pch2lan) ||
+            (hw->mac.type == e1000_pch_lpt)) && link) {
                u32 reg;
+
                reg = er32(STATUS);
                if (!(reg & (E1000_STATUS_FD | E1000_STATUS_SPEED_MASK))) {
+                       u16 emi_addr;
+
                        reg = er32(TIPG);
                        reg &= ~E1000_TIPG_IPGT_MASK;
                        reg |= 0xFF;
@@ -1332,8 +1349,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                        if (ret_val)
                                return ret_val;
 
-                       ret_val =
-                           e1000_write_emi_reg_locked(hw, I82579_RX_CONFIG, 0);
+                       if (hw->mac.type == e1000_pch2lan)
+                               emi_addr = I82579_RX_CONFIG;
+                       else
+                               emi_addr = I217_RX_CONFIG;
+
+                       ret_val = e1000_write_emi_reg_locked(hw, emi_addr, 0);
 
                        hw->phy.ops.release(hw);
 
@@ -2493,51 +2514,44 @@ release:
  *  e1000_k1_gig_workaround_lv - K1 Si workaround
  *  @hw:   pointer to the HW structure
  *
- *  Workaround to set the K1 beacon duration for 82579 parts
+ *  Workaround to set the K1 beacon duration for 82579 parts in 10Mbps
+ *  Disable K1 in 1000Mbps and 100Mbps
  **/
 static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
 {
        s32 ret_val = 0;
        u16 status_reg = 0;
-       u32 mac_reg;
-       u16 phy_reg;
 
        if (hw->mac.type != e1000_pch2lan)
                return 0;
 
-       /* Set K1 beacon duration based on 1Gbps speed or otherwise */
+       /* Set K1 beacon duration based on 10Mbs speed */
        ret_val = e1e_rphy(hw, HV_M_STATUS, &status_reg);
        if (ret_val)
                return ret_val;
 
        if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
            == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
-               mac_reg = er32(FEXTNVM4);
-               mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
-
-               ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
-               if (ret_val)
-                       return ret_val;
-
-               if (status_reg & HV_M_STATUS_SPEED_1000) {
+               if (status_reg &
+                   (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) {
                        u16 pm_phy_reg;
 
-                       mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
-                       phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
-                       /* LV 1G Packet drop issue wa  */
+                       /* LV 1G/100 Packet drop issue wa  */
                        ret_val = e1e_rphy(hw, HV_PM_CTRL, &pm_phy_reg);
                        if (ret_val)
                                return ret_val;
-                       pm_phy_reg &= ~HV_PM_CTRL_PLL_STOP_IN_K1_GIGA;
+                       pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE;
                        ret_val = e1e_wphy(hw, HV_PM_CTRL, pm_phy_reg);
                        if (ret_val)
                                return ret_val;
                } else {
+                       u32 mac_reg;
+
+                       mac_reg = er32(FEXTNVM4);
+                       mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
                        mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
-                       phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+                       ew32(FEXTNVM4, mac_reg);
                }
-               ew32(FEXTNVM4, mac_reg);
-               ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
        }
 
        return ret_val;
index bead50f9187b527291596da67351339b64482707..5515126c81c199b5e44bd909ac9ea3f336cf4fcd 100644 (file)
 #define I82577_MSE_THRESHOLD   0x0887  /* 82577 Mean Square Error Threshold */
 #define I82579_MSE_LINK_DOWN   0x2411  /* MSE count before dropping link */
 #define I82579_RX_CONFIG               0x3412  /* Receive configuration */
+#define I82579_LPI_PLL_SHUT            0x4412  /* LPI PLL Shut Enable */
 #define I82579_EEE_PCS_STATUS          0x182E  /* IEEE MMD Register 3.1 >> 8 */
 #define I82579_EEE_CAPABILITY          0x0410  /* IEEE MMD Register 3.20 */
 #define I82579_EEE_ADVERTISEMENT       0x040E  /* IEEE MMD Register 7.60 */
 #define I82579_EEE_LP_ABILITY          0x040F  /* IEEE MMD Register 7.61 */
 #define I82579_EEE_100_SUPPORTED       (1 << 1)        /* 100BaseTx EEE */
 #define I82579_EEE_1000_SUPPORTED      (1 << 2)        /* 1000BaseTx EEE */
+#define I82579_LPI_100_PLL_SHUT        (1 << 2)        /* 100M LPI PLL Shut Enabled */
 #define I217_EEE_PCS_STATUS    0x9401  /* IEEE MMD Register 3.1 */
 #define I217_EEE_CAPABILITY    0x8000  /* IEEE MMD Register 3.20 */
 #define I217_EEE_ADVERTISEMENT 0x8001  /* IEEE MMD Register 7.60 */
 #define I217_EEE_LP_ABILITY    0x8002  /* IEEE MMD Register 7.61 */
+#define I217_RX_CONFIG         0xB20C  /* Receive configuration */
 
 #define E1000_EEE_RX_LPI_RCVD  0x0400  /* Tx LP idle received */
 #define E1000_EEE_TX_LPI_RCVD  0x0800  /* Rx LP idle received */
index d50c91e5052808b9485a44538e4b0821b9b30e88..e4207efd13f8651cf75b5ea9ba3a94a437f189a4 100644 (file)
@@ -599,6 +599,7 @@ static void e1000e_update_rdt_wa(struct e1000_ring *rx_ring, unsigned int i)
 
        if (unlikely(!ret_val && (i != readl(rx_ring->tail)))) {
                u32 rctl = er32(RCTL);
+
                ew32(RCTL, rctl & ~E1000_RCTL_EN);
                e_err("ME firmware caused invalid RDT - resetting\n");
                schedule_work(&adapter->reset_task);
@@ -615,6 +616,7 @@ static void e1000e_update_tdt_wa(struct e1000_ring *tx_ring, unsigned int i)
 
        if (unlikely(!ret_val && (i != readl(tx_ring->tail)))) {
                u32 tctl = er32(TCTL);
+
                ew32(TCTL, tctl & ~E1000_TCTL_EN);
                e_err("ME firmware caused invalid TDT - resetting\n");
                schedule_work(&adapter->reset_task);
@@ -1165,7 +1167,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
                dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
                adapter->tx_hwtstamp_skb = NULL;
                adapter->tx_hwtstamp_timeouts++;
-               e_warn("clearing Tx timestamp hang");
+               e_warn("clearing Tx timestamp hang\n");
        } else {
                /* reschedule to check later */
                schedule_work(&adapter->tx_hwtstamp_work);
@@ -1198,6 +1200,7 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
        while ((eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
               (count < tx_ring->count)) {
                bool cleaned = false;
+
                rmb();          /* read buffer_info after eop_desc */
                for (; !cleaned; count++) {
                        tx_desc = E1000_TX_DESC(*tx_ring, i);
@@ -1753,6 +1756,7 @@ static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data)
                    adapter->flags & FLAG_RX_NEEDS_RESTART) {
                        /* disable receives */
                        u32 rctl = er32(RCTL);
+
                        ew32(RCTL, rctl & ~E1000_RCTL_EN);
                        adapter->flags |= FLAG_RESTART_NOW;
                }
@@ -1960,6 +1964,7 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
        /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */
        if (hw->mac.type == e1000_82574) {
                u32 rfctl = er32(RFCTL);
+
                rfctl |= E1000_RFCTL_ACK_DIS;
                ew32(RFCTL, rfctl);
        }
@@ -2204,6 +2209,7 @@ static void e1000_irq_disable(struct e1000_adapter *adapter)
 
        if (adapter->msix_entries) {
                int i;
+
                for (i = 0; i < adapter->num_vectors; i++)
                        synchronize_irq(adapter->msix_entries[i].vector);
        } else {
@@ -2921,6 +2927,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
 
        if (adapter->flags2 & FLAG2_DMA_BURST) {
                u32 txdctl = er32(TXDCTL(0));
+
                txdctl &= ~(E1000_TXDCTL_PTHRESH | E1000_TXDCTL_HTHRESH |
                            E1000_TXDCTL_WTHRESH);
                /* set up some performance related parameters to encourage the
@@ -3239,6 +3246,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 
                if (adapter->flags & FLAG_IS_ICH) {
                        u32 rxdctl = er32(RXDCTL(0));
+
                        ew32(RXDCTL(0), rxdctl | 0x3);
                }
 
@@ -4695,6 +4703,7 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
        /* Correctable ECC Errors */
        if (hw->mac.type == e1000_pch_lpt) {
                u32 pbeccsts = er32(PBECCSTS);
+
                adapter->corr_errors +=
                    pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
                adapter->uncorr_errors +=
@@ -4808,6 +4817,7 @@ static void e1000e_enable_receives(struct e1000_adapter *adapter)
            (adapter->flags & FLAG_RESTART_NOW)) {
                struct e1000_hw *hw = &adapter->hw;
                u32 rctl = er32(RCTL);
+
                ew32(RCTL, rctl | E1000_RCTL_EN);
                adapter->flags &= ~FLAG_RESTART_NOW;
        }
@@ -4930,6 +4940,7 @@ static void e1000_watchdog_task(struct work_struct *work)
                        if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) &&
                            !txb2b) {
                                u32 tarc0;
+
                                tarc0 = er32(TARC(0));
                                tarc0 &= ~SPEED_MODE_BIT;
                                ew32(TARC(0), tarc0);
@@ -5170,7 +5181,7 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
        __be16 protocol;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL)
-               return 0;
+               return false;
 
        if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
                protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
@@ -5215,7 +5226,7 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
                i = 0;
        tx_ring->next_to_use = i;
 
-       return 1;
+       return true;
 }
 
 static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
@@ -5687,7 +5698,7 @@ struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
 static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+       int max_frame = new_mtu + VLAN_HLEN + ETH_HLEN + ETH_FCS_LEN;
 
        /* Jumbo frame support */
        if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) &&
@@ -6209,6 +6220,7 @@ static int __e1000_resume(struct pci_dev *pdev)
                e1e_wphy(&adapter->hw, BM_WUS, ~0);
        } else {
                u32 wus = er32(WUS);
+
                if (wus) {
                        e_info("MAC Wakeup cause - %s\n",
                               wus & E1000_WUS_EX ? "Unicast Packet" :
@@ -6235,6 +6247,7 @@ static int __e1000_resume(struct pci_dev *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int e1000e_pm_thaw(struct device *dev)
 {
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
@@ -6255,7 +6268,6 @@ static int e1000e_pm_thaw(struct device *dev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int e1000e_pm_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -7027,7 +7039,7 @@ static const struct pci_error_handlers e1000_err_handler = {
        .resume = e1000_io_resume,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
+static const struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
@@ -7144,6 +7156,7 @@ static struct pci_driver e1000_driver = {
 static int __init e1000_init_module(void)
 {
        int ret;
+
        pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
                e1000e_driver_version);
        pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n");
index a9a976f04bffe957e22b0852bd8918c6d6f63bd0..b1f212b7baf7e71f0b2a3a160463898019778a00 100644 (file)
@@ -398,6 +398,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
                /* Loop to allow for up to whole page write of eeprom */
                while (widx < words) {
                        u16 word_out = data[widx];
+
                        word_out = (word_out >> 8) | (word_out << 8);
                        e1000_shift_out_eec_bits(hw, word_out, 16);
                        widx++;
index d0ac0f3249c886415d308c4a0cd376feda3d44db..aa1923f7ebdd2e56dd0ebd436feb69164426ad7c 100644 (file)
@@ -436,6 +436,7 @@ void e1000e_check_options(struct e1000_adapter *adapter)
 
                if (num_IntMode > bd) {
                        unsigned int int_mode = IntMode[bd];
+
                        e1000_validate_option(&int_mode, &opt, adapter);
                        adapter->int_mode = int_mode;
                } else {
@@ -457,6 +458,7 @@ void e1000e_check_options(struct e1000_adapter *adapter)
 
                if (num_SmartPowerDownEnable > bd) {
                        unsigned int spd = SmartPowerDownEnable[bd];
+
                        e1000_validate_option(&spd, &opt, adapter);
                        if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && spd)
                                adapter->flags |= FLAG_SMART_POWER_DOWN;
@@ -473,6 +475,7 @@ void e1000e_check_options(struct e1000_adapter *adapter)
 
                if (num_CrcStripping > bd) {
                        unsigned int crc_stripping = CrcStripping[bd];
+
                        e1000_validate_option(&crc_stripping, &opt, adapter);
                        if (crc_stripping == OPTION_ENABLED) {
                                adapter->flags2 |= FLAG2_CRC_STRIPPING;
@@ -495,6 +498,7 @@ void e1000e_check_options(struct e1000_adapter *adapter)
 
                if (num_KumeranLockLoss > bd) {
                        unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
+
                        e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
                        enabled = kmrn_lock_loss;
                }
index 00b3fc98bf309bf3d371a984f0da7245caf07013..b2005e13fb01583a10f58aa37339feb2336191bd 100644 (file)
@@ -2896,6 +2896,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
                    (hw->phy.addr == 2) &&
                    !(MAX_PHY_REG_ADDRESS & reg) && (data & (1 << 11))) {
                        u16 data2 = 0x7EFF;
+
                        ret_val = e1000_access_phy_debug_regs_hv(hw,
                                                                 (1 << 6) | 0x3,
                                                                 &data2, false);
index 3841bccf058c7aa0fe3b2f90e2c70c38e9b6f209..537d2780b408b3cdc9e0fc546d45c04444cc86e2 100644 (file)
@@ -164,6 +164,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
 #define HV_M_STATUS_AUTONEG_COMPLETE   0x1000
 #define HV_M_STATUS_SPEED_MASK         0x0300
 #define HV_M_STATUS_SPEED_1000         0x0200
+#define HV_M_STATUS_SPEED_100          0x0100
 #define HV_M_STATUS_LINK_UP            0x0040
 
 #define IGP01E1000_PHY_PCS_INIT_REG    0x00B4
index beb7b4393a6c26fc46c917a798a6fd7bfaee28ea..a46571c1e9f1879e5b55982774ff40fc824f6efe 100644 (file)
@@ -329,9 +329,7 @@ struct i40e_pf {
        struct ptp_clock *ptp_clock;
        struct ptp_clock_info ptp_caps;
        struct sk_buff *ptp_tx_skb;
-       struct work_struct ptp_tx_work;
        struct hwtstamp_config tstamp_config;
-       unsigned long ptp_tx_start;
        unsigned long last_rx_ptp_check;
        spinlock_t tmreg_lock; /* Used to protect the device time registers. */
        u64 ptp_base_adj;
index ed3902bf249b3e4ceb047ed14762d6ea50b1a4c0..34415d342ece381a97755b051f68945b254303b8 100644 (file)
 
 static void i40e_resume_aq(struct i40e_hw *hw);
 
+/**
+ * i40e_is_nvm_update_op - return true if this is an NVM update operation
+ * @desc: API request descriptor
+ **/
+static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc)
+{
+       return (desc->opcode == i40e_aqc_opc_nvm_erase) ||
+              (desc->opcode == i40e_aqc_opc_nvm_update);
+}
+
 /**
  *  i40e_adminq_init_regs - Initialize AdminQ registers
  *  @hw: pointer to the hardware structure
@@ -585,6 +595,7 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
 
        /* pre-emptive resource lock release */
        i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
+       hw->aq.nvm_busy = false;
 
        ret_code = i40e_aq_set_hmc_resource_profile(hw,
                                                    I40E_HMC_PROFILE_DEFAULT,
@@ -708,6 +719,12 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
                goto asq_send_command_exit;
        }
 
+       if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) {
+               i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n");
+               status = I40E_ERR_NVM;
+               goto asq_send_command_exit;
+       }
+
        details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
        if (cmd_details) {
                *details = *cmd_details;
@@ -835,6 +852,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
                hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
        }
 
+       if (i40e_is_nvm_update_op(desc))
+               hw->aq.nvm_busy = true;
+
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
            (!details->async && !details->postpone)) {
@@ -929,6 +949,9 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
                               e->msg_size);
        }
 
+       if (i40e_is_nvm_update_op(&e->desc))
+               hw->aq.nvm_busy = false;
+
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
         * size
index 993f7685a9111694726c1a9bee44f3653651df72..b1552fbc48a0e6876acf838ab7eadf1e72fe492e 100644 (file)
@@ -90,6 +90,7 @@ struct i40e_adminq_info {
        u16 fw_min_ver;                 /* firmware minor version */
        u16 api_maj_ver;                /* api major version */
        u16 api_min_ver;                /* api minor version */
+       bool nvm_busy;
 
        struct mutex asq_mutex; /* Send queue lock */
        struct mutex arq_mutex; /* Receive queue lock */
index 7b6374a8f8da5cbb5054c431dce910d75de205c5..f2ba4b76ecd31a8b431475ce101353be693c354a 100644 (file)
@@ -182,9 +182,6 @@ enum i40e_admin_queue_opc {
        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,
@@ -207,6 +204,7 @@ enum i40e_admin_queue_opc {
        i40e_aqc_opc_query_switching_comp_bw_config        = 0x041A,
        i40e_aqc_opc_suspend_port_tx                       = 0x041B,
        i40e_aqc_opc_resume_port_tx                        = 0x041C,
+       i40e_aqc_opc_configure_partition_bw                = 0x041D,
 
        /* hmc */
        i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
@@ -1289,27 +1287,6 @@ struct i40e_aqc_add_delete_mirror_rule_completion {
 
 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)
@@ -1499,6 +1476,15 @@ struct i40e_aqc_query_switching_comp_bw_config_resp {
  * (direct 0x041B and 0x041C) uses the generic SEID struct
  */
 
+/* Configure partition BW
+ * (indirect 0x041D)
+ */
+struct i40e_aqc_configure_partition_bw_data {
+       __le16 pf_valid_bits;
+       u8     min_bw[16];      /* guaranteed bandwidth */
+       u8     max_bw[16];      /* bandwidth limit */
+};
+
 /* Get and set the active HMC resource profile and status.
  * (direct 0x0500) and (direct 0x0501)
  */
@@ -1583,11 +1569,8 @@ struct i40e_aq_get_phy_abilities_resp {
 #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_LINK_ENABLED                 0x08
+#define I40E_AQ_PHY_AN_ENABLED                   0x10
 #define I40E_AQ_PHY_FLAG_MODULE_QUAL      0x20
        __le16 eee_capability;
 #define I40E_AQ_EEE_100BASE_TX       0x0002
index 922cdcc45c54b1d36de2a7c0b7faf0ed8cdf1e0d..22eefda3a5303d6a352fa75ce8a7b4d60707fe13 100644 (file)
@@ -975,6 +975,13 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
        hw_link_info->an_info = resp->an_info;
        hw_link_info->ext_info = resp->ext_info;
        hw_link_info->loopback = resp->loopback;
+       hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size);
+       hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK;
+
+       if (resp->config & I40E_AQ_CONFIG_CRC_ENA)
+               hw_link_info->crc_enable = true;
+       else
+               hw_link_info->crc_enable = false;
 
        if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE))
                hw_link_info->lse_enable = true;
@@ -1300,6 +1307,7 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
        struct i40e_aqc_driver_version *cmd =
                (struct i40e_aqc_driver_version *)&desc.params.raw;
        i40e_status status;
+       u16 len;
 
        if (dv == NULL)
                return I40E_ERR_PARAM;
@@ -1311,7 +1319,14 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
        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);
+
+       len = 0;
+       while (len < sizeof(dv->driver_string) &&
+              (dv->driver_string[len] < 0x80) &&
+              dv->driver_string[len])
+               len++;
+       status = i40e_asq_send_command(hw, &desc, dv->driver_string,
+                                      len, cmd_details);
 
        return status;
 }
@@ -2094,8 +2109,8 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
  * @cmd_details: pointer to command details structure or NULL
  **/
 i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
-                               u16 udp_port, u8 header_len,
-                               u8 protocol_index, u8 *filter_index,
+                               u16 udp_port, u8 protocol_index,
+                               u8 *filter_index,
                                struct i40e_asq_cmd_details *cmd_details)
 {
        struct i40e_aq_desc desc;
@@ -2252,6 +2267,35 @@ static i40e_status i40e_aq_tx_sched_cmd(struct i40e_hw *hw, u16 seid,
        return status;
 }
 
+/**
+ * i40e_aq_config_vsi_bw_limit - Configure VSI BW Limit
+ * @hw: pointer to the hw struct
+ * @seid: VSI seid
+ * @credit: BW limit credits (0 = disabled)
+ * @max_credit: Max BW limit credits
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw,
+                               u16 seid, u16 credit, u8 max_credit,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_configure_vsi_bw_limit *cmd =
+               (struct i40e_aqc_configure_vsi_bw_limit *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_configure_vsi_bw_limit);
+
+       cmd->vsi_seid = cpu_to_le16(seid);
+       cmd->credit = cpu_to_le16(credit);
+       cmd->max_credit = max_credit;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
 /**
  * i40e_aq_config_vsi_tc_bw - Config VSI BW Allocation per TC
  * @hw: pointer to the hw struct
index 3c37386fd138fdeb3941170e5789687d90385fd5..1aaec400b28ecb3120b7236a516b13fb59f160b9 100644 (file)
@@ -1744,10 +1744,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, false);
        } else if (strncmp(cmd_buf, "fd-atr on", 9) == 0) {
                i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, true);
-       } else if (strncmp(cmd_buf, "fd-sb off", 9) == 0) {
-               i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_SB_ENABLED, false);
-       } else if (strncmp(cmd_buf, "fd-sb on", 8) == 0) {
-               i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_SB_ENABLED, true);
        } else if (strncmp(cmd_buf, "lldp", 4) == 0) {
                if (strncmp(&cmd_buf[5], "stop", 4) == 0) {
                        int ret;
@@ -1967,8 +1963,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                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, "  fd-atr off\n");
                dev_info(&pf->pdev->dev, "  fd-atr on\n");
-               dev_info(&pf->pdev->dev, "  fd-sb off\n");
-               dev_info(&pf->pdev->dev, "  fd-sb on\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");
index 03d99cbc5c251bcbb0120667ff1d53e304da00a9..0cf47c958081ad6996c61e55a77be7a45f60609d 100644 (file)
@@ -649,7 +649,7 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
                        sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
        }
        rcu_read_lock();
-       for (j = 0; j < vsi->num_queue_pairs; j++, i += 4) {
+       for (j = 0; j < vsi->num_queue_pairs; j++) {
                struct i40e_ring *tx_ring = ACCESS_ONCE(vsi->tx_rings[j]);
                struct i40e_ring *rx_ring;
 
@@ -662,14 +662,16 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
                        data[i] = tx_ring->stats.packets;
                        data[i + 1] = tx_ring->stats.bytes;
                } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
+               i += 2;
 
                /* Rx ring is the 2nd half of the queue pair */
                rx_ring = &tx_ring[1];
                do {
                        start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
-                       data[i + 2] = rx_ring->stats.packets;
-                       data[i + 3] = rx_ring->stats.bytes;
+                       data[i] = rx_ring->stats.packets;
+                       data[i + 1] = rx_ring->stats.bytes;
                } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
+               i += 2;
        }
        rcu_read_unlock();
        if (vsi == pf->vsi[pf->lan_vsi]) {
@@ -1189,6 +1191,12 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
                return -EINVAL;
 
        fsp->flow_type = rule->flow_type;
+       if (fsp->flow_type == IP_USER_FLOW) {
+               fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+               fsp->h_u.usr_ip4_spec.proto = 0;
+               fsp->m_u.usr_ip4_spec.proto = 0;
+       }
+
        fsp->h_u.tcp_ip4_spec.psrc = rule->src_port;
        fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port;
        fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0];
index d5d98fe2691dd6048f7edba7f6b4847076e5316d..5c341aeb5d530de5318bc8847d4c6762c3f8abc1 100644 (file)
@@ -747,6 +747,7 @@ static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = {
        { 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 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, prefena),      1,    201 },
        { 0 }
 };
 
index 341de925a2983181a1cd7d7f18d59996fd128158..eb65fe23c4a70077e31e2546208aaeaecf93224d 100644 (file)
@@ -56,6 +56,7 @@ struct i40e_hmc_obj_rxq {
        u8  tphdata_ena;
        u8  tphhead_ena;
        u8  lrxqthresh;
+       u8  prefena;    /* NOTE: normally must be set to 1 at init */
 };
 
 /* Tx queue context data */
index 861b722c2672e78b0ed0ccbe2cdd2f4428d8f472..e399f9b7077766cd96f5ecfe7483c8f60d7c036c 100644 (file)
@@ -39,7 +39,7 @@ static const char i40e_driver_string[] =
 
 #define DRV_VERSION_MAJOR 0
 #define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 36
+#define DRV_VERSION_BUILD 46
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -2312,6 +2312,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
        rx_ctx.crcstrip = 1;
        rx_ctx.l2tsel = 1;
        rx_ctx.showiv = 1;
+       /* set the prefena field to 1 because the manual says to */
+       rx_ctx.prefena = 1;
 
        /* clear the context in the HMC */
        err = i40e_clear_lan_rx_queue_context(hw, pf_q);
@@ -2897,12 +2899,9 @@ static irqreturn_t i40e_intr(int irq, void *data)
                u32 prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_0);
 
                if (prttsyn_stat & I40E_PRTTSYN_STAT_0_TXTIME_MASK) {
-                       ena_mask &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
+                       icr0 &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
                        i40e_ptp_tx_hwtstamp(pf);
-                       prttsyn_stat &= ~I40E_PRTTSYN_STAT_0_TXTIME_MASK;
                }
-
-               wr32(hw, I40E_PRTTSYN_STAT_0, prttsyn_stat);
        }
 
        /* If a critical error is pending we have no choice but to reset the
@@ -3163,9 +3162,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
                        usleep_range(1000, 2000);
                }
                /* Skip if the queue is already in the requested state */
-               if (enable && (tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
-                       continue;
-               if (!enable && !(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
+               if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
                        continue;
 
                /* turn on/off the queue */
@@ -3181,13 +3178,8 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
                /* 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;
-                       }
+                       if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
+                               break;
 
                        udelay(10);
                }
@@ -3226,15 +3218,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
                        usleep_range(1000, 2000);
                }
 
-               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;
-               }
+               /* Skip if the queue is already in the requested state */
+               if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
+                       continue;
 
                /* turn on/off the queue */
                if (enable)
@@ -3247,13 +3233,8 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
                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;
-                       }
+                       if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
+                               break;
 
                        udelay(10);
                }
@@ -3515,6 +3496,19 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi)
                napi_disable(&vsi->q_vectors[q_idx]->napi);
 }
 
+/**
+ * i40e_vsi_close - Shut down a VSI
+ * @vsi: the vsi to be quelled
+ **/
+static void i40e_vsi_close(struct i40e_vsi *vsi)
+{
+       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_quiesce_vsi - Pause a given VSI
  * @vsi: the VSI being paused
@@ -3528,8 +3522,7 @@ static void i40e_quiesce_vsi(struct i40e_vsi *vsi)
        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_vsi_close(vsi);
        }
 }
 
@@ -3546,7 +3539,7 @@ static void i40e_unquiesce_vsi(struct i40e_vsi *vsi)
        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_vsi_open(vsi);   /* this clears the DOWN bit */
 }
 
 /**
@@ -4031,6 +4024,8 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf)
                                 pf->vsi[v]->seid);
                        /* Will try to configure as many components */
                } else {
+                       /* Re-configure VSI vectors based on updated TC map */
+                       i40e_vsi_map_rings_to_vectors(pf->vsi[v]);
                        if (pf->vsi[v]->netdev)
                                i40e_dcbnl_set_all(pf->vsi[v]);
                }
@@ -4070,6 +4065,9 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
                                       DCB_CAP_DCBX_VER_IEEE;
                        pf->flags |= I40E_FLAG_DCB_ENABLED;
                }
+       } else {
+               dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n",
+                        pf->hw.aq.asq_last_status);
        }
 
 out:
@@ -4271,6 +4269,14 @@ static int i40e_open(struct net_device *netdev)
        if (err)
                return err;
 
+       /* configure global TSO hardware offload settings */
+       wr32(&pf->hw, I40E_GLLAN_TSOMSK_F, be32_to_cpu(TCP_FLAG_PSH |
+                                                      TCP_FLAG_FIN) >> 16);
+       wr32(&pf->hw, I40E_GLLAN_TSOMSK_M, be32_to_cpu(TCP_FLAG_PSH |
+                                                      TCP_FLAG_FIN |
+                                                      TCP_FLAG_CWR) >> 16);
+       wr32(&pf->hw, I40E_GLLAN_TSOMSK_L, be32_to_cpu(TCP_FLAG_CWR) >> 16);
+
 #ifdef CONFIG_I40E_VXLAN
        vxlan_get_rx_port(netdev);
 #endif
@@ -4304,24 +4310,32 @@ int i40e_vsi_open(struct i40e_vsi *vsi)
        if (err)
                goto err_setup_rx;
 
-       if (!vsi->netdev) {
+       if (vsi->netdev) {
+               snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
+                        dev_driver_string(&pf->pdev->dev), vsi->netdev->name);
+               err = i40e_vsi_request_irq(vsi, int_name);
+               if (err)
+                       goto err_setup_rx;
+
+               /* Notify the stack of the actual queue counts. */
+               err = netif_set_real_num_tx_queues(vsi->netdev,
+                                                  vsi->num_queue_pairs);
+               if (err)
+                       goto err_set_queues;
+
+               err = netif_set_real_num_rx_queues(vsi->netdev,
+                                                  vsi->num_queue_pairs);
+               if (err)
+                       goto err_set_queues;
+
+       } else if (vsi->type == I40E_VSI_FDIR) {
+               snprintf(int_name, sizeof(int_name) - 1, "%s-fdir",
+                        dev_driver_string(&pf->pdev->dev));
+               err = i40e_vsi_request_irq(vsi, int_name);
+       } else {
                err = EINVAL;
                goto err_setup_rx;
        }
-       snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
-                dev_driver_string(&pf->pdev->dev), vsi->netdev->name);
-       err = i40e_vsi_request_irq(vsi, int_name);
-       if (err)
-               goto err_setup_rx;
-
-       /* Notify the stack of the actual queue counts. */
-       err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_queue_pairs);
-       if (err)
-               goto err_set_queues;
-
-       err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_queue_pairs);
-       if (err)
-               goto err_set_queues;
 
        err = i40e_up_complete(vsi);
        if (err)
@@ -4378,14 +4392,7 @@ 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);
+       i40e_vsi_close(vsi);
 
        return 0;
 }
@@ -5221,9 +5228,6 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
                }
        } while (err);
 
-       /* increment MSI-X count because current FW skips one */
-       pf->hw.func_caps.num_msix_vectors++;
-
        if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) ||
            (pf->hw.aq.fw_maj_ver < 2)) {
                pf->hw.func_caps.num_msix_vectors++;
@@ -5262,8 +5266,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi);
 static void i40e_fdir_sb_setup(struct i40e_pf *pf)
 {
        struct i40e_vsi *vsi;
-       bool new_vsi = false;
-       int err, i;
+       int i;
 
        if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
                return;
@@ -5283,47 +5286,12 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
                                     pf->vsi[pf->lan_vsi]->seid, 0);
                if (!vsi) {
                        dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n");
-                       goto err_vsi;
+                       pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       return;
                }
-               new_vsi = true;
        }
-       i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_ring);
-
-       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;
 
-       if (new_vsi) {
-               char int_name[IFNAMSIZ + 9];
-               err = i40e_vsi_configure(vsi);
-               if (err)
-                       goto err_setup_rx;
-               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)
-                       goto err_setup_rx;
-               err = i40e_up_complete(vsi);
-               if (err)
-                       goto err_up_complete;
-               clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
-       }
-
-       return;
-
-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);
-err_vsi:
-       pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
-       i40e_vsi_clear(vsi);
+       i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_ring);
 }
 
 /**
@@ -5637,7 +5605,6 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
  **/
 static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf)
 {
-       const int vxlan_hdr_qwords = 4;
        struct i40e_hw *hw = &pf->hw;
        i40e_status ret;
        u8 filter_index;
@@ -5655,7 +5622,6 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf)
                        port = pf->vxlan_ports[i];
                        ret = port ?
                              i40e_aq_add_udp_tunnel(hw, ntohs(port),
-                                                    vxlan_hdr_qwords,
                                                     I40E_AQC_TUNNEL_TYPE_VXLAN,
                                                     &filter_index, NULL)
                              : i40e_aq_del_udp_tunnel(hw, i, NULL);
@@ -6644,6 +6610,96 @@ static void i40e_del_vxlan_port(struct net_device *netdev,
 }
 
 #endif
+#ifdef HAVE_FDB_OPS
+#ifdef USE_CONST_DEV_UC_CHAR
+static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+                           struct net_device *dev,
+                           const unsigned char *addr,
+                           u16 flags)
+#else
+static int i40e_ndo_fdb_add(struct ndmsg *ndm,
+                           struct net_device *dev,
+                           unsigned char *addr,
+                           u16 flags)
+#endif
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
+       struct i40e_pf *pf = np->vsi->back;
+       int err = 0;
+
+       if (!(pf->flags & I40E_FLAG_SRIOV_ENABLED))
+               return -EOPNOTSUPP;
+
+       /* Hardware does not support aging addresses so if a
+        * ndm_state is given only allow permanent addresses
+        */
+       if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+               netdev_info(dev, "FDB only supports static addresses\n");
+               return -EINVAL;
+       }
+
+       if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+               err = dev_uc_add_excl(dev, addr);
+       else if (is_multicast_ether_addr(addr))
+               err = dev_mc_add_excl(dev, addr);
+       else
+               err = -EINVAL;
+
+       /* Only return duplicate errors if NLM_F_EXCL is set */
+       if (err == -EEXIST && !(flags & NLM_F_EXCL))
+               err = 0;
+
+       return err;
+}
+
+#ifndef USE_DEFAULT_FDB_DEL_DUMP
+#ifdef USE_CONST_DEV_UC_CHAR
+static int i40e_ndo_fdb_del(struct ndmsg *ndm,
+                           struct net_device *dev,
+                           const unsigned char *addr)
+#else
+static int i40e_ndo_fdb_del(struct ndmsg *ndm,
+                           struct net_device *dev,
+                           unsigned char *addr)
+#endif
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
+       struct i40e_pf *pf = np->vsi->back;
+       int err = -EOPNOTSUPP;
+
+       if (ndm->ndm_state & NUD_PERMANENT) {
+               netdev_info(dev, "FDB only supports static addresses\n");
+               return -EINVAL;
+       }
+
+       if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
+               if (is_unicast_ether_addr(addr))
+                       err = dev_uc_del(dev, addr);
+               else if (is_multicast_ether_addr(addr))
+                       err = dev_mc_del(dev, addr);
+               else
+                       err = -EINVAL;
+       }
+
+       return err;
+}
+
+static int i40e_ndo_fdb_dump(struct sk_buff *skb,
+                            struct netlink_callback *cb,
+                            struct net_device *dev,
+                            int idx)
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
+       struct i40e_pf *pf = np->vsi->back;
+
+       if (pf->flags & I40E_FLAG_SRIOV_ENABLED)
+               idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
+
+       return idx;
+}
+
+#endif /* USE_DEFAULT_FDB_DEL_DUMP */
+#endif /* HAVE_FDB_OPS */
 static const struct net_device_ops i40e_netdev_ops = {
        .ndo_open               = i40e_open,
        .ndo_stop               = i40e_close,
@@ -6671,6 +6727,13 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_add_vxlan_port     = i40e_add_vxlan_port,
        .ndo_del_vxlan_port     = i40e_del_vxlan_port,
 #endif
+#ifdef HAVE_FDB_OPS
+       .ndo_fdb_add            = i40e_ndo_fdb_add,
+#ifndef USE_DEFAULT_FDB_DEL_DUMP
+       .ndo_fdb_del            = i40e_ndo_fdb_del,
+       .ndo_fdb_dump           = i40e_ndo_fdb_dump,
+#endif
+#endif
 };
 
 /**
@@ -6712,12 +6775,15 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
                           NETIF_F_HW_VLAN_CTAG_FILTER |
                           NETIF_F_IPV6_CSUM           |
                           NETIF_F_TSO                 |
+                          NETIF_F_TSO_ECN             |
                           NETIF_F_TSO6                |
                           NETIF_F_RXCSUM              |
-                          NETIF_F_NTUPLE              |
                           NETIF_F_RXHASH              |
                           0;
 
+       if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+               netdev->features |= NETIF_F_NTUPLE;
+
        /* copy netdev features into list of user selectable features */
        netdev->hw_features |= netdev->features;
 
@@ -6976,11 +7042,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
                                unregister_netdev(vsi->netdev);
                        }
                } 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_close(vsi);
                }
                i40e_vsi_disable_irq(vsi);
        }
@@ -8084,6 +8146,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        u16 link_status;
        int err = 0;
        u32 len;
+       u32 i;
 
        err = pci_enable_device_mem(pdev);
        if (err)
@@ -8237,7 +8300,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err) {
                dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err);
                pf->flags &= ~I40E_FLAG_DCB_ENABLED;
-               goto err_init_dcb;
+               /* Continue without DCB enabled */
        }
 #endif /* CONFIG_I40E_DCB */
 
@@ -8273,6 +8336,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err);
                goto err_vsis;
        }
+       /* if FDIR VSI was set up, start it now */
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+               if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
+                       i40e_vsi_open(pf->vsi[i]);
+                       break;
+               }
+       }
 
        /* 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
@@ -8326,6 +8396,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        dv.minor_version = DRV_VERSION_MINOR;
        dv.build_version = DRV_VERSION_BUILD;
        dv.subbuild_version = 0;
+       strncpy(dv.driver_string, DRV_VERSION, sizeof(dv.driver_string));
        i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
 
        /* since everything's happy, start the service_task timer */
@@ -8367,9 +8438,6 @@ err_vsis:
 err_switch_setup:
        i40e_reset_interrupt_capability(pf);
        del_timer_sync(&pf->service_timer);
-#ifdef CONFIG_I40E_DCB
-err_init_dcb:
-#endif /* CONFIG_I40E_DCB */
 err_mac_addr:
 err_configure_lan_hmc:
        (void)i40e_shutdown_lan_hmc(hw);
index 262bdf11d221e5a30be53a2f57a09e1865b32e79..81299189a47d3e58b61e75dba58869a85e813f2e 100644 (file)
@@ -160,7 +160,7 @@ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
                udelay(5);
        }
        if (ret_code == I40E_ERR_TIMEOUT)
-               hw_dbg(hw, "Done bit in GLNVM_SRCTL not set");
+               hw_dbg(hw, "Done bit in GLNVM_SRCTL not set\n");
        return ret_code;
 }
 
index 9cd57e617959b1622ec57f8c8f6e2146c9c800a6..d351832bf2359a66b97a20b11b5f447ac1e9ce1c 100644 (file)
@@ -157,8 +157,8 @@ i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
 i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
-                               u16 udp_port, u8 header_len,
-                               u8 protocol_index, u8 *filter_index,
+                               u16 udp_port, u8 protocol_index,
+                               u8 *filter_index,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index,
                                struct i40e_asq_cmd_details *cmd_details);
@@ -167,6 +167,9 @@ i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid,
 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_config_vsi_bw_limit(struct i40e_hw *hw,
+                               u16 seid, u16 credit, u8 max_credit,
+                               struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_dcb_updated(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_hmc_resource_profile(struct i40e_hw *hw,
index e33ec6c842b7035acd8189520a4f410c495270f1..1fedc7a1589d11cdffea27218be3adc9434d0fbe 100644 (file)
@@ -216,40 +216,6 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp,
        return 0;
 }
 
-/**
- * i40e_ptp_tx_work
- * @work: pointer to work struct
- *
- * This work function polls the PRTTSYN_STAT_0.TXTIME bit to determine when a
- * Tx timestamp event has occurred, in order to pass the Tx timestamp value up
- * the stack in the skb.
- */
-static void i40e_ptp_tx_work(struct work_struct *work)
-{
-       struct i40e_pf *pf = container_of(work, struct i40e_pf,
-                                         ptp_tx_work);
-       struct i40e_hw *hw = &pf->hw;
-       u32 prttsyn_stat_0;
-
-       if (!pf->ptp_tx_skb)
-               return;
-
-       if (time_is_before_jiffies(pf->ptp_tx_start +
-                                  I40E_PTP_TX_TIMEOUT)) {
-               dev_kfree_skb_any(pf->ptp_tx_skb);
-               pf->ptp_tx_skb = NULL;
-               pf->tx_hwtstamp_timeouts++;
-               dev_warn(&pf->pdev->dev, "clearing Tx timestamp hang");
-               return;
-       }
-
-       prttsyn_stat_0 = rd32(hw, I40E_PRTTSYN_STAT_0);
-       if (prttsyn_stat_0 & I40E_PRTTSYN_STAT_0_TXTIME_MASK)
-               i40e_ptp_tx_hwtstamp(pf);
-       else
-               schedule_work(&pf->ptp_tx_work);
-}
-
 /**
  * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem
  * @ptp: The PTP clock structure
@@ -321,7 +287,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
                pf->last_rx_ptp_check = jiffies;
                pf->rx_hwtstamp_cleared++;
                dev_warn(&vsi->back->pdev->dev,
-                        "%s: clearing Rx timestamp hang",
+                        "%s: clearing Rx timestamp hang\n",
                         __func__);
        }
 }
@@ -608,7 +574,6 @@ void i40e_ptp_init(struct i40e_pf *pf)
                u32 regval;
 
                spin_lock_init(&pf->tmreg_lock);
-               INIT_WORK(&pf->ptp_tx_work, i40e_ptp_tx_work);
 
                dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__,
                         netdev->name);
@@ -647,7 +612,6 @@ void i40e_ptp_stop(struct i40e_pf *pf)
        pf->ptp_tx = false;
        pf->ptp_rx = false;
 
-       cancel_work_sync(&pf->ptp_tx_work);
        if (pf->ptp_tx_skb) {
                dev_kfree_skb_any(pf->ptp_tx_skb);
                pf->ptp_tx_skb = NULL;
index 0f5d96ad281d2400cbe4fbc47e886f9832758e4b..ece7ae99b03a57d1c2ae3f3897ff420f0b4177b9 100644 (file)
@@ -418,7 +418,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
                }
                break;
        default:
-               dev_info(&pf->pdev->dev, "Could not specify spec type %d",
+               dev_info(&pf->pdev->dev, "Could not specify spec type %d\n",
                         input->flow_type);
                ret = -EINVAL;
        }
@@ -478,7 +478,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                                pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
                        }
                } else {
-                       dev_info(&pdev->dev, "FD filter programming error");
+                       dev_info(&pdev->dev, "FD filter programming error\n");
                }
        } else if (error ==
                          (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
@@ -1713,9 +1713,11 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
                                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;
+                       int rc;
+
+                       rc = skb_cow_head(skb, 0);
+                       if (rc < 0)
+                               return rc;
                        vhdr = (struct vlan_ethhdr *)skb->data;
                        vhdr->h_vlan_TCI = htons(tx_flags >>
                                                 I40E_TX_FLAGS_VLAN_SHIFT);
@@ -1743,20 +1745,18 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                    u64 *cd_type_cmd_tso_mss, u32 *cd_tunneling)
 {
        u32 cd_cmd, cd_tso_len, cd_mss;
+       struct ipv6hdr *ipv6h;
        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;
-       }
+       err = skb_cow_head(skb, 0);
+       if (err < 0)
+               return err;
 
        if (protocol == htons(ETH_P_IP)) {
                iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
@@ -1825,9 +1825,6 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
        *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN <<
                                I40E_TXD_CTX_QW1_CMD_SHIFT;
 
-       pf->ptp_tx_start = jiffies;
-       schedule_work(&pf->ptp_tx_work);
-
        return 1;
 }
 
index 71a968fe557f33e12f6feb81d416f4f5a55946fb..c4df8bac2db17df4987d64195af5a61e02c93cd6 100644 (file)
@@ -167,6 +167,9 @@ struct i40e_link_status {
        u8 loopback;
        /* is Link Status Event notification to SW enabled */
        bool lse_enable;
+       u16 max_frame_size;
+       bool crc_enable;
+       u8 pacing;
 };
 
 struct i40e_phy_info {
@@ -409,6 +412,7 @@ struct i40e_driver_version {
        u8 minor_version;
        u8 build_version;
        u8 subbuild_version;
+       u8 driver_string[32];
 };
 
 /* RX Descriptors */
index 02c11a7f7d29e80c533b48894e5ee0b5619a9c91..82e7abf643081c692ac60087e59c0b9f0645cf5c 100644 (file)
 
 /***********************misc routines*****************************/
 
+/**
+ * i40e_vc_disable_vf
+ * @pf: pointer to the pf info
+ * @vf: pointer to the vf info
+ *
+ * Disable the VF through a SW reset
+ **/
+static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u32 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);
+       i40e_flush(hw);
+}
+
 /**
  * i40e_vc_isvalid_vsi_id
  * @vf: pointer to the vf info
@@ -416,6 +434,15 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
        if (ret)
                dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
 
+       /* Set VF bandwidth if specified */
+       if (vf->tx_rate) {
+               ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid,
+                                                 vf->tx_rate / 50, 0, NULL);
+               if (ret)
+                       dev_err(&pf->pdev->dev, "Unable to set tx rate, VF %d, error code %d.\n",
+                               vf->vf_id, ret);
+       }
+
 error_alloc_vsi_res:
        return ret;
 }
@@ -2022,10 +2049,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
        }
 
        /* delete the temporary mac address */
-       i40e_del_filter(vsi, vf->default_lan_addr.addr, 0, true, false);
+       i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id,
+                       true, false);
 
        /* add the new mac address */
-       f = i40e_add_filter(vsi, mac, 0, true, false);
+       f = i40e_add_filter(vsi, mac, vf->port_vlan_id, true, false);
        if (!f) {
                dev_err(&pf->pdev->dev,
                        "Unable to add VF ucast filter\n");
@@ -2088,18 +2116,28 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
                goto error_pvid;
        }
 
-       if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi))
+       if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) {
                dev_err(&pf->pdev->dev,
                        "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n",
                        vf_id);
+               /* Administrator Error - knock the VF offline until he does
+                * the right thing by reconfiguring his network correctly
+                * and then reloading the VF driver.
+                */
+               i40e_vc_disable_vf(pf, vf);
+       }
 
        /* Check for condition where there was already a port VLAN ID
         * filter set and now it is being deleted by setting it to zero.
+        * Additionally check for the condition where there was a port
+        * VLAN but now there is a new and different port VLAN being set.
         * Before deleting all the old VLAN filters we must add new ones
         * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our
         * MAC addresses deleted.
         */
-       if (!(vlan_id || qos) && vsi->info.pvid)
+       if ((!(vlan_id || qos) ||
+           (vlan_id | qos) != le16_to_cpu(vsi->info.pvid)) &&
+           vsi->info.pvid)
                ret = i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY);
 
        if (vsi->info.pvid) {
@@ -2160,7 +2198,61 @@ error_pvid:
  **/
 int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate)
 {
-       return -EOPNOTSUPP;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int speed = 0;
+       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;
+       }
+
+       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;
+       }
+
+       switch (pf->hw.phy.link_info.link_speed) {
+       case I40E_LINK_SPEED_40GB:
+               speed = 40000;
+               break;
+       case I40E_LINK_SPEED_10GB:
+               speed = 10000;
+               break;
+       case I40E_LINK_SPEED_1GB:
+               speed = 1000;
+               break;
+       default:
+               break;
+       }
+
+       if (tx_rate > speed) {
+               dev_err(&pf->pdev->dev, "Invalid tx rate %d specified for vf %d.",
+                       tx_rate, vf->vf_id);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Tx rate credits are in values of 50Mbps, 0 is disabled*/
+       ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid, tx_rate / 50, 0,
+                                         NULL);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Unable to set tx rate, error code %d.\n",
+                       ret);
+               ret = -EIO;
+               goto error;
+       }
+       vf->tx_rate = tx_rate;
+error:
+       return ret;
 }
 
 /**
@@ -2200,10 +2292,17 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
 
        memcpy(&ivi->mac, vf->default_lan_addr.addr, ETH_ALEN);
 
-       ivi->tx_rate = 0;
+       ivi->tx_rate = vf->tx_rate;
        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;
+       if (vf->link_forced == false)
+               ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
+       else if (vf->link_up == true)
+               ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
+       else
+               ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
+
        ret = 0;
 
 error_param:
index 389c47f396d5261d708228f48d8e1bf8ed90e4c5..ba3d1f8414beabdd1b6a0e61a524978f77831c42 100644 (file)
@@ -98,6 +98,7 @@ struct i40e_vf {
 
        unsigned long vf_caps;  /* vf's adv. capabilities */
        unsigned long vf_states;        /* vf's runtime states */
+       unsigned int tx_rate;   /* Tx bandwidth limit in Mbps */
        bool link_forced;
        bool link_up;           /* only valid if vf link is forced */
 };
index 5470ce95936ed483abc547f1ef12b1ef30a34721..c79df257f830d7791580b81ae68028d8ee18d65e 100644 (file)
 #include "i40e_adminq.h"
 #include "i40e_prototype.h"
 
+/**
+ * i40e_is_nvm_update_op - return true if this is an NVM update operation
+ * @desc: API request descriptor
+ **/
+static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc)
+{
+       return (desc->opcode == i40e_aqc_opc_nvm_erase) ||
+              (desc->opcode == i40e_aqc_opc_nvm_update);
+}
+
 /**
  *  i40e_adminq_init_regs - Initialize AdminQ registers
  *  @hw: pointer to the hardware structure
@@ -659,6 +669,12 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
                goto asq_send_command_exit;
        }
 
+       if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) {
+               i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n");
+               status = I40E_ERR_NVM;
+               goto asq_send_command_exit;
+       }
+
        details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
        if (cmd_details) {
                *details = *cmd_details;
@@ -786,6 +802,9 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
                hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
        }
 
+       if (i40e_is_nvm_update_op(desc))
+               hw->aq.nvm_busy = true;
+
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
            (!details->async && !details->postpone)) {
@@ -880,6 +899,9 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
                               e->msg_size);
        }
 
+       if (i40e_is_nvm_update_op(&e->desc))
+               hw->aq.nvm_busy = false;
+
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
         * size
index 8f72c31d95cc85adafac60190967de3f607b4bd6..7d24be528601c990e97307c7b0663cd7b66273cf 100644 (file)
@@ -87,6 +87,7 @@ struct i40e_adminq_info {
        u16 fw_min_ver;                 /* firmware minor version */
        u16 api_maj_ver;                /* api major version */
        u16 api_min_ver;                /* api minor version */
+       bool nvm_busy;
 
        struct mutex asq_mutex; /* Send queue lock */
        struct mutex arq_mutex; /* Receive queue lock */
index 97662b6bd98a3e5badd0660bfcc9c932500ae124..6e617669c326256295e4c283c1781e6681ed2bdd 100644 (file)
@@ -180,9 +180,6 @@ enum i40e_admin_queue_opc {
        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,
@@ -205,6 +202,7 @@ enum i40e_admin_queue_opc {
        i40e_aqc_opc_query_switching_comp_bw_config        = 0x041A,
        i40e_aqc_opc_suspend_port_tx                       = 0x041B,
        i40e_aqc_opc_resume_port_tx                        = 0x041C,
+       i40e_aqc_opc_configure_partition_bw                = 0x041D,
 
        /* hmc */
        i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
@@ -1289,27 +1287,6 @@ struct i40e_aqc_add_delete_mirror_rule_completion {
 
 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)
@@ -1499,6 +1476,15 @@ struct i40e_aqc_query_switching_comp_bw_config_resp {
  * (direct 0x041B and 0x041C) uses the generic SEID struct
  */
 
+/* Configure partition BW
+ * (indirect 0x041D)
+ */
+struct i40e_aqc_configure_partition_bw_data {
+       __le16 pf_valid_bits;
+       u8     min_bw[16];      /* guaranteed bandwidth */
+       u8     max_bw[16];      /* bandwidth limit */
+};
+
 /* Get and set the active HMC resource profile and status.
  * (direct 0x0500) and (direct 0x0501)
  */
@@ -1583,11 +1569,8 @@ struct i40e_aq_get_phy_abilities_resp {
 #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_LINK_ENABLED                 0x08
+#define I40E_AQ_PHY_AN_ENABLED                   0x10
 #define I40E_AQ_PHY_FLAG_MODULE_QUAL      0x20
        __le16 eee_capability;
 #define I40E_AQ_EEE_100BASE_TX       0x0002
index 17e42ca26d0ba045fc51a0efd1ec0b1af0fffd71..775fcb2463d7f4e0ffbef124ed717958a12ffbec 100644 (file)
@@ -53,6 +53,7 @@ struct i40e_hmc_obj_rxq {
        u8  tphdata_ena;
        u8  tphhead_ena;
        u8  lrxqthresh;
+       u8  prefena;    /* NOTE: normally must be set to 1 at init */
 };
 
 /* Tx queue context data */
index 4673b3381eddaa1672edca1f60b85e89d33ab247..51a6dee3c7b1a61fb3feeda80c98313f85b0bef2 100644 (file)
@@ -173,6 +173,9 @@ struct i40e_link_status {
        u8 loopback;
        /* is Link Status Event notification to SW enabled */
        bool lse_enable;
+       u16 max_frame_size;
+       bool crc_enable;
+       u8 pacing;
 };
 
 struct i40e_phy_info {
@@ -415,6 +418,7 @@ struct i40e_driver_version {
        u8 minor_version;
        u8 build_version;
        u8 subbuild_version;
+       u8 driver_string[32];
 };
 
 /* RX Descriptors */
index 8b0db1ce179c5447ce83240098e6c076d6782ed6..a46be016039e37c0adecd3545f903bf5dd7d29d0 100644 (file)
@@ -365,6 +365,316 @@ static int i40evf_set_coalesce(struct net_device *netdev,
        return 0;
 }
 
+/**
+ * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type
+ * @adapter: board private structure
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the flow is supported, else Invalid Input.
+ **/
+static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter,
+                                   struct ethtool_rxnfc *cmd)
+{
+       struct i40e_hw *hw = &adapter->hw;
+       u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
+                  ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32);
+
+       /* We always hash on IP src and dest addresses */
+       cmd->data = RXH_IP_SRC | RXH_IP_DST;
+
+       switch (cmd->flow_type) {
+       case TCP_V4_FLOW:
+               if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP))
+                       cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case UDP_V4_FLOW:
+               if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP))
+                       cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+
+       case SCTP_V4_FLOW:
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case IPV4_FLOW:
+               break;
+
+       case TCP_V6_FLOW:
+               if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP))
+                       cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case UDP_V6_FLOW:
+               if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP))
+                       cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+
+       case SCTP_V6_FLOW:
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case IPV6_FLOW:
+               break;
+       default:
+               cmd->data = 0;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40evf_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 i40evf_get_rxnfc(struct net_device *netdev,
+                           struct ethtool_rxnfc *cmd,
+                           u32 *rule_locs)
+{
+       struct i40evf_adapter *adapter = netdev_priv(netdev);
+       int ret = -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_GRXRINGS:
+               cmd->data = adapter->vsi_res->num_queue_pairs;
+               ret = 0;
+               break;
+       case ETHTOOL_GRXFH:
+               ret = i40evf_get_rss_hash_opts(adapter, cmd);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * i40evf_set_rss_hash_opt - Enable/Disable flow types for RSS hash
+ * @adapter: board private structure
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the flow input set is supported.
+ **/
+static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter,
+                                  struct ethtool_rxnfc *nfc)
+{
+       struct i40e_hw *hw = &adapter->hw;
+
+       u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
+                  ((u64)rd32(hw, I40E_VFQF_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_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_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_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_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_VFQF_HENA(0), (u32)hena);
+       wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
+       i40e_flush(hw);
+
+       return 0;
+}
+
+/**
+ * i40evf_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 i40evf_set_rxnfc(struct net_device *netdev,
+                           struct ethtool_rxnfc *cmd)
+{
+       struct i40evf_adapter *adapter = netdev_priv(netdev);
+       int ret = -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_SRXFH:
+               ret = i40evf_set_rss_hash_opt(adapter, cmd);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * i40evf_get_channels: get the number of channels supported by the device
+ * @netdev: network interface device structure
+ * @ch: channel information structure
+ *
+ * For the purposes of our device, we only use combined channels, i.e. a tx/rx
+ * queue pair. Report one extra channel to match our "other" MSI-X vector.
+ **/
+static void i40evf_get_channels(struct net_device *netdev,
+                               struct ethtool_channels *ch)
+{
+       struct i40evf_adapter *adapter = netdev_priv(netdev);
+
+       /* Report maximum channels */
+       ch->max_combined = adapter->vsi_res->num_queue_pairs;
+
+       ch->max_other = NONQ_VECS;
+       ch->other_count = NONQ_VECS;
+
+       ch->combined_count = adapter->vsi_res->num_queue_pairs;
+}
+
+/**
+ * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size
+ * @netdev: network interface device structure
+ *
+ * Returns the table size.
+ **/
+static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev)
+{
+       return (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4;
+}
+
+/**
+ * i40evf_get_rxfh_indir - get the rx flow hash indirection table
+ * @netdev: network interface device structure
+ * @indir: indirection table
+ *
+ * Reads the indirection table directly from the hardware. Always returns 0.
+ **/
+static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir)
+{
+       struct i40evf_adapter *adapter = netdev_priv(netdev);
+       struct i40e_hw *hw = &adapter->hw;
+       u32 hlut_val;
+       int i, j;
+
+       for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX; i++) {
+               hlut_val = rd32(hw, I40E_VFQF_HLUT(i));
+               indir[j++] = hlut_val & 0xff;
+               indir[j++] = (hlut_val >> 8) & 0xff;
+               indir[j++] = (hlut_val >> 16) & 0xff;
+               indir[j++] = (hlut_val >> 24) & 0xff;
+       }
+       return 0;
+}
+
+/**
+ * i40evf_set_rxfh_indir - set the rx flow hash indirection table
+ * @netdev: network interface device structure
+ * @indir: indirection table
+ *
+ * Returns -EINVAL if the table specifies an inavlid queue id, otherwise
+ * returns 0 after programming the table.
+ **/
+static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir)
+{
+       struct i40evf_adapter *adapter = netdev_priv(netdev);
+       struct i40e_hw *hw = &adapter->hw;
+       u32 hlut_val;
+       int i, j;
+
+       for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX + 1; i++) {
+               hlut_val = indir[j++];
+               hlut_val |= indir[j++] << 8;
+               hlut_val |= indir[j++] << 16;
+               hlut_val |= indir[j++] << 24;
+               wr32(hw, I40E_VFQF_HLUT(i), hlut_val);
+       }
+
+       return 0;
+}
+
 static struct ethtool_ops i40evf_ethtool_ops = {
        .get_settings           = i40evf_get_settings,
        .get_drvinfo            = i40evf_get_drvinfo,
@@ -378,6 +688,12 @@ static struct ethtool_ops i40evf_ethtool_ops = {
        .set_msglevel           = i40evf_set_msglevel,
        .get_coalesce           = i40evf_get_coalesce,
        .set_coalesce           = i40evf_set_coalesce,
+       .get_rxnfc              = i40evf_get_rxnfc,
+       .set_rxnfc              = i40evf_set_rxnfc,
+       .get_rxfh_indir_size    = i40evf_get_rxfh_indir_size,
+       .get_rxfh_indir         = i40evf_get_rxfh_indir,
+       .set_rxfh_indir         = i40evf_set_rxfh_indir,
+       .get_channels           = i40evf_get_channels,
 };
 
 /**
index 2797548fde0dd918051a8f033472749e86d124c9..6edd581dffa74ff7a6290728bd0ac8990db788d1 100644 (file)
 #include "i40e_prototype.h"
 static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter);
 static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter);
+static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
+static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
 static int i40evf_close(struct net_device *netdev);
 
 char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
        "Intel(R) XL710 X710 Virtual Function Network Driver";
 
-#define DRV_VERSION "0.9.16"
+#define DRV_VERSION "0.9.23"
 const char i40evf_driver_version[] = DRV_VERSION;
 static const char i40evf_copyright[] =
        "Copyright (c) 2013 - 2014 Intel Corporation.";
@@ -1309,7 +1311,6 @@ static void i40evf_watchdog_task(struct work_struct *work)
                goto restart_watchdog;
 
        if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
-               dev_info(&adapter->pdev->dev, "Checking for redemption\n");
                if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) {
                        /* A chance for redemption! */
                        dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
@@ -1534,9 +1535,13 @@ static void i40evf_reset_task(struct work_struct *work)
                        rstat_val);
                adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
 
-               if (netif_running(adapter->netdev))
-                       i40evf_close(adapter->netdev);
-
+               if (netif_running(adapter->netdev)) {
+                       set_bit(__I40E_DOWN, &adapter->vsi.state);
+                       i40evf_down(adapter);
+                       i40evf_free_traffic_irqs(adapter);
+                       i40evf_free_all_tx_resources(adapter);
+                       i40evf_free_all_rx_resources(adapter);
+               }
                i40evf_free_misc_irq(adapter);
                i40evf_reset_interrupt_capability(adapter);
                i40evf_free_queues(adapter);
index fa36fe12e77502658cfe864780849d6f00e93c2e..2e36c670d8df48753d98f311d41b7c02eba2f66f 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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
+ */
 
 /* e1000_82575
  * e1000_82576
@@ -73,9 +70,8 @@ static s32  igb_validate_nvm_checksum_82580(struct e1000_hw *hw);
 static s32  igb_update_nvm_checksum_82580(struct e1000_hw *hw);
 static s32 igb_validate_nvm_checksum_i350(struct e1000_hw *hw);
 static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw);
-static const u16 e1000_82580_rxpbs_table[] =
-       { 36, 72, 144, 1, 2, 4, 8, 16,
-         35, 70, 140 };
+static const u16 e1000_82580_rxpbs_table[] = {
+       36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 };
 
 /**
  *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
@@ -526,7 +522,7 @@ out:
 static s32 igb_get_invariants_82575(struct e1000_hw *hw)
 {
        struct e1000_mac_info *mac = &hw->mac;
-       struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575;
+       struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
        s32 ret_val;
        u32 ctrl_ext = 0;
        u32 link_mode = 0;
@@ -1180,8 +1176,8 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
 {
        u32 swfw_sync;
 
-       while (igb_get_hw_semaphore(hw) != 0);
-       /* Empty */
+       while (igb_get_hw_semaphore(hw) != 0)
+               ; /* Empty */
 
        swfw_sync = rd32(E1000_SW_FW_SYNC);
        swfw_sync &= ~mask;
@@ -1216,7 +1212,7 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
        while (timeout) {
                if (rd32(E1000_EEMNGCTL) & mask)
                        break;
-               msleep(1);
+               usleep_range(1000, 2000);
                timeout--;
        }
        if (!timeout)
@@ -1269,7 +1265,7 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw)
 
        if (hw->phy.media_type != e1000_media_type_copper) {
                ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
-                                                            &duplex);
+                                                            &duplex);
                /* Use this flag to determine if link needs to be checked or
                 * not.  If  we have link clear the flag so that we do not
                 * continue to check for link.
@@ -1316,7 +1312,7 @@ void igb_power_up_serdes_link_82575(struct e1000_hw *hw)
 
        /* flush the write to verify completion */
        wrfl();
-       msleep(1);
+       usleep_range(1000, 2000);
 }
 
 /**
@@ -1411,7 +1407,7 @@ void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
 
                /* flush the write to verify completion */
                wrfl();
-               msleep(1);
+               usleep_range(1000, 2000);
        }
 }
 
@@ -1436,9 +1432,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
 
        /* set the completion timeout for interface */
        ret_val = igb_set_pcie_completion_timeout(hw);
-       if (ret_val) {
+       if (ret_val)
                hw_dbg("PCI-E Set completion timeout has failed.\n");
-       }
 
        hw_dbg("Masking off all interrupts\n");
        wr32(E1000_IMC, 0xffffffff);
@@ -1447,7 +1442,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
        wr32(E1000_TCTL, E1000_TCTL_PSP);
        wrfl();
 
-       msleep(10);
+       usleep_range(10000, 20000);
 
        ctrl = rd32(E1000_CTRL);
 
@@ -1676,7 +1671,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
                    hw->mac.type == e1000_82576) {
                        ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &data);
                        if (ret_val) {
-                               printk(KERN_DEBUG "NVM Read Error\n\n");
+                               hw_dbg(KERN_DEBUG "NVM Read Error\n\n");
                                return ret_val;
                        }
 
@@ -1689,7 +1684,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
                 * link either autoneg or be forced to 1000/Full
                 */
                ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
-                           E1000_CTRL_FD | E1000_CTRL_FRCDPX;
+                               E1000_CTRL_FD | E1000_CTRL_FRCDPX;
 
                /* set speed of 1000/Full if speed/duplex is forced */
                reg |= E1000_PCS_LCTL_FSV_1000 | E1000_PCS_LCTL_FDV_FULL;
@@ -1925,7 +1920,7 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
        }
        /* Poll all queues to verify they have shut down */
        for (ms_wait = 0; ms_wait < 10; ms_wait++) {
-               msleep(1);
+               usleep_range(1000, 2000);
                rx_enabled = 0;
                for (i = 0; i < 4; i++)
                        rx_enabled |= rd32(E1000_RXDCTL(i));
@@ -1953,7 +1948,7 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
        wr32(E1000_RCTL, temp_rctl);
        wr32(E1000_RCTL, temp_rctl | E1000_RCTL_EN);
        wrfl();
-       msleep(2);
+       usleep_range(2000, 3000);
 
        /* Enable RX queues that were previously enabled and restore our
         * previous state
@@ -2005,14 +2000,14 @@ static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
         * 16ms to 55ms
         */
        ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
-                                       &pcie_devctl2);
+                                       &pcie_devctl2);
        if (ret_val)
                goto out;
 
        pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
 
        ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
-                                        &pcie_devctl2);
+                                        &pcie_devctl2);
 out:
        /* disable completion timeout resend */
        gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
@@ -2241,7 +2236,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
        wr32(E1000_TCTL, E1000_TCTL_PSP);
        wrfl();
 
-       msleep(10);
+       usleep_range(10000, 11000);
 
        /* Determine whether or not a global dev reset is requested */
        if (global_device_reset &&
@@ -2259,7 +2254,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
 
        /* Add delay to insure DEV_RST has time to complete */
        if (global_device_reset)
-               msleep(5);
+               usleep_range(5000, 6000);
 
        ret_val = igb_get_auto_rd_done(hw);
        if (ret_val) {
@@ -2436,8 +2431,7 @@ static s32 igb_update_nvm_checksum_82580(struct e1000_hw *hw)
 
        ret_val = hw->nvm.ops.read(hw, NVM_COMPATIBILITY_REG_3, 1, &nvm_data);
        if (ret_val) {
-               hw_dbg("NVM Read Error while updating checksum"
-                       " compatibility bit.\n");
+               hw_dbg("NVM Read Error while updating checksum compatibility bit.\n");
                goto out;
        }
 
@@ -2447,8 +2441,7 @@ static s32 igb_update_nvm_checksum_82580(struct e1000_hw *hw)
                ret_val = hw->nvm.ops.write(hw, NVM_COMPATIBILITY_REG_3, 1,
                                        &nvm_data);
                if (ret_val) {
-                       hw_dbg("NVM Write Error while updating checksum"
-                               " compatibility bit.\n");
+                       hw_dbg("NVM Write Error while updating checksum compatibility bit.\n");
                        goto out;
                }
        }
index 09d78be72416563beeda5e3cb72a7338b2aa7060..b407c55738fadf0a333ee7947fedd2c0c31638a1 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_82575_H_
 #define _E1000_82575_H_
@@ -37,9 +34,9 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr,
                       u8 data);
 
 #define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
-                                     (ID_LED_DEF1_DEF2 <<  8) | \
-                                     (ID_LED_DEF1_DEF2 <<  4) | \
-                                     (ID_LED_OFF1_ON2))
+                                    (ID_LED_DEF1_DEF2 <<  8) | \
+                                    (ID_LED_DEF1_DEF2 <<  4) | \
+                                    (ID_LED_OFF1_ON2))
 
 #define E1000_RAR_ENTRIES_82575        16
 #define E1000_RAR_ENTRIES_82576        24
@@ -67,16 +64,16 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr,
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
 
 #define E1000_EICR_TX_QUEUE ( \
-    E1000_EICR_TX_QUEUE0 |    \
-    E1000_EICR_TX_QUEUE1 |    \
-    E1000_EICR_TX_QUEUE2 |    \
-    E1000_EICR_TX_QUEUE3)
+       E1000_EICR_TX_QUEUE0 |    \
+       E1000_EICR_TX_QUEUE1 |    \
+       E1000_EICR_TX_QUEUE2 |    \
+       E1000_EICR_TX_QUEUE3)
 
 #define E1000_EICR_RX_QUEUE ( \
-    E1000_EICR_RX_QUEUE0 |    \
-    E1000_EICR_RX_QUEUE1 |    \
-    E1000_EICR_RX_QUEUE2 |    \
-    E1000_EICR_RX_QUEUE3)
+       E1000_EICR_RX_QUEUE0 |    \
+       E1000_EICR_RX_QUEUE1 |    \
+       E1000_EICR_RX_QUEUE2 |    \
+       E1000_EICR_RX_QUEUE3)
 
 /* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
 #define E1000_IMIREXT_SIZE_BP     0x00001000  /* Packet size bypass */
@@ -92,8 +89,7 @@ union e1000_adv_rx_desc {
                struct {
                        struct {
                                __le16 pkt_info;   /* RSS type, Packet type */
-                               __le16 hdr_info;   /* Split Header,
-                                                   * header buffer length */
+                               __le16 hdr_info;   /* Split Head, buf len */
                        } lo_dword;
                        union {
                                __le32 rss;          /* RSS Hash */
index b05bf925ac721982d8ded6d3aa647d64236890f4..f85be6695e44857b7e149184405a1f06a9d2fab3 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_DEFINES_H_
 #define _E1000_DEFINES_H_
 
 /* Same mask, but for extended and packet split descriptors */
 #define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
-    E1000_RXDEXT_STATERR_CE  |            \
-    E1000_RXDEXT_STATERR_SE  |            \
-    E1000_RXDEXT_STATERR_SEQ |            \
-    E1000_RXDEXT_STATERR_CXE |            \
-    E1000_RXDEXT_STATERR_RXE)
+       E1000_RXDEXT_STATERR_CE  |            \
+       E1000_RXDEXT_STATERR_SE  |            \
+       E1000_RXDEXT_STATERR_SEQ |            \
+       E1000_RXDEXT_STATERR_CXE |            \
+       E1000_RXDEXT_STATERR_RXE)
 
 #define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
 #define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
 #define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
 
 /* DMA Coalescing register fields */
-#define E1000_DMACR_DMACWT_MASK         0x00003FFF /* DMA Coalescing
-                                                       * Watchdog Timer */
-#define E1000_DMACR_DMACTHR_MASK        0x00FF0000 /* DMA Coalescing Receive
-                                                       * Threshold */
+#define E1000_DMACR_DMACWT_MASK         0x00003FFF /* DMA Coal Watchdog Timer */
+#define E1000_DMACR_DMACTHR_MASK        0x00FF0000 /* DMA Coal Rx Threshold */
 #define E1000_DMACR_DMACTHR_SHIFT       16
-#define E1000_DMACR_DMAC_LX_MASK        0x30000000 /* Lx when no PCIe
-                                                       * transactions */
+#define E1000_DMACR_DMAC_LX_MASK        0x30000000 /* Lx when no PCIe trans */
 #define E1000_DMACR_DMAC_LX_SHIFT       28
 #define E1000_DMACR_DMAC_EN             0x80000000 /* Enable DMA Coalescing */
 /* DMA Coalescing BMC-to-OS Watchdog Enable */
 #define E1000_DMACR_DC_BMC2OSW_EN      0x00008000
 
-#define E1000_DMCTXTH_DMCTTHR_MASK      0x00000FFF /* DMA Coalescing Transmit
-                                                       * Threshold */
+#define E1000_DMCTXTH_DMCTTHR_MASK      0x00000FFF /* DMA Coal Tx Threshold */
 
 #define E1000_DMCTLX_TTLX_MASK          0x00000FFF /* Time to LX request */
 
-#define E1000_DMCRTRH_UTRESH_MASK       0x0007FFFF /* Receive Traffic Rate
-                                                       * Threshold */
-#define E1000_DMCRTRH_LRPRCW            0x80000000 /* Rcv packet rate in
-                                                       * current window */
+#define E1000_DMCRTRH_UTRESH_MASK       0x0007FFFF /* Rx Traffic Rate Thresh */
+#define E1000_DMCRTRH_LRPRCW            0x80000000 /* Rx pkt rate curr window */
 
-#define E1000_DMCCNT_CCOUNT_MASK        0x01FFFFFF /* DMA Coal Rcv Traffic
-                                                       * Current Cnt */
+#define E1000_DMCCNT_CCOUNT_MASK        0x01FFFFFF /* DMA Coal Rx Current Cnt */
 
-#define E1000_FCRTC_RTH_COAL_MASK       0x0003FFF0 /* Flow ctrl Rcv Threshold
-                                                       * High val */
+#define E1000_FCRTC_RTH_COAL_MASK       0x0003FFF0 /* FC Rx Thresh High val */
 #define E1000_FCRTC_RTH_COAL_SHIFT      4
 #define E1000_PCIEMISC_LX_DECISION      0x00000080 /* Lx power decision */
 
  *   o LSC    = Link Status Change
  */
 #define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC    |    \
-    E1000_IMS_DOUTSYNC)
+       E1000_IMS_RXT0   |    \
+       E1000_IMS_TXDW   |    \
+       E1000_IMS_RXDMT0 |    \
+       E1000_IMS_RXSEQ  |    \
+       E1000_IMS_LSC    |    \
+       E1000_IMS_DOUTSYNC)
 
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
 #define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
 
 /* DMA Coalescing register fields */
-#define E1000_PCIEMISC_LX_DECISION      0x00000080 /* Lx power decision based
-                                                      on DMA coal */
+#define E1000_PCIEMISC_LX_DECISION      0x00000080 /* Lx power on DMA coal */
 
 /* Tx Rate-Scheduler Config fields */
 #define E1000_RTTBCNRC_RS_ENA          0x80000000
index 10741d170f2ddad46b2fad14d362998bdc19d639..89925e4058498ea1c1ffda3195576d8abcda611e 100644 (file)
@@ -1,28 +1,24 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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,
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_HW_H_
 #define _E1000_HW_H_
@@ -320,15 +316,15 @@ struct e1000_host_mng_command_info {
 #include "e1000_mbx.h"
 
 struct e1000_mac_operations {
-       s32  (*check_for_link)(struct e1000_hw *);
-       s32  (*reset_hw)(struct e1000_hw *);
-       s32  (*init_hw)(struct e1000_hw *);
+       s32 (*check_for_link)(struct e1000_hw *);
+       s32 (*reset_hw)(struct e1000_hw *);
+       s32 (*init_hw)(struct e1000_hw *);
        bool (*check_mng_mode)(struct e1000_hw *);
-       s32  (*setup_physical_interface)(struct e1000_hw *);
+       s32 (*setup_physical_interface)(struct e1000_hw *);
        void (*rar_set)(struct e1000_hw *, u8 *, u32);
-       s32  (*read_mac_addr)(struct e1000_hw *);
-       s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
-       s32  (*acquire_swfw_sync)(struct e1000_hw *, u16);
+       s32 (*read_mac_addr)(struct e1000_hw *);
+       s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
+       s32 (*acquire_swfw_sync)(struct e1000_hw *, u16);
        void (*release_swfw_sync)(struct e1000_hw *, u16);
 #ifdef CONFIG_IGB_HWMON
        s32 (*get_thermal_sensor_data)(struct e1000_hw *);
@@ -338,31 +334,31 @@ struct e1000_mac_operations {
 };
 
 struct e1000_phy_operations {
-       s32  (*acquire)(struct e1000_hw *);
-       s32  (*check_polarity)(struct e1000_hw *);
-       s32  (*check_reset_block)(struct e1000_hw *);
-       s32  (*force_speed_duplex)(struct e1000_hw *);
-       s32  (*get_cfg_done)(struct e1000_hw *hw);
-       s32  (*get_cable_length)(struct e1000_hw *);
-       s32  (*get_phy_info)(struct e1000_hw *);
-       s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
+       s32 (*acquire)(struct e1000_hw *);
+       s32 (*check_polarity)(struct e1000_hw *);
+       s32 (*check_reset_block)(struct e1000_hw *);
+       s32 (*force_speed_duplex)(struct e1000_hw *);
+       s32 (*get_cfg_done)(struct e1000_hw *hw);
+       s32 (*get_cable_length)(struct e1000_hw *);
+       s32 (*get_phy_info)(struct e1000_hw *);
+       s32 (*read_reg)(struct e1000_hw *, u32, u16 *);
        void (*release)(struct e1000_hw *);
-       s32  (*reset)(struct e1000_hw *);
-       s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
-       s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
-       s32  (*write_reg)(struct e1000_hw *, u32, u16);
+       s32 (*reset)(struct e1000_hw *);
+       s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
+       s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
+       s32 (*write_reg)(struct e1000_hw *, u32, u16);
        s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *);
        s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8);
 };
 
 struct e1000_nvm_operations {
-       s32  (*acquire)(struct e1000_hw *);
-       s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
+       s32 (*acquire)(struct e1000_hw *);
+       s32 (*read)(struct e1000_hw *, u16, u16, u16 *);
        void (*release)(struct e1000_hw *);
-       s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
-       s32  (*update)(struct e1000_hw *);
-       s32  (*validate)(struct e1000_hw *);
-       s32  (*valid_led_default)(struct e1000_hw *, u16 *);
+       s32 (*write)(struct e1000_hw *, u16, u16, u16 *);
+       s32 (*update)(struct e1000_hw *);
+       s32 (*validate)(struct e1000_hw *);
+       s32 (*valid_led_default)(struct e1000_hw *, u16 *);
 };
 
 #define E1000_MAX_SENSORS              3
index db963397cc27f42fd15829ec6dc540e19af5f562..2231598fb42d12833c8c4a134e7e888080e02df4 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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
+ */
 
 /* e1000_i210
  * e1000_i211
@@ -365,7 +362,7 @@ static s32 igb_read_invm_word_i210(struct e1000_hw *hw, u8 address, u16 *data)
                        word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
                        if (word_address == address) {
                                *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
-                               hw_dbg("Read INVM Word 0x%02x = %x",
+                               hw_dbg("Read INVM Word 0x%02x = %x\n",
                                          address, *data);
                                status = E1000_SUCCESS;
                                break;
@@ -435,6 +432,7 @@ static s32 igb_read_invm_i210(struct e1000_hw *hw, u16 offset,
                        *data = ID_LED_RESERVED_FFFF;
                        ret_val = E1000_SUCCESS;
                }
+               break;
        case NVM_SUB_DEV_ID:
                *data = hw->subsystem_device_id;
                break;
index 907fe99a9813130e45a3dddf0d5d48c6dfdc492d..9f34976687baedc7eb4d4844678cb2592c10e9d1 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_I210_H_
 #define _E1000_I210_H_
index 5910a932ea7c92cb67223a7c900f7c3b3e36a990..2a88595f956cf4e3089d20a986f0adb9db48681e 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 <linux/if_ether.h>
 #include <linux/delay.h>
@@ -442,7 +439,7 @@ static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
  *  The caller must have a packed mc_addr_list of multicast addresses.
  **/
 void igb_update_mc_addr_list(struct e1000_hw *hw,
-                             u8 *mc_addr_list, u32 mc_addr_count)
+                            u8 *mc_addr_list, u32 mc_addr_count)
 {
        u32 hash_value, hash_bit, hash_reg;
        int i;
@@ -866,8 +863,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
                        goto out;
 
                if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
-                       hw_dbg("Copper PHY and Auto Neg "
-                                "has not completed.\n");
+                       hw_dbg("Copper PHY and Auto Neg has not completed.\n");
                        goto out;
                }
 
@@ -929,11 +925,10 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
                         */
                        if (hw->fc.requested_mode == e1000_fc_full) {
                                hw->fc.current_mode = e1000_fc_full;
-                               hw_dbg("Flow Control = FULL.\r\n");
+                               hw_dbg("Flow Control = FULL.\n");
                        } else {
                                hw->fc.current_mode = e1000_fc_rx_pause;
-                               hw_dbg("Flow Control = "
-                                      "RX PAUSE frames only.\r\n");
+                               hw_dbg("Flow Control = RX PAUSE frames only.\n");
                        }
                }
                /* For receiving PAUSE frames ONLY.
@@ -948,7 +943,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
                          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
                          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
                        hw->fc.current_mode = e1000_fc_tx_pause;
-                       hw_dbg("Flow Control = TX PAUSE frames only.\r\n");
+                       hw_dbg("Flow Control = TX PAUSE frames only.\n");
                }
                /* For transmitting PAUSE frames ONLY.
                 *
@@ -962,7 +957,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
                         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
                         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
                        hw->fc.current_mode = e1000_fc_rx_pause;
-                       hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
+                       hw_dbg("Flow Control = RX PAUSE frames only.\n");
                }
                /* Per the IEEE spec, at this point flow control should be
                 * disabled.  However, we want to consider that we could
@@ -988,10 +983,10 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
                         (hw->fc.requested_mode == e1000_fc_tx_pause) ||
                         (hw->fc.strict_ieee)) {
                        hw->fc.current_mode = e1000_fc_none;
-                       hw_dbg("Flow Control = NONE.\r\n");
+                       hw_dbg("Flow Control = NONE.\n");
                } else {
                        hw->fc.current_mode = e1000_fc_rx_pause;
-                       hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
+                       hw_dbg("Flow Control = RX PAUSE frames only.\n");
                }
 
                /* Now we need to do one last check...  If we auto-
@@ -1266,7 +1261,7 @@ s32 igb_get_auto_rd_done(struct e1000_hw *hw)
        while (i < AUTO_READ_DONE_TIMEOUT) {
                if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD)
                        break;
-               msleep(1);
+               usleep_range(1000, 2000);
                i++;
        }
 
@@ -1299,7 +1294,7 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data)
        }
 
        if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
-               switch(hw->phy.media_type) {
+               switch (hw->phy.media_type) {
                case e1000_media_type_internal_serdes:
                        *data = ID_LED_DEFAULT_82575_SERDES;
                        break;
index 99299ba8ee3a2def53ab2e6fcc8c5c039aca0265..ea24961b0d705e557a6b9bd57772d984ab0927ae 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_MAC_H_
 #define _E1000_MAC_H_
index d5b121771c313716543b16f5a8464866afd4f8e2..162cc49345d09babbd7fab30ec0917215e1a9b64 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 "e1000_mbx.h"
 
index f52f5515e5a8a8aedcc1568f90fdf1b986b2947e..d20af6b2f581698098a972d557a0a93fe19d1d48 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_MBX_H_
 #define _E1000_MBX_H_
index 9abf82919c65535d7b3fd7f7d7200f80fffd1f0a..92bcdbe756b2027a57fba9e1903dce1e8e810cdb 100644 (file)
@@ -1,28 +1,24 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 <linux/if_ether.h>
 #include <linux/delay.h>
@@ -480,6 +476,7 @@ s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
                /* Loop to allow for up to whole page write of eeprom */
                while (widx < words) {
                        u16 word_out = data[widx];
+
                        word_out = (word_out >> 8) | (word_out << 8);
                        igb_shift_out_eec_bits(hw, word_out, 16);
                        widx++;
index 5b101170b17e4bbc9af310c8aacd5e0b891344a0..febc9cdb739125174e143b0159feb0b529cb5ac6 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_NVM_H_
 #define _E1000_NVM_H_
@@ -32,7 +29,7 @@ void igb_release_nvm(struct e1000_hw *hw);
 s32  igb_read_mac_addr(struct e1000_hw *hw);
 s32  igb_read_part_num(struct e1000_hw *hw, u32 *part_num);
 s32  igb_read_part_string(struct e1000_hw *hw, u8 *part_num,
-                          u32 part_num_size);
+                         u32 part_num_size);
 s32  igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
 s32  igb_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
 s32  igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
index 4009bbab7407d21945e7c1af20df5deedba564a3..424f16c43759b1b787e44cb4d7c8194ec327c825 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 <linux/if_ether.h>
 #include <linux/delay.h>
@@ -924,8 +921,7 @@ static s32 igb_copper_link_autoneg(struct e1000_hw *hw)
        if (phy->autoneg_wait_to_complete) {
                ret_val = igb_wait_autoneg(hw);
                if (ret_val) {
-                       hw_dbg("Error while waiting for "
-                              "autoneg to complete\n");
+                       hw_dbg("Error while waiting for autoneg to complete\n");
                        goto out;
                }
        }
@@ -2244,7 +2240,7 @@ void igb_power_down_phy_copper(struct e1000_hw *hw)
                hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg);
        }
        hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
-       msleep(1);
+       usleep_range(1000, 2000);
 }
 
 /**
index 4c2c36c46a7398d217c1418b3966b4cde5813812..fe921e29dda8f96a201b82d70152466c15a1da26 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_PHY_H_
 #define _E1000_PHY_H_
index bdb246e848e13bb5e569f279336dbb5a2c5bfe86..833bbb948d970975cd3a42cfa759f7604f8f04a3 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 _E1000_REGS_H_
 #define _E1000_REGS_H_
 #define E1000_RA2      0x054E0  /* 2nd half of Rx address array - RW Array */
 #define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
 #define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
-                                       (0x054E0 + ((_i - 16) * 8)))
+                                       (0x054E0 + ((_i - 16) * 8)))
 #define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
-                                       (0x054E4 + ((_i - 16) * 8)))
+                                       (0x054E4 + ((_i - 16) * 8)))
 #define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
 #define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
 #define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
 #define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
 #define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
 #define E1000_DVMOLR(_n)       (0x0C038 + (64 * (_n)))
-#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
-                                                       * Filter - RW */
+#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN VM Filter */
 #define E1000_VMVIR(_n)        (0x03700 + (4 * (_n)))
 
 struct e1000_hw;
index 27130065d92a70679292ef316aaadf848772944c..06102d1f7c0362208118ec99dcaba0e6db89eeb3 100644 (file)
@@ -1,29 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
-
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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
+ */
 
 /* Linux PRO/1000 Ethernet Driver main header file */
 
@@ -198,6 +194,7 @@ struct igb_tx_buffer {
        unsigned int bytecount;
        u16 gso_segs;
        __be16 protocol;
+
        DEFINE_DMA_UNMAP_ADDR(dma);
        DEFINE_DMA_UNMAP_LEN(len);
        u32 tx_flags;
index e5570acbeea84509855a98383ab128876e7447c9..333a2b0bbada8c800cc83bad309ac1beeb38ba12 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 igb */
 
@@ -286,7 +283,7 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
        }
 
        while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
-               msleep(1);
+               usleep_range(1000, 2000);
 
        if (ecmd->autoneg == AUTONEG_ENABLE) {
                hw->mac.autoneg = 1;
@@ -399,7 +396,7 @@ static int igb_set_pauseparam(struct net_device *netdev,
        adapter->fc_autoneg = pause->autoneg;
 
        while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
-               msleep(1);
+               usleep_range(1000, 2000);
 
        if (adapter->fc_autoneg == AUTONEG_ENABLE) {
                hw->fc.requested_mode = e1000_fc_default;
@@ -886,7 +883,7 @@ static int igb_set_ringparam(struct net_device *netdev,
        }
 
        while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
-               msleep(1);
+               usleep_range(1000, 2000);
 
        if (!netif_running(adapter->netdev)) {
                for (i = 0; i < adapter->num_tx_queues; i++)
@@ -1060,8 +1057,8 @@ static struct igb_reg_test reg_test_i350[] = {
        { E1000_TDT(0),    0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_TDT(4),    0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
-       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
-       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
        { E1000_TCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
        { E1000_RA,        0, 16, TABLE64_TEST_LO,
                                                0xFFFFFFFF, 0xFFFFFFFF },
@@ -1103,8 +1100,8 @@ static struct igb_reg_test reg_test_82580[] = {
        { E1000_TDT(0),    0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_TDT(4),    0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
-       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
-       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
        { E1000_TCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
        { E1000_RA,        0, 16, TABLE64_TEST_LO,
                                                0xFFFFFFFF, 0xFFFFFFFF },
@@ -1132,8 +1129,10 @@ static struct igb_reg_test reg_test_82576[] = {
        { E1000_RDBAH(4),  0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_RDLEN(4),  0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
        /* Enable all RX queues before testing. */
-       { E1000_RXDCTL(0), 0x100, 4,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
-       { E1000_RXDCTL(4), 0x40, 12,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
+       { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0,
+         E1000_RXDCTL_QUEUE_ENABLE },
+       { E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0,
+         E1000_RXDCTL_QUEUE_ENABLE },
        /* RDH is read-only for 82576, only test RDT. */
        { E1000_RDT(0),    0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_RDT(4),    0x40, 12,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
@@ -1149,14 +1148,14 @@ static struct igb_reg_test reg_test_82576[] = {
        { E1000_TDBAH(4),  0x40, 12,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_TDLEN(4),  0x40, 12,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
        { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
-       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
-       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
        { E1000_TCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
        { E1000_RA,        0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_RA,        0, 16, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF },
        { E1000_RA2,       0, 8, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_RA2,       0, 8, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF },
-       { E1000_MTA,       0, 128,TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_MTA,       0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
        { 0, 0, 0, 0 }
 };
 
@@ -1170,7 +1169,8 @@ static struct igb_reg_test reg_test_82575[] = {
        { E1000_RDBAH(0),  0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_RDLEN(0),  0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
        /* Enable all four RX queues before testing. */
-       { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
+       { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0,
+         E1000_RXDCTL_QUEUE_ENABLE },
        /* RDH is read-only for 82575, only test RDT. */
        { E1000_RDT(0),    0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 },
@@ -1196,8 +1196,8 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 pat, val;
-       static const u32 _test[] =
-               {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+       static const u32 _test[] = {
+               0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
        for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {
                wr32(reg, (_test[pat] & write));
                val = rd32(reg) & mask;
@@ -1206,11 +1206,11 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
                                "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
                                reg, val, (_test[pat] & write & mask));
                        *data = reg;
-                       return 1;
+                       return true;
                }
        }
 
-       return 0;
+       return false;
 }
 
 static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
@@ -1218,17 +1218,18 @@ static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 val;
+
        wr32(reg, write & mask);
        val = rd32(reg);
        if ((write & mask) != (val & mask)) {
                dev_err(&adapter->pdev->dev,
-                       "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", reg,
-                       (val & mask), (write & mask));
+                       "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
+                       reg, (val & mask), (write & mask));
                *data = reg;
-               return 1;
+               return true;
        }
 
-       return 0;
+       return false;
 }
 
 #define REG_PATTERN_TEST(reg, mask, write) \
@@ -1387,14 +1388,14 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
        /* Hook up test interrupt handler just for this test */
        if (adapter->flags & IGB_FLAG_HAS_MSIX) {
                if (request_irq(adapter->msix_entries[0].vector,
-                               igb_test_intr, 0, netdev->name, adapter)) {
+                               igb_test_intr, 0, netdev->name, adapter)) {
                        *data = 1;
                        return -1;
                }
        } else if (adapter->flags & IGB_FLAG_HAS_MSI) {
                shared_int = false;
                if (request_irq(irq,
-                               igb_test_intr, 0, netdev->name, adapter)) {
+                               igb_test_intr, 0, netdev->name, adapter)) {
                        *data = 1;
                        return -1;
                }
@@ -1412,7 +1413,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
        /* Disable all the interrupts */
        wr32(E1000_IMC, ~0);
        wrfl();
-       msleep(10);
+       usleep_range(10000, 11000);
 
        /* Define all writable bits for ICS */
        switch (hw->mac.type) {
@@ -1459,7 +1460,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
                        wr32(E1000_IMC, mask);
                        wr32(E1000_ICS, mask);
                        wrfl();
-                       msleep(10);
+                       usleep_range(10000, 11000);
 
                        if (adapter->test_icr & mask) {
                                *data = 3;
@@ -1481,7 +1482,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
                wr32(E1000_IMS, mask);
                wr32(E1000_ICS, mask);
                wrfl();
-               msleep(10);
+               usleep_range(10000, 11000);
 
                if (!(adapter->test_icr & mask)) {
                        *data = 4;
@@ -1503,7 +1504,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
                        wr32(E1000_IMC, ~mask);
                        wr32(E1000_ICS, ~mask);
                        wrfl();
-                       msleep(10);
+                       usleep_range(10000, 11000);
 
                        if (adapter->test_icr & mask) {
                                *data = 5;
@@ -1515,7 +1516,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
        /* Disable all the interrupts */
        wr32(E1000_IMC, ~0);
        wrfl();
-       msleep(10);
+       usleep_range(10000, 11000);
 
        /* Unhook test interrupt handler */
        if (adapter->flags & IGB_FLAG_HAS_MSIX)
@@ -1949,6 +1950,7 @@ static int igb_link_test(struct igb_adapter *adapter, u64 *data)
        *data = 0;
        if (hw->phy.media_type == e1000_media_type_internal_serdes) {
                int i = 0;
+
                hw->mac.serdes_has_link = false;
 
                /* On some blade server designs, link establishment
@@ -2413,9 +2415,11 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter,
        switch (cmd->flow_type) {
        case TCP_V4_FLOW:
                cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               /* Fall through */
        case UDP_V4_FLOW:
                if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)
                        cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               /* Fall through */
        case SCTP_V4_FLOW:
        case AH_ESP_V4_FLOW:
        case AH_V4_FLOW:
@@ -2425,9 +2429,11 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter,
                break;
        case TCP_V6_FLOW:
                cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               /* Fall through */
        case UDP_V6_FLOW:
                if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)
                        cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               /* Fall through */
        case SCTP_V6_FLOW:
        case AH_ESP_V6_FLOW:
        case AH_V6_FLOW:
index 8333f67acf96b3a6e83746c1cedd1f0eff7636ec..44b6a68f1af727136271132014b1efa412ee7e32 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 "igb.h"
 #include "e1000_82575.h"
index fb98d4602f9d4fd130b660de0265bee786fec7a6..bfcda8a455f46cc99058faf1a8bd0c339e7300e2 100644 (file)
@@ -1,28 +1,25 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
-
-  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
-
-*******************************************************************************/
+/* Intel(R) Gigabit Ethernet Linux driver
+ * Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
+ *
+ * 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
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -75,7 +72,7 @@ static const struct e1000_info *igb_info_tbl[] = {
        [board_82575] = &e1000_82575_info,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
+static const struct pci_device_id igb_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) },
@@ -117,7 +114,6 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
 
 MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
 
-void igb_reset(struct igb_adapter *);
 static int igb_setup_all_tx_resources(struct igb_adapter *);
 static int igb_setup_all_rx_resources(struct igb_adapter *);
 static void igb_free_all_tx_resources(struct igb_adapter *);
@@ -141,7 +137,7 @@ static void igb_watchdog(unsigned long);
 static void igb_watchdog_task(struct work_struct *);
 static netdev_tx_t igb_xmit_frame(struct sk_buff *skb, struct net_device *);
 static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *dev,
-                                                struct rtnl_link_stats64 *stats);
+                                         struct rtnl_link_stats64 *stats);
 static int igb_change_mtu(struct net_device *, int);
 static int igb_set_mac(struct net_device *, void *);
 static void igb_set_uta(struct igb_adapter *adapter);
@@ -159,7 +155,8 @@ static bool igb_clean_rx_irq(struct igb_q_vector *, int);
 static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
 static void igb_tx_timeout(struct net_device *);
 static void igb_reset_task(struct work_struct *);
-static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features);
+static void igb_vlan_mode(struct net_device *netdev,
+                         netdev_features_t features);
 static int igb_vlan_rx_add_vid(struct net_device *, __be16, u16);
 static int igb_vlan_rx_kill_vid(struct net_device *, __be16, u16);
 static void igb_restore_vlan(struct igb_adapter *);
@@ -215,10 +212,9 @@ static struct notifier_block dca_notifier = {
 static void igb_netpoll(struct net_device *);
 #endif
 #ifdef CONFIG_PCI_IOV
-static unsigned int max_vfs = 0;
+static unsigned int max_vfs;
 module_param(max_vfs, uint, 0);
-MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate "
-                 "per physical function");
+MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate per physical function");
 #endif /* CONFIG_PCI_IOV */
 
 static pci_ers_result_t igb_io_error_detected(struct pci_dev *,
@@ -384,8 +380,7 @@ static void igb_dump(struct igb_adapter *adapter)
        /* Print netdevice Info */
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
-               pr_info("Device Name     state            trans_start      "
-                       "last_rx\n");
+               pr_info("Device Name     state            trans_start      last_rx\n");
                pr_info("%-15s %016lX %016lX %016lX\n", netdev->name,
                        netdev->state, netdev->trans_start, netdev->last_rx);
        }
@@ -438,9 +433,7 @@ static void igb_dump(struct igb_adapter *adapter)
                pr_info("------------------------------------\n");
                pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
                pr_info("------------------------------------\n");
-               pr_info("T [desc]     [address 63:0  ] [PlPOCIStDDM Ln] "
-                       "[bi->dma       ] leng  ntw timestamp        "
-                       "bi->skb\n");
+               pr_info("T [desc]     [address 63:0  ] [PlPOCIStDDM Ln] [bi->dma       ] leng  ntw timestamp        bi->skb\n");
 
                for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
                        const char *next_desc;
@@ -458,9 +451,8 @@ static void igb_dump(struct igb_adapter *adapter)
                        else
                                next_desc = "";
 
-                       pr_info("T [0x%03X]    %016llX %016llX %016llX"
-                               " %04X  %p %016llX %p%s\n", i,
-                               le64_to_cpu(u0->a),
+                       pr_info("T [0x%03X]    %016llX %016llX %016llX %04X  %p %016llX %p%s\n",
+                               i, le64_to_cpu(u0->a),
                                le64_to_cpu(u0->b),
                                (u64)dma_unmap_addr(buffer_info, dma),
                                dma_unmap_len(buffer_info, len),
@@ -519,10 +511,8 @@ rx_ring_summary:
                pr_info("------------------------------------\n");
                pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
                pr_info("------------------------------------\n");
-               pr_info("R  [desc]      [ PktBuf     A0] [  HeadBuf   DD] "
-                       "[bi->dma       ] [bi->skb] <-- Adv Rx Read format\n");
-               pr_info("RWB[desc]      [PcsmIpSHl PtRs] [vl er S cks ln] -----"
-                       "----------- [bi->skb] <-- Adv Rx Write-Back format\n");
+               pr_info("R  [desc]      [ PktBuf     A0] [  HeadBuf   DD] [bi->dma       ] [bi->skb] <-- Adv Rx Read format\n");
+               pr_info("RWB[desc]      [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n");
 
                for (i = 0; i < rx_ring->count; i++) {
                        const char *next_desc;
@@ -584,7 +574,7 @@ static int igb_get_i2c_data(void *data)
        struct e1000_hw *hw = &adapter->hw;
        s32 i2cctl = rd32(E1000_I2CPARAMS);
 
-       return ((i2cctl & E1000_I2C_DATA_IN) != 0);
+       return !!(i2cctl & E1000_I2C_DATA_IN);
 }
 
 /**
@@ -648,7 +638,7 @@ static int igb_get_i2c_clk(void *data)
        struct e1000_hw *hw = &adapter->hw;
        s32 i2cctl = rd32(E1000_I2CPARAMS);
 
-       return ((i2cctl & E1000_I2C_CLK_IN) != 0);
+       return !!(i2cctl & E1000_I2C_CLK_IN);
 }
 
 static const struct i2c_algo_bit_data igb_i2c_algo = {
@@ -681,9 +671,9 @@ struct net_device *igb_get_hw_dev(struct e1000_hw *hw)
 static int __init igb_init_module(void)
 {
        int ret;
+
        pr_info("%s - version %s\n",
               igb_driver_string, igb_driver_version);
-
        pr_info("%s\n", igb_copyright);
 
 #ifdef CONFIG_IGB_DCA
@@ -736,12 +726,14 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
                                adapter->rx_ring[i]->reg_idx = rbase_offset +
                                                               Q_IDX_82576(i);
                }
+               /* Fall through */
        case e1000_82575:
        case e1000_82580:
        case e1000_i350:
        case e1000_i354:
        case e1000_i210:
        case e1000_i211:
+               /* Fall through */
        default:
                for (; i < adapter->num_rx_queues; i++)
                        adapter->rx_ring[i]->reg_idx = rbase_offset + i;
@@ -1292,8 +1284,7 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
                if (adapter->hw.mac.type >= e1000_82576)
                        set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags);
 
-               /*
-                * On i350, i354, i210, and i211, loopback VLAN packets
+               /* On i350, i354, i210, and i211, loopback VLAN packets
                 * have the tag byte-swapped.
                 */
                if (adapter->hw.mac.type >= e1000_i350)
@@ -1345,6 +1336,7 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter)
        for (; v_idx < q_vectors; v_idx++) {
                int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx);
                int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx);
+
                err = igb_alloc_q_vector(adapter, q_vectors, v_idx,
                                         tqpv, txr_idx, rqpv, rxr_idx);
 
@@ -1484,6 +1476,7 @@ static void igb_irq_disable(struct igb_adapter *adapter)
         */
        if (adapter->flags & IGB_FLAG_HAS_MSIX) {
                u32 regval = rd32(E1000_EIAM);
+
                wr32(E1000_EIAM, regval & ~adapter->eims_enable_mask);
                wr32(E1000_EIMC, adapter->eims_enable_mask);
                regval = rd32(E1000_EIAC);
@@ -1495,6 +1488,7 @@ static void igb_irq_disable(struct igb_adapter *adapter)
        wrfl();
        if (adapter->flags & IGB_FLAG_HAS_MSIX) {
                int i;
+
                for (i = 0; i < adapter->num_q_vectors; i++)
                        synchronize_irq(adapter->msix_entries[i].vector);
        } else {
@@ -1513,6 +1507,7 @@ static void igb_irq_enable(struct igb_adapter *adapter)
        if (adapter->flags & IGB_FLAG_HAS_MSIX) {
                u32 ims = E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_DRSTA;
                u32 regval = rd32(E1000_EIAC);
+
                wr32(E1000_EIAC, regval | adapter->eims_enable_mask);
                regval = rd32(E1000_EIAM);
                wr32(E1000_EIAM, regval | adapter->eims_enable_mask);
@@ -1745,6 +1740,7 @@ int igb_up(struct igb_adapter *adapter)
        /* notify VFs that reset has been completed */
        if (adapter->vfs_allocated_count) {
                u32 reg_data = rd32(E1000_CTRL_EXT);
+
                reg_data |= E1000_CTRL_EXT_PFRSTD;
                wr32(E1000_CTRL_EXT, reg_data);
        }
@@ -1787,7 +1783,7 @@ void igb_down(struct igb_adapter *adapter)
        wr32(E1000_TCTL, tctl);
        /* flush both disables and wait for them to finish */
        wrfl();
-       msleep(10);
+       usleep_range(10000, 11000);
 
        igb_irq_disable(adapter);
 
@@ -1827,7 +1823,7 @@ void igb_reinit_locked(struct igb_adapter *adapter)
 {
        WARN_ON(in_interrupt());
        while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
-               msleep(1);
+               usleep_range(1000, 2000);
        igb_down(adapter);
        igb_up(adapter);
        clear_bit(__IGB_RESETTING, &adapter->state);
@@ -1960,6 +1956,7 @@ void igb_reset(struct igb_adapter *adapter)
        /* disable receive for all VFs and wait one second */
        if (adapter->vfs_allocated_count) {
                int i;
+
                for (i = 0 ; i < adapter->vfs_allocated_count; i++)
                        adapter->vf_data[i].flags &= IGB_VF_FLAG_PF_SET_MAC;
 
@@ -2529,7 +2526,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* let the f/w know that the h/w is now under the control of the
-        * driver. */
+        * driver.
+        */
        igb_get_hw_control(adapter);
 
        strcpy(netdev->name, "eth%d");
@@ -3077,6 +3075,7 @@ static int __igb_open(struct net_device *netdev, bool resuming)
        /* notify VFs that reset has been completed */
        if (adapter->vfs_allocated_count) {
                u32 reg_data = rd32(E1000_CTRL_EXT);
+
                reg_data |= E1000_CTRL_EXT_PFRSTD;
                wr32(E1000_CTRL_EXT, reg_data);
        }
@@ -3248,7 +3247,7 @@ void igb_setup_tctl(struct igb_adapter *adapter)
  *  Configure a transmit ring after a reset.
  **/
 void igb_configure_tx_ring(struct igb_adapter *adapter,
-                           struct igb_ring *ring)
+                          struct igb_ring *ring)
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 txdctl = 0;
@@ -3389,7 +3388,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
 
        if (adapter->rss_indir_tbl_init != num_rx_queues) {
                for (j = 0; j < IGB_RETA_SIZE; j++)
-                       adapter->rss_indir_tbl[j] = (j * num_rx_queues) / IGB_RETA_SIZE;
+                       adapter->rss_indir_tbl[j] =
+                       (j * num_rx_queues) / IGB_RETA_SIZE;
                adapter->rss_indir_tbl_init = num_rx_queues;
        }
        igb_write_rss_indir_tbl(adapter);
@@ -3430,6 +3430,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
                if (hw->mac.type > e1000_82575) {
                        /* Set the default pool for the PF's first queue */
                        u32 vtctl = rd32(E1000_VT_CTL);
+
                        vtctl &= ~(E1000_VT_CTL_DEFAULT_POOL_MASK |
                                   E1000_VT_CTL_DISABLE_DEF_POOL);
                        vtctl |= adapter->vfs_allocated_count <<
@@ -3511,7 +3512,7 @@ void igb_setup_rctl(struct igb_adapter *adapter)
 }
 
 static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
-                                   int vfn)
+                                  int vfn)
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 vmolr;
@@ -4058,7 +4059,8 @@ static void igb_check_wvbr(struct igb_adapter *adapter)
        switch (hw->mac.type) {
        case e1000_82576:
        case e1000_i350:
-               if (!(wvbr = rd32(E1000_WVBR)))
+               wvbr = rd32(E1000_WVBR);
+               if (!wvbr)
                        return;
                break;
        default:
@@ -4077,7 +4079,7 @@ static void igb_spoof_check(struct igb_adapter *adapter)
        if (!adapter->wvbr)
                return;
 
-       for(j = 0; j < adapter->vfs_allocated_count; j++) {
+       for (j = 0; j < adapter->vfs_allocated_count; j++) {
                if (adapter->wvbr & (1 << j) ||
                    adapter->wvbr & (1 << (j + IGB_STAGGERED_QUEUE_OFFSET))) {
                        dev_warn(&adapter->pdev->dev,
@@ -4209,14 +4211,15 @@ static void igb_watchdog_task(struct work_struct *work)
 
                if (!netif_carrier_ok(netdev)) {
                        u32 ctrl;
+
                        hw->mac.ops.get_speed_and_duplex(hw,
                                                         &adapter->link_speed,
                                                         &adapter->link_duplex);
 
                        ctrl = rd32(E1000_CTRL);
                        /* Links status message must follow this format */
-                       printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s "
-                              "Duplex, Flow Control: %s\n",
+                       netdev_info(netdev,
+                              "igb: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
                               netdev->name,
                               adapter->link_speed,
                               adapter->link_duplex == FULL_DUPLEX ?
@@ -4242,11 +4245,8 @@ static void igb_watchdog_task(struct work_struct *work)
 
                        /* check for thermal sensor event */
                        if (igb_thermal_sensor_event(hw,
-                           E1000_THSTAT_LINK_THROTTLE)) {
-                               netdev_info(netdev, "The network adapter link "
-                                           "speed was downshifted because it "
-                                           "overheated\n");
-                       }
+                           E1000_THSTAT_LINK_THROTTLE))
+                               netdev_info(netdev, "The network adapter link speed was downshifted because it overheated\n");
 
                        /* adjust timeout factor according to speed/duplex */
                        adapter->tx_timeout_factor = 1;
@@ -4277,12 +4277,11 @@ static void igb_watchdog_task(struct work_struct *work)
                        /* check for thermal sensor event */
                        if (igb_thermal_sensor_event(hw,
                            E1000_THSTAT_PWR_DOWN)) {
-                               netdev_err(netdev, "The network adapter was "
-                                          "stopped because it overheated\n");
+                               netdev_err(netdev, "The network adapter was stopped because it overheated\n");
                        }
 
                        /* Links status message must follow this format */
-                       printk(KERN_INFO "igb: %s NIC Link is Down\n",
+                       netdev_info(netdev, "igb: %s NIC Link is Down\n",
                               netdev->name);
                        netif_carrier_off(netdev);
 
@@ -4344,6 +4343,7 @@ static void igb_watchdog_task(struct work_struct *work)
        /* Cause software interrupt to ensure Rx ring is cleaned */
        if (adapter->flags & IGB_FLAG_HAS_MSIX) {
                u32 eics = 0;
+
                for (i = 0; i < adapter->num_q_vectors; i++)
                        eics |= adapter->q_vector[i]->eims_value;
                wr32(E1000_EICS, eics);
@@ -4483,13 +4483,12 @@ static void igb_update_itr(struct igb_q_vector *q_vector,
        case low_latency:  /* 50 usec aka 20000 ints/s */
                if (bytes > 10000) {
                        /* this if handles the TSO accounting */
-                       if (bytes/packets > 8000) {
+                       if (bytes/packets > 8000)
                                itrval = bulk_latency;
-                       } else if ((packets < 10) || ((bytes/packets) > 1200)) {
+                       else if ((packets < 10) || ((bytes/packets) > 1200))
                                itrval = bulk_latency;
-                       } else if ((packets > 35)) {
+                       else if ((packets > 35))
                                itrval = lowest_latency;
-                       }
                } else if (bytes/packets > 2000) {
                        itrval = bulk_latency;
                } else if (packets <= 2 && bytes < 512) {
@@ -4675,6 +4674,7 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
                        return;
        } else {
                u8 l4_hdr = 0;
+
                switch (first->protocol) {
                case htons(ETH_P_IP):
                        vlan_macip_lens |= skb_network_header_len(skb);
@@ -4962,6 +4962,7 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
         */
        if (NETDEV_FRAG_PAGE_MAX_SIZE > IGB_MAX_DATA_PER_TXD) {
                unsigned short f;
+
                for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
                        count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
        } else {
@@ -5140,7 +5141,7 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
                max_frame = ETH_FRAME_LEN + ETH_FCS_LEN;
 
        while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
-               msleep(1);
+               usleep_range(1000, 2000);
 
        /* igb_down has a dependency on max_frame_size */
        adapter->max_frame_size = max_frame;
@@ -5193,8 +5194,10 @@ void igb_update_stats(struct igb_adapter *adapter,
 
        rcu_read_lock();
        for (i = 0; i < adapter->num_rx_queues; i++) {
-               u32 rqdpc = rd32(E1000_RQDPC(i));
                struct igb_ring *ring = adapter->rx_ring[i];
+               u32 rqdpc = rd32(E1000_RQDPC(i));
+               if (hw->mac.type >= e1000_i210)
+                       wr32(E1000_RQDPC(i), 0);
 
                if (rqdpc) {
                        ring->rx_stats.drops += rqdpc;
@@ -5619,6 +5622,7 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
                        vmolr |= E1000_VMOLR_MPME;
                } else if (vf_data->num_vf_mc_hashes) {
                        int j;
+
                        vmolr |= E1000_VMOLR_ROMPE;
                        for (j = 0; j < vf_data->num_vf_mc_hashes; j++)
                                igb_mta_set(hw, vf_data->vf_mc_hashes[j]);
@@ -5670,6 +5674,7 @@ static void igb_restore_vf_multicasts(struct igb_adapter *adapter)
 
        for (i = 0; i < adapter->vfs_allocated_count; i++) {
                u32 vmolr = rd32(E1000_VMOLR(i));
+
                vmolr &= ~(E1000_VMOLR_ROMPE | E1000_VMOLR_MPME);
 
                vf_data = &adapter->vf_data[i];
@@ -5768,6 +5773,7 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
 
                        if (!adapter->vf_data[vf].vlans_enabled) {
                                u32 size;
+
                                reg = rd32(E1000_VMOLR(vf));
                                size = reg & E1000_VMOLR_RLPML_MASK;
                                size += 4;
@@ -5796,6 +5802,7 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
                        adapter->vf_data[vf].vlans_enabled--;
                        if (!adapter->vf_data[vf].vlans_enabled) {
                                u32 size;
+
                                reg = rd32(E1000_VMOLR(vf));
                                size = reg & E1000_VMOLR_RLPML_MASK;
                                size -= 4;
@@ -5900,8 +5907,8 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
         */
        if (!add && (adapter->netdev->flags & IFF_PROMISC)) {
                u32 vlvf, bits;
-
                int regndx = igb_find_vlvf_entry(adapter, vid);
+
                if (regndx < 0)
                        goto out;
                /* See if any other pools are set for this VLAN filter
@@ -6492,7 +6499,7 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring,
        rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
 
        /* transfer page from old buffer to new buffer */
-       memcpy(new_buff, old_buff, sizeof(struct igb_rx_buffer));
+       *new_buff = *old_buff;
 
        /* sync the buffer for use by the device */
        dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma,
@@ -6961,6 +6968,7 @@ static void igb_process_skb_fields(struct igb_ring *rx_ring,
        if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
            igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
                u16 vid;
+
                if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
                    test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
                        vid = be16_to_cpu(rx_desc->wb.upper.vlan);
@@ -7049,7 +7057,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
        if (cleaned_count)
                igb_alloc_rx_buffers(rx_ring, cleaned_count);
 
-       return (total_packets < budget);
+       return total_packets < budget;
 }
 
 static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
@@ -7170,7 +7178,7 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                break;
        case SIOCGMIIREG:
                if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
-                                    &data->val_out))
+                                    &data->val_out))
                        return -EIO;
                break;
        case SIOCSMIIREG:
@@ -7953,11 +7961,13 @@ static void igb_vmm_control(struct igb_adapter *adapter)
                reg = rd32(E1000_DTXCTL);
                reg |= E1000_DTXCTL_VLAN_ADDED;
                wr32(E1000_DTXCTL, reg);
+               /* Fall through */
        case e1000_82580:
                /* enable replication vlan tag stripping */
                reg = rd32(E1000_RPLOLR);
                reg |= E1000_RPLOLR_STRVLAN;
                wr32(E1000_RPLOLR, reg);
+               /* Fall through */
        case e1000_i350:
                /* none of the above registers are supported by i350 */
                break;
@@ -8047,6 +8057,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
                } /* endif adapter->dmac is not disabled */
        } else if (hw->mac.type == e1000_82580) {
                u32 reg = rd32(E1000_PCIEMISC);
+
                wr32(E1000_PCIEMISC, reg & ~E1000_PCIEMISC_LX_DECISION);
                wr32(E1000_DMACR, 0);
        }
index 9209d652e1c96090c712d78ce925612871ebad64..ab25e49365f79e26cfcad7a7ad12b8c5192824c9 100644 (file)
@@ -389,7 +389,7 @@ static void igb_ptp_tx_work(struct work_struct *work)
                adapter->ptp_tx_skb = NULL;
                clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
                adapter->tx_hwtstamp_timeouts++;
-               dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
+               dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n");
                return;
        }
 
@@ -451,7 +451,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
                rd32(E1000_RXSTMPH);
                adapter->last_rx_ptp_check = jiffies;
                adapter->rx_hwtstamp_cleared++;
-               dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang");
+               dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang\n");
        }
 }
 
index 1a12c1dd7a279c8f9db97c61a61ff4847c74db97..c688c8a4c0630ea5555214c6635bcc76940d6d57 100644 (file)
@@ -155,7 +155,6 @@ struct vf_data_storage {
 struct vf_macvlans {
        struct list_head l;
        int vf;
-       int rar_entry;
        bool free;
        bool is_macvlan;
        u8 vf_macvlan[ETH_ALEN];
@@ -256,7 +255,6 @@ struct ixgbe_ring {
                struct ixgbe_tx_buffer *tx_buffer_info;
                struct ixgbe_rx_buffer *rx_buffer_info;
        };
-       unsigned long last_rx_timestamp;
        unsigned long state;
        u8 __iomem *tail;
        dma_addr_t dma;                 /* phys. address of descriptor ring */
@@ -614,6 +612,15 @@ static inline void ixgbe_write_tail(struct ixgbe_ring *ring, u32 value)
 #define MAX_MSIX_VECTORS_82598 18
 #define MAX_Q_VECTORS_82598 16
 
+struct ixgbe_mac_addr {
+       u8 addr[ETH_ALEN];
+       u16 queue;
+       u16 state; /* bitmask */
+};
+#define IXGBE_MAC_STATE_DEFAULT                0x1
+#define IXGBE_MAC_STATE_MODIFIED       0x2
+#define IXGBE_MAC_STATE_IN_USE         0x4
+
 #define MAX_Q_VECTORS MAX_Q_VECTORS_82599
 #define MAX_MSIX_COUNT MAX_MSIX_VECTORS_82599
 
@@ -770,6 +777,7 @@ struct ixgbe_adapter {
        unsigned long ptp_tx_start;
        unsigned long last_overflow_check;
        unsigned long last_rx_ptp_check;
+       unsigned long last_rx_timestamp;
        spinlock_t tmreg_lock;
        struct cyclecounter cc;
        struct timecounter tc;
@@ -785,6 +793,7 @@ struct ixgbe_adapter {
 
        u32 timer_event_accumulator;
        u32 vferr_refcount;
+       struct ixgbe_mac_addr *mac_table;
        struct kobject *info_kobj;
 #ifdef CONFIG_IXGBE_HWMON
        struct hwmon_buff *ixgbe_hwmon_buff;
@@ -863,6 +872,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
 int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
                               u16 subdevice_id);
+#ifdef CONFIG_PCI_IOV
+void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter);
+#endif
+int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
+                        u8 *addr, u16 queue);
+int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter,
+                        u8 *addr, u16 queue);
 void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
 netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *, struct ixgbe_adapter *,
                                  struct ixgbe_ring *);
@@ -944,24 +960,7 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
-void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
-                            struct sk_buff *skb);
-static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
-                                        union ixgbe_adv_rx_desc *rx_desc,
-                                        struct sk_buff *skb)
-{
-       if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
-               return;
-
-       __ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
-
-       /*
-        * Update the last_rx_timestamp timer in order to enable watchdog check
-        * for error case of latched timestamp on a dropped packet.
-        */
-       rx_ring->last_rx_timestamp = jiffies;
-}
-
+void ixgbe_ptp_rx_hwtstamp(struct ixgbe_adapter *adapter, struct sk_buff *skb);
 int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
 int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
 void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
index 4c78ea8946c1b48838db6d7e9ce890089ff6ab59..1c52e4753480c0a133451e9234ffc826772b2d41 100644 (file)
@@ -337,19 +337,25 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw)
        int i;
        bool link_up;
 
-       /*
-        * Validate the water mark configuration for packet buffer 0.  Zero
-        * water marks indicate that the packet buffer was not configured
-        * and the watermarks for packet buffer 0 should always be configured.
-        */
-       if (!hw->fc.low_water ||
-           !hw->fc.high_water[0] ||
-           !hw->fc.pause_time) {
-               hw_dbg(hw, "Invalid water mark configuration\n");
+       /* Validate the water mark configuration */
+       if (!hw->fc.pause_time) {
                ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
                goto out;
        }
 
+       /* Low water mark of zero causes XOFF floods */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               if ((hw->fc.current_mode & ixgbe_fc_tx_pause) &&
+                   hw->fc.high_water[i]) {
+                       if (!hw->fc.low_water[i] ||
+                           hw->fc.low_water[i] >= hw->fc.high_water[i]) {
+                               hw_dbg(hw, "Invalid water mark configuration\n");
+                               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+                               goto out;
+                       }
+               }
+       }
+
        /*
         * On 82598 having Rx FC on causes resets while doing 1G
         * so if it's on turn it off once we know link_speed. For
@@ -432,12 +438,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw)
        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg);
        IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
 
-       fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE;
-
        /* Set up and enable Rx high/low water mark thresholds, enable XON. */
        for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
                if ((hw->fc.current_mode & ixgbe_fc_tx_pause) &&
                    hw->fc.high_water[i]) {
+                       fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE;
                        fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN;
                        IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl);
                        IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), fcrth);
index 24fba39e194e682640391e42e5e618907ff230d9..bdc55819179d19e7be2994c692b51941c464943a 100644 (file)
@@ -271,6 +271,7 @@ out:
  **/
 s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
 {
+       s32 ret_val;
        u32 ctrl_ext;
 
        /* Set the media type */
@@ -292,12 +293,15 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
        IXGBE_WRITE_FLUSH(hw);
 
        /* Setup flow control */
-       ixgbe_setup_fc(hw);
+       ret_val = ixgbe_setup_fc(hw);
+       if (!ret_val)
+               goto out;
 
        /* Clear adapter stopped flag */
        hw->adapter_stopped = false;
 
-       return 0;
+out:
+       return ret_val;
 }
 
 /**
@@ -1195,7 +1199,7 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
         */
        hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX - data[0];
 
-       hw_dbg(hw, "Detected EEPROM page size = %d words.",
+       hw_dbg(hw, "Detected EEPROM page size = %d words.\n",
               hw->eeprom.word_page_size);
 out:
        return status;
@@ -2106,19 +2110,25 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw)
        u32 fcrtl, fcrth;
        int i;
 
-       /*
-        * Validate the water mark configuration for packet buffer 0.  Zero
-        * water marks indicate that the packet buffer was not configured
-        * and the watermarks for packet buffer 0 should always be configured.
-        */
-       if (!hw->fc.low_water ||
-           !hw->fc.high_water[0] ||
-           !hw->fc.pause_time) {
-               hw_dbg(hw, "Invalid water mark configuration\n");
+       /* Validate the water mark configuration. */
+       if (!hw->fc.pause_time) {
                ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
                goto out;
        }
 
+       /* Low water mark of zero causes XOFF floods */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               if ((hw->fc.current_mode & ixgbe_fc_tx_pause) &&
+                   hw->fc.high_water[i]) {
+                       if (!hw->fc.low_water[i] ||
+                           hw->fc.low_water[i] >= hw->fc.high_water[i]) {
+                               hw_dbg(hw, "Invalid water mark configuration\n");
+                               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+                               goto out;
+                       }
+               }
+       }
+
        /* Negotiate the fc mode to use */
        ixgbe_fc_autoneg(hw);
 
@@ -2181,12 +2191,11 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw)
        IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg);
        IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg);
 
-       fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE;
-
        /* Set up and enable Rx high/low water mark thresholds, enable XON. */
        for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
                if ((hw->fc.current_mode & ixgbe_fc_tx_pause) &&
                    hw->fc.high_water[i]) {
+                       fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE;
                        IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl);
                        fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN;
                } else {
index f12c40fb5537a18604ff030f4adc4287946dbff4..d15ff2e5edb76b3dcb80a102666b2e2fa1dc6531 100644 (file)
@@ -141,8 +141,6 @@ static inline bool ixgbe_removed(void __iomem *addr)
        return unlikely(!addr);
 }
 
-void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg);
-
 static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
 {
        u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
@@ -172,18 +170,7 @@ static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value)
 }
 #define IXGBE_WRITE_REG64(a, reg, value) ixgbe_write_reg64((a), (reg), (value))
 
-static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
-{
-       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
-       u32 value;
-
-       if (ixgbe_removed(reg_addr))
-               return IXGBE_FAILED_READ_REG;
-       value = readl(reg_addr + reg);
-       if (unlikely(value == IXGBE_FAILED_READ_REG))
-               ixgbe_check_remove(hw, reg);
-       return value;
-}
+u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg);
 #define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg))
 
 #define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \
index 7a77f37a7cbcbd6b7b5b87dd78e9e50b677e778c..d3ba63f9ad3712fcf82d1bafc3408070112d1aa0 100644 (file)
@@ -208,7 +208,6 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
 
        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg);
 
-       fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE;
        /* Configure PFC Tx thresholds per TC */
        for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
                if (!(pfc_en & (1 << i))) {
@@ -217,6 +216,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
                        continue;
                }
 
+               fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE;
                reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN;
                IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl);
                IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg);
index bdb99b3b0f30f4ee2253e81bc72e84fb6a0d1e30..3b932fe64ab66c916f86f4184f45d626cc687cb1 100644 (file)
@@ -242,7 +242,6 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc)
                        max_tc = prio_tc[i];
        }
 
-       fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE;
 
        /* Configure PFC Tx thresholds per TC */
        for (i = 0; i <= max_tc; i++) {
@@ -257,6 +256,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc)
 
                if (enabled) {
                        reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN;
+                       fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE;
                        IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl);
                } else {
                        reg = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32;
index b16cc786750dec8bb7bf29749db331a31f028ec9..0772b7730fce92de4e2ff54d44f6528397c2b3a9 100644 (file)
@@ -81,9 +81,7 @@ struct ixgbe_fcoe {
        void *extra_ddp_buffer;
        dma_addr_t extra_ddp_buffer_dma;
        unsigned long mode;
-#ifdef CONFIG_IXGBE_DCB
        u8 up;
-#endif
 };
 
 #endif /* _IXGBE_FCOE_H */
index c4c526b7f99f48e2fe4eaccfe070273bd4078c98..8089ea9f2fba2b40662f3120a18ffbc84db33e5e 100644 (file)
@@ -301,7 +301,7 @@ static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
                ixgbe_service_event_schedule(adapter);
 }
 
-void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
+static void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
 {
        u32 value;
 
@@ -320,6 +320,32 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
                ixgbe_remove_adapter(hw);
 }
 
+/**
+ * ixgbe_read_reg - Read from device register
+ * @hw: hw specific details
+ * @reg: offset of register to read
+ *
+ * Returns : value read or IXGBE_FAILED_READ_REG if removed
+ *
+ * This function is used to read device registers. It checks for device
+ * removal by confirming any read that returns all ones by checking the
+ * status register value for all ones. This function avoids reading from
+ * the hardware if a removal was previously detected in which case it
+ * returns IXGBE_FAILED_READ_REG (all ones).
+ */
+u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
+{
+       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u32 value;
+
+       if (ixgbe_removed(reg_addr))
+               return IXGBE_FAILED_READ_REG;
+       value = readl(reg_addr + reg);
+       if (unlikely(value == IXGBE_FAILED_READ_REG))
+               ixgbe_check_remove(hw, reg);
+       return value;
+}
+
 static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev)
 {
        u16 value;
@@ -1664,7 +1690,8 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
 
        ixgbe_rx_checksum(rx_ring, rx_desc, skb);
 
-       ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
+       if (unlikely(ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
+               ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector->adapter, skb);
 
        if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
            ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
@@ -3741,35 +3768,6 @@ static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev,
        return 0;
 }
 
-/**
- * ixgbe_vlan_filter_disable - helper to disable hw vlan filtering
- * @adapter: driver data
- */
-static void ixgbe_vlan_filter_disable(struct ixgbe_adapter *adapter)
-{
-       struct ixgbe_hw *hw = &adapter->hw;
-       u32 vlnctrl;
-
-       vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
-       vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
-       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
-}
-
-/**
- * ixgbe_vlan_filter_enable - helper to enable hw vlan filtering
- * @adapter: driver data
- */
-static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
-{
-       struct ixgbe_hw *hw = &adapter->hw;
-       u32 vlnctrl;
-
-       vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
-       vlnctrl |= IXGBE_VLNCTRL_VFE;
-       vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
-       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
-}
-
 /**
  * ixgbe_vlan_strip_disable - helper to disable hw vlan stripping
  * @adapter: driver data
@@ -3848,6 +3846,158 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
                ixgbe_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
 }
 
+/**
+ * ixgbe_write_mc_addr_list - write multicast addresses to MTA
+ * @netdev: network interface device structure
+ *
+ * Writes multicast address list to the MTA hash table.
+ * Returns: -ENOMEM on failure
+ *                0 on no addresses written
+ *                X on writing X addresses to MTA
+ **/
+static int ixgbe_write_mc_addr_list(struct net_device *netdev)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       if (!netif_running(netdev))
+               return 0;
+
+       if (hw->mac.ops.update_mc_addr_list)
+               hw->mac.ops.update_mc_addr_list(hw, netdev);
+       else
+               return -ENOMEM;
+
+#ifdef CONFIG_PCI_IOV
+       ixgbe_restore_vf_multicasts(adapter);
+#endif
+
+       return netdev_mc_count(netdev);
+}
+
+#ifdef CONFIG_PCI_IOV
+void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+               if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE)
+                       hw->mac.ops.set_rar(hw, i, adapter->mac_table[i].addr,
+                                           adapter->mac_table[i].queue,
+                                           IXGBE_RAH_AV);
+               else
+                       hw->mac.ops.clear_rar(hw, i);
+
+               adapter->mac_table[i].state &= ~(IXGBE_MAC_STATE_MODIFIED);
+       }
+}
+#endif
+
+static void ixgbe_sync_mac_table(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+               if (adapter->mac_table[i].state & IXGBE_MAC_STATE_MODIFIED) {
+                       if (adapter->mac_table[i].state &
+                           IXGBE_MAC_STATE_IN_USE)
+                               hw->mac.ops.set_rar(hw, i,
+                                               adapter->mac_table[i].addr,
+                                               adapter->mac_table[i].queue,
+                                               IXGBE_RAH_AV);
+                       else
+                               hw->mac.ops.clear_rar(hw, i);
+
+                       adapter->mac_table[i].state &=
+                                               ~(IXGBE_MAC_STATE_MODIFIED);
+               }
+       }
+}
+
+static void ixgbe_flush_sw_mac_table(struct ixgbe_adapter *adapter)
+{
+       int i;
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+               adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED;
+               adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE;
+               memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
+               adapter->mac_table[i].queue = 0;
+       }
+       ixgbe_sync_mac_table(adapter);
+}
+
+static int ixgbe_available_rars(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i, count = 0;
+
+       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+               if (adapter->mac_table[i].state == 0)
+                       count++;
+       }
+       return count;
+}
+
+/* this function destroys the first RAR entry */
+static void ixgbe_mac_set_default_filter(struct ixgbe_adapter *adapter,
+                                        u8 *addr)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN);
+       adapter->mac_table[0].queue = VMDQ_P(0);
+       adapter->mac_table[0].state = (IXGBE_MAC_STATE_DEFAULT |
+                                      IXGBE_MAC_STATE_IN_USE);
+       hw->mac.ops.set_rar(hw, 0, adapter->mac_table[0].addr,
+                           adapter->mac_table[0].queue,
+                           IXGBE_RAH_AV);
+}
+
+int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+
+       if (is_zero_ether_addr(addr))
+               return -EINVAL;
+
+       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+               if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE)
+                       continue;
+               adapter->mac_table[i].state |= (IXGBE_MAC_STATE_MODIFIED |
+                                               IXGBE_MAC_STATE_IN_USE);
+               ether_addr_copy(adapter->mac_table[i].addr, addr);
+               adapter->mac_table[i].queue = queue;
+               ixgbe_sync_mac_table(adapter);
+               return i;
+       }
+       return -ENOMEM;
+}
+
+int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue)
+{
+       /* search table for addr, if found, set to 0 and sync */
+       int i;
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       if (is_zero_ether_addr(addr))
+               return -EINVAL;
+
+       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+               if (ether_addr_equal(addr, adapter->mac_table[i].addr) &&
+                   adapter->mac_table[i].queue == queue) {
+                       adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED;
+                       adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE;
+                       memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
+                       adapter->mac_table[i].queue = 0;
+                       ixgbe_sync_mac_table(adapter);
+                       return 0;
+               }
+       }
+       return -ENOMEM;
+}
 /**
  * ixgbe_write_uc_addr_list - write unicast addresses to RAR table
  * @netdev: network interface device structure
@@ -3857,39 +4007,23 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
  *                0 on no addresses written
  *                X on writing X addresses to the RAR table
  **/
-static int ixgbe_write_uc_addr_list(struct net_device *netdev)
+static int ixgbe_write_uc_addr_list(struct net_device *netdev, int vfn)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       struct ixgbe_hw *hw = &adapter->hw;
-       unsigned int rar_entries = hw->mac.num_rar_entries - 1;
        int count = 0;
 
-       /* In SR-IOV/VMDQ modes significantly less RAR entries are available */
-       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
-               rar_entries = IXGBE_MAX_PF_MACVLANS - 1;
-
        /* return ENOMEM indicating insufficient memory for addresses */
-       if (netdev_uc_count(netdev) > rar_entries)
+       if (netdev_uc_count(netdev) > ixgbe_available_rars(adapter))
                return -ENOMEM;
 
        if (!netdev_uc_empty(netdev)) {
                struct netdev_hw_addr *ha;
-               /* return error if we do not support writing to RAR table */
-               if (!hw->mac.ops.set_rar)
-                       return -ENOMEM;
-
                netdev_for_each_uc_addr(ha, netdev) {
-                       if (!rar_entries)
-                               break;
-                       hw->mac.ops.set_rar(hw, rar_entries--, ha->addr,
-                                           VMDQ_P(0), IXGBE_RAH_AV);
+                       ixgbe_del_mac_filter(adapter, ha->addr, vfn);
+                       ixgbe_add_mac_filter(adapter, ha->addr, vfn);
                        count++;
                }
        }
-       /* write the addresses in reverse order to avoid write combining */
-       for (; rar_entries > 0 ; rar_entries--)
-               hw->mac.ops.clear_rar(hw, rar_entries);
-
        return count;
 }
 
@@ -3907,11 +4041,12 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
+       u32 vlnctrl;
        int count;
 
        /* Check for Promiscuous and All Multicast modes */
-
        fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+       vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
 
        /* set all bits that we expect to always be set */
        fctrl &= ~IXGBE_FCTRL_SBP; /* disable store-bad-packets */
@@ -3921,26 +4056,24 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
 
        /* clear the bits we are changing the status of */
        fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
-
+       vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
        if (netdev->flags & IFF_PROMISC) {
                hw->addr_ctrl.user_set_promisc = true;
                fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
-               vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
+               vmolr |= IXGBE_VMOLR_MPE;
                /* Only disable hardware filter vlans in promiscuous mode
                 * if SR-IOV and VMDQ are disabled - otherwise ensure
                 * that hardware VLAN filters remain enabled.
                 */
                if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
                                        IXGBE_FLAG_SRIOV_ENABLED)))
-                       ixgbe_vlan_filter_disable(adapter);
-               else
-                       ixgbe_vlan_filter_enable(adapter);
+                       vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
        } else {
                if (netdev->flags & IFF_ALLMULTI) {
                        fctrl |= IXGBE_FCTRL_MPE;
                        vmolr |= IXGBE_VMOLR_MPE;
                }
-               ixgbe_vlan_filter_enable(adapter);
+               vlnctrl |= IXGBE_VLNCTRL_VFE;
                hw->addr_ctrl.user_set_promisc = false;
        }
 
@@ -3949,7 +4082,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
         * sufficient space to store all the addresses then enable
         * unicast promiscuous mode
         */
-       count = ixgbe_write_uc_addr_list(netdev);
+       count = ixgbe_write_uc_addr_list(netdev, VMDQ_P(0));
        if (count < 0) {
                fctrl |= IXGBE_FCTRL_UPE;
                vmolr |= IXGBE_VMOLR_ROPE;
@@ -3959,11 +4092,13 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
         * then we should just turn on promiscuous mode so
         * that we can at least receive multicast traffic
         */
-       hw->mac.ops.update_mc_addr_list(hw, netdev);
-       vmolr |= IXGBE_VMOLR_ROMPE;
-
-       if (adapter->num_vfs)
-               ixgbe_restore_vf_multicasts(adapter);
+       count = ixgbe_write_mc_addr_list(netdev);
+       if (count < 0) {
+               fctrl |= IXGBE_FCTRL_MPE;
+               vmolr |= IXGBE_VMOLR_MPE;
+       } else if (count) {
+               vmolr |= IXGBE_VMOLR_ROMPE;
+       }
 
        if (hw->mac.type != ixgbe_mac_82598EB) {
                vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(VMDQ_P(0))) &
@@ -3984,6 +4119,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
                /* NOTE:  VLAN filtering is disabled by setting PROMISC */
        }
 
+       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
 
        if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
@@ -4100,8 +4236,8 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
            (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) &&
            (pb == ixgbe_fcoe_get_tc(adapter)))
                tc = IXGBE_FCOE_JUMBO_FRAME_SIZE;
-
 #endif
+
        /* Calculate delay value for device */
        switch (hw->mac.type) {
        case ixgbe_mac_X540:
@@ -4142,7 +4278,7 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
  * @adapter: board private structure to calculate for
  * @pb: packet buffer to calculate
  */
-static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter)
+static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter, int pb)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        struct net_device *dev = adapter->netdev;
@@ -4152,6 +4288,14 @@ static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter)
        /* Calculate max LAN frame size */
        tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
 
+#ifdef IXGBE_FCOE
+       /* FCoE traffic class uses FCOE jumbo frames */
+       if ((dev->features & NETIF_F_FCOE_MTU) &&
+           (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) &&
+           (pb == netdev_get_prio_tc_map(dev, adapter->fcoe.up)))
+               tc = IXGBE_FCOE_JUMBO_FRAME_SIZE;
+#endif
+
        /* Calculate delay value for device */
        switch (hw->mac.type) {
        case ixgbe_mac_X540:
@@ -4178,15 +4322,17 @@ static void ixgbe_pbthresh_setup(struct ixgbe_adapter *adapter)
        if (!num_tc)
                num_tc = 1;
 
-       hw->fc.low_water = ixgbe_lpbthresh(adapter);
-
        for (i = 0; i < num_tc; i++) {
                hw->fc.high_water[i] = ixgbe_hpbthresh(adapter, i);
+               hw->fc.low_water[i] = ixgbe_lpbthresh(adapter, i);
 
                /* Low water marks must not be larger than high water marks */
-               if (hw->fc.low_water > hw->fc.high_water[i])
-                       hw->fc.low_water = 0;
+               if (hw->fc.low_water[i] > hw->fc.high_water[i])
+                       hw->fc.low_water[i] = 0;
        }
+
+       for (; i < MAX_TRAFFIC_CLASS; i++)
+               hw->fc.high_water[i] = 0;
 }
 
 static void ixgbe_configure_pb(struct ixgbe_adapter *adapter)
@@ -4248,20 +4394,10 @@ static void ixgbe_macvlan_set_rx_mode(struct net_device *dev, unsigned int pool,
                vmolr |= IXGBE_VMOLR_ROMPE;
                hw->mac.ops.update_mc_addr_list(hw, dev);
        }
-       ixgbe_write_uc_addr_list(adapter->netdev);
+       ixgbe_write_uc_addr_list(adapter->netdev, pool);
        IXGBE_WRITE_REG(hw, IXGBE_VMOLR(pool), vmolr);
 }
 
-static void ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
-                                u8 *addr, u16 pool)
-{
-       struct ixgbe_hw *hw = &adapter->hw;
-       unsigned int entry;
-
-       entry = hw->mac.num_rar_entries - pool;
-       hw->mac.ops.set_rar(hw, entry, addr, VMDQ_P(pool), IXGBE_RAH_AV);
-}
-
 static void ixgbe_fwd_psrtype(struct ixgbe_fwd_adapter *vadapter)
 {
        struct ixgbe_adapter *adapter = vadapter->real_adapter;
@@ -4741,7 +4877,9 @@ void ixgbe_up(struct ixgbe_adapter *adapter)
 void ixgbe_reset(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
        int err;
+       u8 old_addr[ETH_ALEN];
 
        if (ixgbe_removed(hw->hw_addr))
                return;
@@ -4777,9 +4915,10 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
        }
 
        clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
-
-       /* reprogram the RAR[0] in case user changed it. */
-       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, VMDQ_P(0), IXGBE_RAH_AV);
+       /* do not flush user set addresses */
+       memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len);
+       ixgbe_flush_sw_mac_table(adapter);
+       ixgbe_mac_set_default_filter(adapter, old_addr);
 
        /* update SAN MAC vmdq pool selection */
        if (hw->mac.san_mac_rar_index)
@@ -5025,6 +5164,10 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
 #endif /* CONFIG_IXGBE_DCB */
 #endif /* IXGBE_FCOE */
 
+       adapter->mac_table = kzalloc(sizeof(struct ixgbe_mac_addr) *
+                                    hw->mac.num_rar_entries,
+                                    GFP_ATOMIC);
+
        /* Set MAC specific capability flags and exceptions */
        switch (hw->mac.type) {
        case ixgbe_mac_82598EB:
@@ -7171,16 +7314,17 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p)
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
        struct sockaddr *addr = p;
+       int ret;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
+       ixgbe_del_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
 
-       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, VMDQ_P(0), IXGBE_RAH_AV);
-
-       return 0;
+       ret = ixgbe_add_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
+       return ret > 0 ? 0 : ret;
 }
 
 static int
@@ -8186,6 +8330,8 @@ skip_sriov:
                goto err_sw_init;
        }
 
+       ixgbe_mac_set_default_filter(adapter, hw->mac.perm_addr);
+
        setup_timer(&adapter->service_timer, &ixgbe_service_timer,
                    (unsigned long) adapter);
 
@@ -8318,6 +8464,7 @@ err_sw_init:
        ixgbe_disable_sriov(adapter);
        adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
        iounmap(adapter->io_addr);
+       kfree(adapter->mac_table);
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
@@ -8391,6 +8538,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
 
        e_dev_info("complete\n");
 
+       kfree(adapter->mac_table);
        free_netdev(netdev);
 
        pci_disable_pcie_error_reporting(pdev);
index 23f765263f12479822654a9af55263a8db233bd7..a76af8e28a04be16386c444cc947581638f3befa 100644 (file)
@@ -536,7 +536,7 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
 
        if (time_out == max_time_out) {
                status = IXGBE_ERR_LINK_SETUP;
-               hw_dbg(hw, "ixgbe_setup_phy_link_generic: time out");
+               hw_dbg(hw, "ixgbe_setup_phy_link_generic: time out\n");
        }
 
        return status;
@@ -745,7 +745,7 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
 
        if (time_out == max_time_out) {
                status = IXGBE_ERR_LINK_SETUP;
-               hw_dbg(hw, "ixgbe_setup_phy_link_tnx: time out");
+               hw_dbg(hw, "ixgbe_setup_phy_link_tnx: time out\n");
        }
 
        return status;
@@ -1175,7 +1175,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                                status = 0;
                        } else {
                                if (hw->allow_unsupported_sfp) {
-                                       e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics.  Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter.  Intel Corporation is not responsible for any harm caused by using untested modules.");
+                                       e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics.  Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter.  Intel Corporation is not responsible for any harm caused by using untested modules.\n");
                                        status = 0;
                                } else {
                                        hw_dbg(hw,
index 63515a6f67fae073b40bad8c58abc55a6c238517..8902ae68345770ce5f28ba2ab91ee73bab3c7ff3 100644 (file)
@@ -435,10 +435,8 @@ void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter)
 void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       struct ixgbe_ring *rx_ring;
        u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
        unsigned long rx_event;
-       int n;
 
        /* if we don't have a valid timestamp in the registers, just update the
         * timeout counter and exit
@@ -450,18 +448,15 @@ void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter)
 
        /* determine the most recent watchdog or rx_timestamp event */
        rx_event = adapter->last_rx_ptp_check;
-       for (n = 0; n < adapter->num_rx_queues; n++) {
-               rx_ring = adapter->rx_ring[n];
-               if (time_after(rx_ring->last_rx_timestamp, rx_event))
-                       rx_event = rx_ring->last_rx_timestamp;
-       }
+       if (time_after(adapter->last_rx_timestamp, rx_event))
+               rx_event = adapter->last_rx_timestamp;
 
        /* only need to read the high RXSTMP register to clear the lock */
        if (time_is_before_jiffies(rx_event + 5*HZ)) {
                IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
                adapter->last_rx_ptp_check = jiffies;
 
-               e_warn(drv, "clearing RX Timestamp hang");
+               e_warn(drv, "clearing RX Timestamp hang\n");
        }
 }
 
@@ -517,7 +512,7 @@ static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
                dev_kfree_skb_any(adapter->ptp_tx_skb);
                adapter->ptp_tx_skb = NULL;
                clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
-               e_warn(drv, "clearing Tx Timestamp hang");
+               e_warn(drv, "clearing Tx Timestamp hang\n");
                return;
        }
 
@@ -530,35 +525,22 @@ static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
 }
 
 /**
- * __ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
- * @q_vector: structure containing interrupt and ring information
+ * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
+ * @adapter: pointer to adapter struct
  * @skb: particular skb to send timestamp with
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the shhwtstamps structure which
  * is passed up the network stack
  */
-void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
-                            struct sk_buff *skb)
+void ixgbe_ptp_rx_hwtstamp(struct ixgbe_adapter *adapter, struct sk_buff *skb)
 {
-       struct ixgbe_adapter *adapter;
-       struct ixgbe_hw *hw;
+       struct ixgbe_hw *hw = &adapter->hw;
        struct skb_shared_hwtstamps *shhwtstamps;
        u64 regval = 0, ns;
        u32 tsyncrxctl;
        unsigned long flags;
 
-       /* we cannot process timestamps on a ring without a q_vector */
-       if (!q_vector || !q_vector->adapter)
-               return;
-
-       adapter = q_vector->adapter;
-       hw = &adapter->hw;
-
-       /*
-        * Read the tsyncrxctl register afterwards in order to prevent taking an
-        * I/O hit on every packet.
-        */
        tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
        if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID))
                return;
@@ -566,13 +548,17 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
        regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
        regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32;
 
-
        spin_lock_irqsave(&adapter->tmreg_lock, flags);
        ns = timecounter_cyc2time(&adapter->tc, regval);
        spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
        shhwtstamps = skb_hwtstamps(skb);
        shhwtstamps->hwtstamp = ns_to_ktime(ns);
+
+       /* Update the last_rx_timestamp timer in order to enable watchdog check
+        * for error case of latched timestamp on a dropped packet.
+        */
+       adapter->last_rx_timestamp = jiffies;
 }
 
 int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
index e6c68d396c992fffb329a1cca4daadb47169faab..a01417c066208e147cafd9134eed78efb7006d28 100644 (file)
@@ -72,8 +72,6 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
                for (i = 0; i < num_vf_macvlans; i++) {
                        mv_list->vf = -1;
                        mv_list->free = true;
-                       mv_list->rar_entry = hw->mac.num_rar_entries -
-                               (i + adapter->num_vfs + 1);
                        list_add(&mv_list->l, &adapter->vf_mvs.l);
                        mv_list++;
                }
@@ -327,6 +325,7 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
        u32 vector_bit;
        u32 vector_reg;
        u32 mta_reg;
+       u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
 
        /* only so many hash values supported */
        entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES);
@@ -353,25 +352,13 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
                mta_reg |= (1 << vector_bit);
                IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
        }
+       vmolr |= IXGBE_VMOLR_ROMPE;
+       IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
 
        return 0;
 }
 
-static void ixgbe_restore_vf_macvlans(struct ixgbe_adapter *adapter)
-{
-       struct ixgbe_hw *hw = &adapter->hw;
-       struct list_head *pos;
-       struct vf_macvlans *entry;
-
-       list_for_each(pos, &adapter->vf_mvs.l) {
-               entry = list_entry(pos, struct vf_macvlans, l);
-               if (!entry->free)
-                       hw->mac.ops.set_rar(hw, entry->rar_entry,
-                                           entry->vf_macvlan,
-                                           entry->vf, IXGBE_RAH_AV);
-       }
-}
-
+#ifdef CONFIG_PCI_IOV
 void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
@@ -382,6 +369,7 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
        u32 mta_reg;
 
        for (i = 0; i < adapter->num_vfs; i++) {
+               u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(i));
                vfinfo = &adapter->vfinfo[i];
                for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) {
                        hw->addr_ctrl.mta_in_use++;
@@ -391,11 +379,18 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
                        mta_reg |= (1 << vector_bit);
                        IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
                }
+
+               if (vfinfo->num_vf_mc_hashes)
+                       vmolr |= IXGBE_VMOLR_ROMPE;
+               else
+                       vmolr &= ~IXGBE_VMOLR_ROMPE;
+               IXGBE_WRITE_REG(hw, IXGBE_VMOLR(i), vmolr);
        }
 
        /* Restore any VF macvlans */
-       ixgbe_restore_vf_macvlans(adapter);
+       ixgbe_full_sync_mac_table(adapter);
 }
+#endif
 
 static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
                             u32 vf)
@@ -495,8 +490,7 @@ static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
 static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
 {
        u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
-       vmolr |= (IXGBE_VMOLR_ROMPE |
-                 IXGBE_VMOLR_BAM);
+       vmolr |= IXGBE_VMOLR_BAM;
        if (aupe)
                vmolr |= IXGBE_VMOLR_AUPE;
        else
@@ -514,7 +508,6 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
-       int rar_entry = hw->mac.num_rar_entries - (vf + 1);
        u8 num_tcs = netdev_get_num_tc(adapter->netdev);
 
        /* add PF assigned VLAN or VLAN 0 */
@@ -544,7 +537,7 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
        /* Flush and reset the mta with the new values */
        ixgbe_set_rx_mode(adapter->netdev);
 
-       hw->mac.ops.clear_rar(hw, rar_entry);
+       ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf);
 
        /* reset VF api back to unknown */
        adapter->vfinfo[vf].vf_api = ixgbe_mbox_api_10;
@@ -553,11 +546,9 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
 static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
                            int vf, unsigned char *mac_addr)
 {
-       struct ixgbe_hw *hw = &adapter->hw;
-       int rar_entry = hw->mac.num_rar_entries - (vf + 1);
-
+       ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf);
        memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
-       hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf, IXGBE_RAH_AV);
+       ixgbe_add_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf);
 
        return 0;
 }
@@ -565,7 +556,6 @@ static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
 static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
                                int vf, int index, unsigned char *mac_addr)
 {
-       struct ixgbe_hw *hw = &adapter->hw;
        struct list_head *pos;
        struct vf_macvlans *entry;
 
@@ -576,7 +566,8 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
                                entry->vf = -1;
                                entry->free = true;
                                entry->is_macvlan = false;
-                               hw->mac.ops.clear_rar(hw, entry->rar_entry);
+                               ixgbe_del_mac_filter(adapter,
+                                                    entry->vf_macvlan, vf);
                        }
                }
        }
@@ -612,7 +603,7 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
        entry->vf = vf;
        memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
 
-       hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, IXGBE_RAH_AV);
+       ixgbe_add_mac_filter(adapter, mac_addr, vf);
 
        return 0;
 }
index 139eaddfb2ed5c8c14a3891137a313b4fcaa3a6a..cea64014760497597710a0697b933771ac75f3a2 100644 (file)
@@ -34,7 +34,9 @@
  */
 #define IXGBE_MAX_VFS_DRV_LIMIT  (IXGBE_MAX_VF_FUNCTIONS - 1)
 
+#ifdef CONFIG_PCI_IOV
 void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter);
+#endif
 void ixgbe_msg_task(struct ixgbe_adapter *adapter);
 int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
 void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
index 8a6ff2423f076974d1c3c408b97c497d00bdc277..551d6089a4d3eb802e64f010f7abff5dc9ae1a94 100644 (file)
@@ -2746,7 +2746,7 @@ struct ixgbe_bus_info {
 /* Flow control parameters */
 struct ixgbe_fc_info {
        u32 high_water[MAX_TRAFFIC_CLASS]; /* Flow Control High-water */
-       u32 low_water; /* Flow Control Low-water */
+       u32 low_water[MAX_TRAFFIC_CLASS]; /* Flow Control Low-water */
        u16 pause_time; /* Flow Control Pause timer */
        bool send_xon; /* Flow control send XON */
        bool strict_ieee; /* Strict IEEE mode */
index d0799e8e31e4ea08e5dc89ec64b58c76bd5840a3..eacce3a2e9eca0f2336a1a2ab2eec732558dbb59 100644 (file)
@@ -85,7 +85,7 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbevf_pci_tbl) = {
 MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl);
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
-MODULE_DESCRIPTION("Intel(R) 82599 Virtual Function Driver");
+MODULE_DESCRIPTION("Intel(R) 10 Gigabit Virtual Function Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
index b161a525fc5bd8accb44b002b64776f05d8d0319..9d5ced263a5eb3d1397e95b675a2f83e71432547 100644 (file)
@@ -232,7 +232,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
                clk_prepare_enable(dev->clk);
 
        dev->err_interrupt = platform_get_irq(pdev, 0);
-       if (dev->err_interrupt != -ENXIO) {
+       if (dev->err_interrupt > 0) {
                ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
                                        orion_mdio_err_irq,
                                        IRQF_SHARED, pdev->name, dev);
@@ -241,6 +241,9 @@ static int orion_mdio_probe(struct platform_device *pdev)
 
                writel(MVMDIO_ERR_INT_SMI_DONE,
                        dev->regs + MVMDIO_ERR_INT_MASK);
+
+       } else if (dev->err_interrupt == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
        }
 
        mutex_init(&dev->lock);
index cef267e24f9c9c680613ec4ed2817c040b21c964..7cf9dadcb471bbfee9ef32761123ece4ceac131d 100644 (file)
@@ -754,10 +754,10 @@ static void mlx4_request_modules(struct mlx4_dev *dev)
                        has_eth_port = true;
        }
 
-       if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
-               request_module_nowait(IB_DRV_NAME);
        if (has_eth_port)
                request_module_nowait(EN_DRV_NAME);
+       if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
+               request_module_nowait(IB_DRV_NAME);
 }
 
 /*
@@ -2440,7 +2440,8 @@ slave_start:
         * No return code for this call, just warn the user in case of PCI
         * express device capabilities are under-satisfied by the bus.
         */
-       mlx4_check_pcie_caps(dev);
+       if (!mlx4_is_slave(dev))
+               mlx4_check_pcie_caps(dev);
 
        /* In master functions, the communication channel must be initialized
         * after obtaining its address from fw */
index cfcad26ed40f60b0e5b992195339d8c12c0e68d7..b5b3549b0c8d30e9878249c502af4d18e5162a25 100644 (file)
@@ -1106,6 +1106,9 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
        }
 
        if (found_ix >= 0) {
+               /* Calculate a slave_gid which is the slave number in the gid
+                * table and not a globally unique slave number.
+                */
                if (found_ix < MLX4_ROCE_PF_GIDS)
                        slave_gid = 0;
                else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
@@ -1118,41 +1121,43 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
                          ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
                         (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
 
+               /* Calculate the globally unique slave id */
                if (slave_gid) {
                        struct mlx4_active_ports exclusive_ports;
                        struct mlx4_active_ports actv_ports;
                        struct mlx4_slaves_pport slaves_pport_actv;
                        unsigned max_port_p_one;
-                       int num_slaves_before = 1;
+                       int num_vfs_before = 0;
+                       int candidate_slave_gid;
 
+                       /* Calculate how many VFs are on the previous port, if exists */
                        for (i = 1; i < port; i++) {
                                bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
-                               set_bit(i, exclusive_ports.ports);
+                               set_bit(i - 1, exclusive_ports.ports);
                                slaves_pport_actv =
                                        mlx4_phys_to_slaves_pport_actv(
                                                        dev, &exclusive_ports);
-                               num_slaves_before += bitmap_weight(
+                               num_vfs_before += bitmap_weight(
                                                slaves_pport_actv.slaves,
                                                dev->num_vfs + 1);
                        }
 
-                       if (slave_gid < num_slaves_before) {
-                               bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
-                               set_bit(port - 1, exclusive_ports.ports);
-                               slaves_pport_actv =
-                                       mlx4_phys_to_slaves_pport_actv(
-                                                       dev, &exclusive_ports);
-                               slave_gid += bitmap_weight(
-                                               slaves_pport_actv.slaves,
-                                               dev->num_vfs + 1) -
-                                               num_slaves_before;
-                       }
-                       actv_ports = mlx4_get_active_ports(dev, slave_gid);
+                       /* candidate_slave_gid isn't necessarily the correct slave, but
+                        * it has the same number of ports and is assigned to the same
+                        * ports as the real slave we're looking for. On dual port VF,
+                        * slave_gid = [single port VFs on port <port>] +
+                        * [offset of the current slave from the first dual port VF] +
+                        * 1 (for the PF).
+                        */
+                       candidate_slave_gid = slave_gid + num_vfs_before;
+
+                       actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
                        max_port_p_one = find_first_bit(
                                actv_ports.ports, dev->caps.num_ports) +
                                bitmap_weight(actv_ports.ports,
                                              dev->caps.num_ports) + 1;
 
+                       /* Calculate the real slave number */
                        for (i = 1; i < max_port_p_one; i++) {
                                if (i == port)
                                        continue;
index 3b5f53ef29b292d6edcb027f6b64b9c108a3a03b..1c3fdd4a1f7df3fe84847ae7ff278d652db13463 100644 (file)
@@ -3733,6 +3733,25 @@ static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
        }
 }
 
+static int mlx4_adjust_port(struct mlx4_dev *dev, int slave,
+                           u8 *gid, enum mlx4_protocol prot)
+{
+       int real_port;
+
+       if (prot != MLX4_PROT_ETH)
+               return 0;
+
+       if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 ||
+           dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               real_port = mlx4_slave_convert_port(dev, slave, gid[5]);
+               if (real_port < 0)
+                       return -EINVAL;
+               gid[5] = real_port;
+       }
+
+       return 0;
+}
+
 int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                               struct mlx4_vhcr *vhcr,
                               struct mlx4_cmd_mailbox *inbox,
@@ -3768,6 +3787,10 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                if (err)
                        goto ex_detach;
        } else {
+               err = mlx4_adjust_port(dev, slave, gid, prot);
+               if (err)
+                       goto ex_put;
+
                err = rem_mcg_res(dev, slave, rqp, gid, prot, type, &reg_id);
                if (err)
                        goto ex_put;
index a2844ff322c4c62bed8957a7f3797ad321359cbf..e900c1abdef789d234de4ad4eb1a41e0b090a358 100644 (file)
@@ -534,15 +534,6 @@ static inline void s2io_start_all_tx_queue(struct s2io_nic *sp)
        netif_tx_start_all_queues(sp->dev);
 }
 
-static inline void s2io_start_tx_queue(struct s2io_nic *sp, int fifo_no)
-{
-       if (!sp->config.multiq)
-               sp->mac_control.fifos[fifo_no].queue_state =
-                       FIFO_QUEUE_START;
-
-       netif_tx_start_all_queues(sp->dev);
-}
-
 static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp)
 {
        if (!sp->config.multiq) {
index c14bd3116e454edad88d27f7ab8923cb999ec885..b8184323faaecc3ccc2678d1ab4b73ce4766526f 100644 (file)
@@ -66,6 +66,17 @@ config QLCNIC_VXLAN
          Say Y here if you want to enable hardware offload support for
          Virtual eXtensible Local Area Network (VXLAN) in the driver.
 
+config QLCNIC_HWMON
+       bool "QLOGIC QLCNIC 82XX and 83XX family HWMON support"
+       depends on QLCNIC && HWMON
+       default y
+       ---help---
+         This configuration parameter can be used to read the
+         board temperature in Converged Ethernet devices
+         supported by qlcnic.
+
+         This data is available via the hwmon sysfs interface.
+
 config QLGE
        tristate "QLogic QLGE 10Gb Ethernet Driver Support"
        depends on PCI
index 7b52a88923ef2e53fadf9aca0185e2af492aa7be..09fe9c276f1c597f398c3bc606aa91a203d1879d 100644 (file)
@@ -39,8 +39,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 57
-#define QLCNIC_LINUX_VERSIONID  "5.3.57"
+#define _QLCNIC_LINUX_SUBVERSION 58
+#define QLCNIC_LINUX_VERSIONID  "5.3.58"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -537,6 +537,7 @@ struct qlcnic_hardware_context {
        u8 phys_port_id[ETH_ALEN];
        u8 lb_mode;
        u16 vxlan_port;
+       struct device *hwmon_dev;
 };
 
 struct qlcnic_adapter_stats {
@@ -2361,4 +2362,18 @@ static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter)
        else
                return QLC_DEFAULT_VNIC_COUNT;
 }
+
+#ifdef CONFIG_QLCNIC_HWMON
+void qlcnic_register_hwmon_dev(struct qlcnic_adapter *);
+void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *);
+#else
+static inline void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter)
+{
+       return;
+}
+static inline void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter)
+{
+       return;
+}
+#endif
 #endif                         /* __QLCNIC_H_ */
index b7cffb46a75dbd8f215752218a6f1f4239c1cc98..7c125d7fb547e3250e72dc149cd87b3f940d3a36 100644 (file)
@@ -33,6 +33,7 @@ static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);
 #define RSS_HASHTYPE_IP_TCP            0x3
 #define QLC_83XX_FW_MBX_CMD            0
 #define QLC_SKIP_INACTIVE_PCI_REGS     7
+#define QLC_MAX_LEGACY_FUNC_SUPP       8
 
 static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
        {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
@@ -357,8 +358,15 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
        if (!ahw->intr_tbl)
                return -ENOMEM;
 
-       if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+       if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               if (adapter->ahw->pci_func >= QLC_MAX_LEGACY_FUNC_SUPP) {
+                       dev_err(&adapter->pdev->dev, "PCI function number 8 and higher are not supported with legacy interrupt, func 0x%x\n",
+                               ahw->pci_func);
+                       return -EOPNOTSUPP;
+               }
+
                qlcnic_83xx_enable_legacy(adapter);
+       }
 
        for (i = 0; i < num_msix; i++) {
                if (adapter->flags & QLCNIC_MSIX_ENABLED)
@@ -879,6 +887,9 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
                        return 0;
                }
        }
+
+       dev_err(&adapter->pdev->dev, "%s: Invalid mailbox command opcode 0x%x\n",
+               __func__, type);
        return -EINVAL;
 }
 
index ba20c721ee97f59d05f18a126471cb4a4a277f0b..34d273794e9664109715218d5e54624bd1d5e599 100644 (file)
@@ -2181,6 +2181,8 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
                max_sds_rings = QLCNIC_MAX_SDS_RINGS;
                max_tx_rings = QLCNIC_MAX_TX_RINGS;
        } else {
+               dev_err(&adapter->pdev->dev, "%s: Invalid opmode %d\n",
+                       __func__, ret);
                return -EIO;
        }
 
index c1e11f5715b056c0e90ba096de8f397eb50fce97..304e247bdf339c59b30c816839da1bb0ccb9a6ac 100644 (file)
@@ -1027,8 +1027,11 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
        u32 arg1;
 
        if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC ||
-           !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
+           !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) {
+               dev_err(&adapter->pdev->dev, "%s: Not a management function\n",
+                       __func__);
                return err;
+       }
 
        arg1 = id | (enable_mirroring ? BIT_4 : 0);
        arg1 |= pci_func << 8;
@@ -1318,8 +1321,12 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
        u32 arg1, arg2 = 0;
        u8 pci_func;
 
-       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+               dev_err(&adapter->pdev->dev, "%s: Not a management function\n",
+                       __func__);
                return err;
+       }
+
        pci_func = esw_cfg->pci_func;
        index = qlcnic_is_valid_nic_func(adapter, pci_func);
        if (index < 0)
@@ -1363,6 +1370,8 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
                        arg1 &= ~(0x0ffff << 16);
                        break;
        default:
+               dev_err(&adapter->pdev->dev, "%s: Invalid opmode 0x%x\n",
+                       __func__, esw_cfg->op_mode);
                return err;
        }
 
index 173b3d12991f55a62751d5e6a213d20ee02c3174..deb2278b48d530759b45f9b1963de3b8e9b224d0 100644 (file)
@@ -305,7 +305,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
 {
        struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data);
        struct ethhdr *phdr = (struct ethhdr *)(skb->data);
-       struct net_device *netdev = adapter->netdev;
        u16 protocol = ntohs(skb->protocol);
        struct qlcnic_filter *fil, *tmp_fil;
        struct hlist_head *head;
@@ -330,13 +329,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
                        return;
        }
 
-       if (adapter->fhash.fnum >= adapter->fhash.fmax) {
-               adapter->stats.mac_filter_limit_overrun++;
-               netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n",
-                           adapter->fhash.fmax, adapter->fhash.fnum);
-               return;
-       }
-
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
        hval = qlcnic_mac_hash(src_addr, vlan_id);
        hindex = hval & (adapter->fhash.fbucket_size - 1);
@@ -353,6 +345,11 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
                }
        }
 
+       if (unlikely(adapter->fhash.fnum >= adapter->fhash.fmax)) {
+               adapter->stats.mac_filter_limit_overrun++;
+               return;
+       }
+
        fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
        if (!fil)
                return;
@@ -1216,8 +1213,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
        if (!skb)
                return buffer;
 
-       if (adapter->drv_mac_learn &&
-           (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+       if (adapter->rx_mac_learn) {
                t_vid = 0;
                is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
                qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
@@ -1293,8 +1289,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
        if (!skb)
                return buffer;
 
-       if (adapter->drv_mac_learn &&
-           (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+       if (adapter->rx_mac_learn) {
                t_vid = 0;
                is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
                qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
index dbf75393f758a153ccecfe2a8e49edb13dc8ff9a..748346e3cd92f8645b65a9f517a3c462308df32e 100644 (file)
@@ -690,10 +690,10 @@ int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter)
                adapter->msix_entries[vector].entry = vector;
 
 restore:
-       err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
-       if (err > 0) {
+       err = pci_enable_msix_exact(pdev, adapter->msix_entries, num_msix);
+       if (err == -ENOSPC) {
                if (!adapter->drv_tss_rings && !adapter->drv_rss_rings)
-                       return -ENOSPC;
+                       return err;
 
                netdev_info(adapter->netdev,
                            "Unable to allocate %d MSI-X vectors, Available vectors %d\n",
@@ -1014,6 +1014,8 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 
                if (pfn >= ahw->max_vnic_func) {
                        ret = QL_STATUS_INVALID_PARAM;
+                       dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n",
+                               __func__, pfn, ahw->max_vnic_func);
                        goto err_eswitch;
                }
 
@@ -2052,6 +2054,7 @@ out:
 
 static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        int err = 0;
 
        adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
@@ -2061,6 +2064,18 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
                goto err_out;
        }
 
+       if (qlcnic_83xx_check(adapter)) {
+               ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX;
+               ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
+               ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
+               ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
+               ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
+       } else {
+               ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX;
+               ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
+               ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
+       }
+
        /* clear stats */
        memset(&adapter->stats, 0, sizeof(adapter->stats));
 err_out:
@@ -2374,6 +2389,14 @@ void qlcnic_set_drv_version(struct qlcnic_adapter *adapter)
                qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd);
 }
 
+/* Reset firmware API lock */
+static void qlcnic_reset_api_lock(struct qlcnic_adapter *adapter)
+{
+       qlcnic_api_lock(adapter);
+       qlcnic_api_unlock(adapter);
+}
+
+
 static int
 qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -2476,6 +2499,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (qlcnic_82xx_check(adapter)) {
                qlcnic_check_vf(adapter, ent);
                adapter->portnum = adapter->ahw->pci_func;
+               qlcnic_reset_api_lock(adapter);
                err = qlcnic_start_firmware(adapter);
                if (err) {
                        dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"
@@ -2517,9 +2541,11 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        case -ENOMEM:
                                dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
                                goto err_out_free_hw;
+                       case -EOPNOTSUPP:
+                               dev_err(&pdev->dev, "Adapter initialization failed\n");
+                               goto err_out_free_hw;
                        default:
-                               dev_err(&pdev->dev, "Adapter initialization failed. A reboot may be required to recover from this failure\n");
-                               dev_err(&pdev->dev, "If reboot does not help to recover from this failure, try a flash update of the adapter\n");
+                               dev_err(&pdev->dev, "Adapter initialization failed. Driver will load in maintenance mode to recover the adapter using the application\n");
                                goto err_out_maintenance_mode;
                        }
                }
@@ -2593,7 +2619,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                qlcnic_alloc_lb_filters_mem(adapter);
 
        qlcnic_add_sysfs(adapter);
-
+       qlcnic_register_hwmon_dev(adapter);
        return 0;
 
 err_out_disable_mbx_intr:
@@ -2700,6 +2726,8 @@ static void qlcnic_remove(struct pci_dev *pdev)
 
        qlcnic_remove_sysfs(adapter);
 
+       qlcnic_unregister_hwmon_dev(adapter);
+
        qlcnic_cleanup_pci_map(adapter->ahw);
 
        qlcnic_release_firmware(adapter);
index 0638c1810d54547df9eafb961439085dff4364a2..6afe9c1f5ab9337a3fa7c64e7863664af3db99b7 100644 (file)
@@ -1370,7 +1370,7 @@ static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
 
        rsp = qlcnic_sriov_alloc_bc_trans(&trans);
        if (rsp)
-               return rsp;
+               goto free_cmd;
 
        rsp = qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND);
        if (rsp)
@@ -1425,6 +1425,13 @@ err_out:
 
 cleanup_transaction:
        qlcnic_sriov_cleanup_transaction(trans);
+
+free_cmd:
+       if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) {
+               qlcnic_free_mbx_args(cmd);
+               kfree(cmd);
+       }
+
        return rsp;
 }
 
index 2801379915447dc54683719c40058d9d89f8387f..c7926ce85fecf76fa226694dc5265dbdc9a812c0 100644 (file)
@@ -16,6 +16,7 @@
 #define QLC_VF_FLOOD_BIT       BIT_16
 #define QLC_FLOOD_MODE         0x5
 #define QLC_SRIOV_ALLOW_VLAN0  BIT_19
+#define QLC_INTR_COAL_TYPE_MASK        0x7
 
 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
 
@@ -1178,19 +1179,41 @@ static int qlcnic_sriov_validate_cfg_intrcoal(struct qlcnic_adapter *adapter,
 {
        struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
        u16 ctx_id, pkts, time;
+       int err = -EINVAL;
+       u8 type;
 
+       type = cmd->req.arg[1] & QLC_INTR_COAL_TYPE_MASK;
        ctx_id = cmd->req.arg[1] >> 16;
        pkts = cmd->req.arg[2] & 0xffff;
        time = cmd->req.arg[2] >> 16;
 
-       if (ctx_id != vf->rx_ctx_id)
-               return -EINVAL;
-       if (pkts > coal->rx_packets)
-               return -EINVAL;
-       if (time < coal->rx_time_us)
-               return -EINVAL;
+       switch (type) {
+       case QLCNIC_INTR_COAL_TYPE_RX:
+               if (ctx_id != vf->rx_ctx_id || pkts > coal->rx_packets ||
+                   time < coal->rx_time_us)
+                       goto err_label;
+               break;
+       case QLCNIC_INTR_COAL_TYPE_TX:
+               if (ctx_id != vf->tx_ctx_id || pkts > coal->tx_packets ||
+                   time < coal->tx_time_us)
+                       goto err_label;
+               break;
+       default:
+               netdev_err(adapter->netdev, "Invalid coalescing type 0x%x received\n",
+                          type);
+               return err;
+       }
 
        return 0;
+
+err_label:
+       netdev_err(adapter->netdev, "Expected: rx_ctx_id 0x%x rx_packets 0x%x rx_time_us 0x%x tx_ctx_id 0x%x tx_packets 0x%x tx_time_us 0x%x\n",
+                  vf->rx_ctx_id, coal->rx_packets, coal->rx_time_us,
+                  vf->tx_ctx_id, coal->tx_packets, coal->tx_time_us);
+       netdev_err(adapter->netdev, "Received: ctx_id 0x%x packets 0x%x time_us 0x%x type 0x%x\n",
+                  ctx_id, pkts, time, type);
+
+       return err;
 }
 
 static int qlcnic_sriov_pf_cfg_intrcoal_cmd(struct qlcnic_bc_trans *tran,
index cd346e27f2e1270078a7580c5e563bc178d5ef37..f5786d5792df06fe16db6f7ffd2276f9bdabe96f 100644 (file)
 #include <linux/sysfs.h>
 #include <linux/aer.h>
 #include <linux/log2.h>
+#ifdef CONFIG_QLCNIC_HWMON
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#endif
 
 #define QLC_STATUS_UNSUPPORTED_CMD     -2
 
@@ -358,6 +362,8 @@ int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
                if (adapter->npars[i].pci_func == pci_func)
                        return i;
        }
+
+       dev_err(&adapter->pdev->dev, "%s: Invalid nic function\n", __func__);
        return -EINVAL;
 }
 
@@ -1243,6 +1249,68 @@ static struct bin_attribute bin_attr_flash = {
        .write = qlcnic_83xx_sysfs_flash_write_handler,
 };
 
+#ifdef CONFIG_QLCNIC_HWMON
+
+static ssize_t qlcnic_hwmon_show_temp(struct device *dev,
+                                     struct device_attribute *dev_attr,
+                                     char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       unsigned int temperature = 0, value = 0;
+
+       if (qlcnic_83xx_check(adapter))
+               value = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
+       else if (qlcnic_82xx_check(adapter))
+               value = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP);
+
+       temperature = qlcnic_get_temp_val(value);
+       /* display millidegree celcius */
+       temperature *= 1000;
+       return sprintf(buf, "%u\n", temperature);
+}
+
+/* hwmon-sysfs attributes */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+                         qlcnic_hwmon_show_temp, NULL, 1);
+
+static struct attribute *qlcnic_hwmon_attrs[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(qlcnic_hwmon);
+
+void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+       struct device *hwmon_dev;
+
+       /* Skip hwmon registration for a VF device */
+       if (qlcnic_sriov_vf_check(adapter)) {
+               adapter->ahw->hwmon_dev = NULL;
+               return;
+       }
+       hwmon_dev = hwmon_device_register_with_groups(dev, qlcnic_driver_name,
+                                                     adapter,
+                                                     qlcnic_hwmon_groups);
+       if (IS_ERR(hwmon_dev)) {
+               dev_err(dev, "Cannot register with hwmon, err=%ld\n",
+                       PTR_ERR(hwmon_dev));
+               hwmon_dev = NULL;
+       }
+       adapter->ahw->hwmon_dev = hwmon_dev;
+}
+
+void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter)
+{
+       struct device *hwmon_dev = adapter->ahw->hwmon_dev;
+       if (hwmon_dev) {
+               hwmon_device_unregister(hwmon_dev);
+               adapter->ahw->hwmon_dev = NULL;
+       }
+}
+#endif
+
 void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
index 0a1d76acab8171929e3c6f9ad6139b48484ebbcc..6e36fe14b84849377fdea01ff5badabc6193b890 100644 (file)
@@ -3595,7 +3595,7 @@ static int ql_request_irq(struct ql_adapter *qdev)
        }
        return status;
 err_irq:
-       netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!/n");
+       netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!\n");
        ql_free_irq(qdev);
        return status;
 }
index 6203c7d8550fda4a530ec91e0a089870e507b4cb..45019649bbbd73227840d866ed92709e22a0d49c 100644 (file)
@@ -358,6 +358,8 @@ struct sxgbe_core_ops {
        /* Enable disable checksum offload operations */
        void (*enable_rx_csum)(void __iomem *ioaddr);
        void (*disable_rx_csum)(void __iomem *ioaddr);
+       void (*enable_rxqueue)(void __iomem *ioaddr, int queue_num);
+       void (*disable_rxqueue)(void __iomem *ioaddr, int queue_num);
 };
 
 const struct sxgbe_core_ops *sxgbe_get_core_ops(void);
index c4da7a2b002a16fa432f0bbe6fbce25be9085acc..58c35692560e599f0977c6460edcd0a616889e5f 100644 (file)
@@ -165,6 +165,26 @@ static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
        writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
 }
 
+static void sxgbe_core_enable_rxqueue(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_CORE_RX_CTL0_REG);
+       reg_val &= ~(SXGBE_CORE_RXQ_ENABLE_MASK << queue_num);
+       reg_val |= SXGBE_CORE_RXQ_ENABLE;
+       writel(reg_val, ioaddr + SXGBE_CORE_RX_CTL0_REG);
+}
+
+static void sxgbe_core_disable_rxqueue(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_CORE_RX_CTL0_REG);
+       reg_val &= ~(SXGBE_CORE_RXQ_ENABLE_MASK << queue_num);
+       reg_val |= SXGBE_CORE_RXQ_DISABLE;
+       writel(reg_val, ioaddr + SXGBE_CORE_RX_CTL0_REG);
+}
+
 static void  sxgbe_set_eee_mode(void __iomem *ioaddr)
 {
        u32 ctrl;
@@ -254,6 +274,8 @@ static const struct sxgbe_core_ops core_ops = {
        .set_eee_pls            = sxgbe_set_eee_pls,
        .enable_rx_csum         = sxgbe_enable_rx_csum,
        .disable_rx_csum        = sxgbe_disable_rx_csum,
+       .enable_rxqueue         = sxgbe_core_enable_rxqueue,
+       .disable_rxqueue        = sxgbe_core_disable_rxqueue,
 };
 
 const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
index e896dbbd2e156514eaf1d83ed8e132fbc3d88e37..2686bb5b6765680a8e18eeabd89146384da1c6f5 100644 (file)
@@ -45,10 +45,10 @@ static void sxgbe_prepare_tx_desc(struct sxgbe_tx_norm_desc *p, u8 is_fd,
        p->tdes23.tx_rd_des23.first_desc = is_fd;
        p->tdes23.tx_rd_des23.buf1_size = buf1_len;
 
-       p->tdes23.tx_rd_des23.tx_pkt_len.cksum_pktlen.total_pkt_len = pkt_len;
+       p->tdes23.tx_rd_des23.tx_pkt_len.pkt_len.total_pkt_len = pkt_len;
 
        if (cksum)
-               p->tdes23.tx_rd_des23.tx_pkt_len.cksum_pktlen.cksum_ctl = cic_full;
+               p->tdes23.tx_rd_des23.cksum_ctl = cic_full;
 }
 
 /* Set VLAN control information */
@@ -233,6 +233,12 @@ static void sxgbe_set_rx_owner(struct sxgbe_rx_norm_desc *p)
        p->rdes23.rx_rd_des23.own_bit = 1;
 }
 
+/* Set Interrupt on completion bit */
+static void sxgbe_set_rx_int_on_com(struct sxgbe_rx_norm_desc *p)
+{
+       p->rdes23.rx_rd_des23.int_on_com = 1;
+}
+
 /* Get the receive frame size */
 static int sxgbe_get_rx_frame_len(struct sxgbe_rx_norm_desc *p)
 {
@@ -498,6 +504,7 @@ static const struct sxgbe_desc_ops desc_ops = {
        .init_rx_desc                   = sxgbe_init_rx_desc,
        .get_rx_owner                   = sxgbe_get_rx_owner,
        .set_rx_owner                   = sxgbe_set_rx_owner,
+       .set_rx_int_on_com              = sxgbe_set_rx_int_on_com,
        .get_rx_frame_len               = sxgbe_get_rx_frame_len,
        .get_rx_fd_status               = sxgbe_get_rx_fd_status,
        .get_rx_ld_status               = sxgbe_get_rx_ld_status,
index 838cb9fb0ea979514bafc7b068cd4c09f3ee5d49..18609324db723dc2fbf5c50880d876ba83deb3d3 100644 (file)
@@ -39,22 +39,22 @@ struct sxgbe_tx_norm_desc {
                        u32 int_on_com:1;
                        /* TDES3 */
                        union {
-                               u32 tcp_payload_len:18;
+                               u16 tcp_payload_len;
                                struct {
                                        u32 total_pkt_len:15;
                                        u32 reserved1:1;
-                                       u32 cksum_ctl:2;
-                               } cksum_pktlen;
+                               } pkt_len;
                        } tx_pkt_len;
 
-                       u32 tse_bit:1;
-                       u32 tcp_hdr_len:4;
-                       u32 sa_insert_ctl:3;
-                       u32 crc_pad_ctl:2;
-                       u32 last_desc:1;
-                       u32 first_desc:1;
-                       u32 ctxt_bit:1;
-                       u32 own_bit:1;
+                       u16 cksum_ctl:2;
+                       u16 tse_bit:1;
+                       u16 tcp_hdr_len:4;
+                       u16 sa_insert_ctl:3;
+                       u16 crc_pad_ctl:2;
+                       u16 last_desc:1;
+                       u16 first_desc:1;
+                       u16 ctxt_bit:1;
+                       u16 own_bit:1;
                } tx_rd_des23;
 
                /* tx write back Desc 2,3 */
@@ -70,25 +70,20 @@ struct sxgbe_tx_norm_desc {
 
 struct sxgbe_rx_norm_desc {
        union {
-               u32 rdes0; /* buf1 address */
-               struct {
+               u64 rdes01; /* buf1 address */
+               union {
                        u32 out_vlan_tag:16;
                        u32 in_vlan_tag:16;
-               } wb_rx_des0;
-       } rd_wb_des0;
-
-       union {
-               u32 rdes1;      /* buf2 address or buf1[63:32] */
-               u32 rss_hash;   /* Write-back RX */
-       } rd_wb_des1;
+                       u32 rss_hash;
+               } rx_wb_des01;
+       } rdes01;
 
        union {
                /* RX Read format Desc 2,3 */
                struct{
                        /* RDES2 */
-                       u32 buf2_addr;
+                       u64 buf2_addr:62;
                        /* RDES3 */
-                       u32 buf2_hi_addr:30;
                        u32 int_on_com:1;
                        u32 own_bit:1;
                } rx_rd_des23;
@@ -263,6 +258,9 @@ struct sxgbe_desc_ops {
        /* Set own bit */
        void (*set_rx_owner)(struct sxgbe_rx_norm_desc *p);
 
+       /* Set Interrupt on completion bit */
+       void (*set_rx_int_on_com)(struct sxgbe_rx_norm_desc *p);
+
        /* Get the receive frame size */
        int (*get_rx_frame_len)(struct sxgbe_rx_norm_desc *p);
 
index 4d989ff6c978a8ad67d36afbb7d2df5ef6632929..bb9b5b8afc5f4417bae05c4ef0e1ea02f84b7421 100644 (file)
 /* DMA core initialization */
 static int sxgbe_dma_init(void __iomem *ioaddr, int fix_burst, int burst_map)
 {
-       int retry_count = 10;
        u32 reg_val;
 
-       /* reset the DMA */
-       writel(SXGBE_DMA_SOFT_RESET, ioaddr + SXGBE_DMA_MODE_REG);
-       while (retry_count--) {
-               if (!(readl(ioaddr + SXGBE_DMA_MODE_REG) &
-                     SXGBE_DMA_SOFT_RESET))
-                       break;
-               mdelay(10);
-       }
-
-       if (retry_count < 0)
-               return -EBUSY;
-
        reg_val = readl(ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
 
        /* if fix_burst = 0, Set UNDEF = 1 of DMA_Sys_Mode Register.
index 27e8c824b204fc8ec16c0f927216676415ca5834..698494481d18072ca00ddecb825ea92bd4e86c56 100644 (file)
@@ -425,8 +425,8 @@ dmamem_err:
  * @rx_rsize: ring size
  * Description:  this function initializes the DMA RX descriptor
  */
-void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring,
-                 int rx_rsize)
+static void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring,
+                        int rx_rsize)
 {
        dma_free_coherent(dev, rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
                          rx_ring->dma_rx, rx_ring->dma_rx_phy);
@@ -519,8 +519,8 @@ error:
  * @tx_rsize: ring size
  * Description:  this function initializes the DMA TX descriptor
  */
-void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring,
-                 int tx_rsize)
+static void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring,
+                        int tx_rsize)
 {
        dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
                          tx_ring->dma_tx, tx_ring->dma_tx_phy);
@@ -1076,6 +1076,9 @@ static int sxgbe_open(struct net_device *dev)
 
        /* Initialize the MAC Core */
        priv->hw->mac->core_init(priv->ioaddr);
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+               priv->hw->mac->enable_rxqueue(priv->ioaddr, queue_num);
+       }
 
        /* Request the IRQ lines */
        ret = devm_request_irq(priv->device, priv->irq, sxgbe_common_interrupt,
@@ -1218,11 +1221,10 @@ static int sxgbe_release(struct net_device *dev)
 
        return 0;
 }
-
 /* Prepare first Tx descriptor for doing TSO operation */
-void sxgbe_tso_prepare(struct sxgbe_priv_data *priv,
-                      struct sxgbe_tx_norm_desc *first_desc,
-                      struct sk_buff *skb)
+static void sxgbe_tso_prepare(struct sxgbe_priv_data *priv,
+                             struct sxgbe_tx_norm_desc *first_desc,
+                             struct sk_buff *skb)
 {
        unsigned int total_hdr_len, tcp_hdr_len;
 
@@ -1453,6 +1455,7 @@ static void sxgbe_rx_refill(struct sxgbe_priv_data *priv)
                /* Added memory barrier for RX descriptor modification */
                wmb();
                priv->hw->desc->set_rx_owner(p);
+               priv->hw->desc->set_rx_int_on_com(p);
                /* Added memory barrier for RX descriptor modification */
                wmb();
        }
@@ -1910,40 +1913,6 @@ static void sxgbe_set_rx_mode(struct net_device *dev)
                   readl(ioaddr + SXGBE_HASH_LOW));
 }
 
-/**
- * sxgbe_config - entry point for changing configuration mode passed on by
- * ifconfig
- * @dev : pointer to the device structure
- * @map : pointer to the device mapping structure
- * Description:
- * This function is a driver entry point which gets called by the kernel
- * whenever some device configuration is changed.
- * Return value:
- * This function returns 0 if success and appropriate error otherwise.
- */
-static int sxgbe_config(struct net_device *dev, struct ifmap *map)
-{
-       struct sxgbe_priv_data *priv = netdev_priv(dev);
-
-       /* Can't act on a running interface */
-       if (dev->flags & IFF_UP)
-               return -EBUSY;
-
-       /* Don't allow changing the I/O address */
-       if (map->base_addr != (unsigned long)priv->ioaddr) {
-               netdev_warn(dev, "can't change I/O address\n");
-               return -EOPNOTSUPP;
-       }
-
-       /* Don't allow changing the IRQ */
-       if (map->irq != priv->irq) {
-               netdev_warn(dev, "not change IRQ number %d\n", priv->irq);
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /**
  * sxgbe_poll_controller - entry point for polling receive by device
@@ -2005,7 +1974,6 @@ static const struct net_device_ops sxgbe_netdev_ops = {
        .ndo_set_rx_mode        = sxgbe_set_rx_mode,
        .ndo_tx_timeout         = sxgbe_tx_timeout,
        .ndo_do_ioctl           = sxgbe_ioctl,
-       .ndo_set_config         = sxgbe_config,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = sxgbe_poll_controller,
 #endif
@@ -2070,6 +2038,24 @@ static int sxgbe_hw_init(struct sxgbe_priv_data * const priv)
        return 0;
 }
 
+static int sxgbe_sw_reset(void __iomem *addr)
+{
+       int retry_count = 10;
+
+       writel(SXGBE_DMA_SOFT_RESET, addr + SXGBE_DMA_MODE_REG);
+       while (retry_count--) {
+               if (!(readl(addr + SXGBE_DMA_MODE_REG) &
+                     SXGBE_DMA_SOFT_RESET))
+                       break;
+               mdelay(10);
+       }
+
+       if (retry_count < 0)
+               return -EBUSY;
+
+       return 0;
+}
+
 /**
  * sxgbe_drv_probe
  * @device: device pointer
@@ -2102,6 +2088,10 @@ struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
        priv->plat = plat_dat;
        priv->ioaddr = addr;
 
+       ret = sxgbe_sw_reset(priv->ioaddr);
+       if (ret)
+               goto error_free_netdev;
+
        /* Verify driver arguments */
        sxgbe_verify_args();
 
@@ -2218,9 +2208,14 @@ error_free_netdev:
 int sxgbe_drv_remove(struct net_device *ndev)
 {
        struct sxgbe_priv_data *priv = netdev_priv(ndev);
+       u8 queue_num;
 
        netdev_info(ndev, "%s: removing driver\n", __func__);
 
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+               priv->hw->mac->disable_rxqueue(priv->ioaddr, queue_num);
+       }
+
        priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES);
        priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES);
 
index 01af2cbb479d10a96c1038bfc3f2ff167a20beb3..43ccb4a6de15a3fe2dedc9198a3866fd89143f47 100644 (file)
@@ -27,7 +27,7 @@
 #define SXGBE_SMA_PREAD_CMD    0x02 /* post read  increament address */
 #define SXGBE_SMA_READ_CMD     0x03 /* read command */
 #define SXGBE_SMA_SKIP_ADDRFRM 0x00040000 /* skip the address frame */
-#define SXGBE_MII_BUSY         0x00800000 /* mii busy */
+#define SXGBE_MII_BUSY         0x00400000 /* mii busy */
 
 static int sxgbe_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_data)
 {
@@ -147,6 +147,7 @@ int sxgbe_mdio_register(struct net_device *ndev)
        struct sxgbe_mdio_bus_data *mdio_data = priv->plat->mdio_bus_data;
        int err, phy_addr;
        int *irqlist;
+       bool phy_found = false;
        bool act;
 
        /* allocate the new mdio bus */
@@ -162,7 +163,7 @@ int sxgbe_mdio_register(struct net_device *ndev)
                irqlist = priv->mii_irq;
 
        /* assign mii bus fields */
-       mdio_bus->name = "samsxgbe";
+       mdio_bus->name = "sxgbe";
        mdio_bus->read = &sxgbe_mdio_read;
        mdio_bus->write = &sxgbe_mdio_write;
        snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%x",
@@ -216,13 +217,22 @@ int sxgbe_mdio_register(struct net_device *ndev)
                        netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
                                    phy->phy_id, phy_addr, irq_str,
                                    dev_name(&phy->dev), act ? " active" : "");
+                       phy_found = true;
                }
        }
 
+       if (!phy_found) {
+               netdev_err(ndev, "PHY not found\n");
+               goto phyfound_err;
+       }
+
        priv->mii = mdio_bus;
 
        return 0;
 
+phyfound_err:
+       err = -ENODEV;
+       mdiobus_unregister(mdio_bus);
 mdiobus_err:
        mdiobus_free(mdio_bus);
        return err;
index 5a89acb4c505fc83f3847a10c437c961db079dec..56f8bf5a3f1b99564a2b055830810fe3d156e6c4 100644 (file)
 #define SXGBE_CORE_RX_CTL2_REG         0x00A8
 #define SXGBE_CORE_RX_CTL3_REG         0x00AC
 
+#define SXGBE_CORE_RXQ_ENABLE_MASK     0x0003
+#define SXGBE_CORE_RXQ_ENABLE          0x0002
+#define SXGBE_CORE_RXQ_DISABLE         0x0000
+
 /* Interrupt Registers */
 #define SXGBE_CORE_INT_STATUS_REG      0x00B0
 #define SXGBE_CORE_INT_ENABLE_REG      0x00B4
index d1b4dca53a9d10be97f05e2e09dd08418598bf05..bcaa41af1e628e9f8d2e84fccc7a38ea716e428c 100644 (file)
@@ -147,18 +147,19 @@ MODULE_ALIAS("platform:smc91x");
  */
 #define MII_DELAY              1
 
-#if SMC_DEBUG > 0
-#define DBG(n, dev, args...)                           \
-       do {                                            \
-               if (SMC_DEBUG >= (n))                   \
-                       netdev_dbg(dev, args);          \
+#define DBG(n, dev, fmt, ...)                                  \
+       do {                                                    \
+               if (SMC_DEBUG >= (n))                           \
+                       netdev_dbg(dev, fmt, ##__VA_ARGS__);    \
        } while (0)
 
-#define PRINTK(dev, args...)   netdev_info(dev, args)
-#else
-#define DBG(n, dev, args...)   do { } while (0)
-#define PRINTK(dev, args...)   netdev_dbg(dev, args)
-#endif
+#define PRINTK(dev, fmt, ...)                                  \
+       do {                                                    \
+               if (SMC_DEBUG > 0)                              \
+                       netdev_info(dev, fmt, ##__VA_ARGS__);   \
+               else                                            \
+                       netdev_dbg(dev, fmt, ##__VA_ARGS__);    \
+       } while (0)
 
 #if SMC_DEBUG > 3
 static void PRINT_PKT(u_char *buf, int length)
@@ -191,7 +192,7 @@ static void PRINT_PKT(u_char *buf, int length)
        pr_cont("\n");
 }
 #else
-#define PRINT_PKT(x...)  do { } while (0)
+static inline void PRINT_PKT(u_char *buf, int length) { }
 #endif
 
 
@@ -1781,7 +1782,7 @@ static int smc_findirq(struct smc_local *lp)
        int timeout = 20;
        unsigned long cookie;
 
-       DBG(2, dev, "%s: %s\n", CARDNAME, __func__);
+       DBG(2, lp->dev, "%s: %s\n", CARDNAME, __func__);
 
        cookie = probe_irq_on();
 
index d940034acdd4aa465153f80ae0d5881cb648d6a8..93cf4f63f42646c60c7c4e29eb147ec07db8fd1e 100644 (file)
@@ -2214,27 +2214,6 @@ static void stmmac_tx_timeout(struct net_device *dev)
        stmmac_tx_err(priv);
 }
 
-/* Configuration changes (passed on by ifconfig) */
-static int stmmac_config(struct net_device *dev, struct ifmap *map)
-{
-       if (dev->flags & IFF_UP)        /* can't act on a running interface */
-               return -EBUSY;
-
-       /* Don't allow changing the I/O address */
-       if (map->base_addr != dev->base_addr) {
-               pr_warn("%s: can't change I/O address\n", dev->name);
-               return -EOPNOTSUPP;
-       }
-
-       /* Don't allow changing the IRQ */
-       if (map->irq != dev->irq) {
-               pr_warn("%s: not change IRQ number %d\n", dev->name, dev->irq);
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
-
 /**
  *  stmmac_set_rx_mode - entry point for multicast addressing
  *  @dev : pointer to the device structure
@@ -2600,7 +2579,6 @@ static const struct net_device_ops stmmac_netdev_ops = {
        .ndo_set_rx_mode = stmmac_set_rx_mode,
        .ndo_tx_timeout = stmmac_tx_timeout,
        .ndo_do_ioctl = stmmac_ioctl,
-       .ndo_set_config = stmmac_config,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = stmmac_poll_controller,
 #endif
index a468eb10782361e31fd0b0af5ce6be33d68a2578..a5b1e1b776fe3313c5c9852062ed66ea1547c285 100644 (file)
@@ -205,10 +205,13 @@ int stmmac_mdio_register(struct net_device *ndev)
        if (new_bus == NULL)
                return -ENOMEM;
 
-       if (mdio_bus_data->irqs)
+       if (mdio_bus_data->irqs) {
                irqlist = mdio_bus_data->irqs;
-       else
+       } else {
+               for (addr = 0; addr < PHY_MAX_ADDR; addr++)
+                       priv->mii_irq[addr] = PHY_POLL;
                irqlist = priv->mii_irq;
+       }
 
 #ifdef CONFIG_OF
        if (priv->device->of_node)
index 73f74f369437174144b59a8f1426cbbcbaf21c34..7399a52f7c260aa7a037cbe134b35ca82b6cf840 100644 (file)
@@ -313,19 +313,6 @@ static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
 
 static struct mii_bus *cpmac_mii;
 
-static int cpmac_config(struct net_device *dev, struct ifmap *map)
-{
-       if (dev->flags & IFF_UP)
-               return -EBUSY;
-
-       /* Don't allow changing the I/O address */
-       if (map->base_addr != dev->base_addr)
-               return -EOPNOTSUPP;
-
-       /* ignore other fields */
-       return 0;
-}
-
 static void cpmac_set_multicast_list(struct net_device *dev)
 {
        struct netdev_hw_addr *ha;
@@ -1100,7 +1087,6 @@ static const struct net_device_ops cpmac_netdev_ops = {
        .ndo_tx_timeout         = cpmac_tx_timeout,
        .ndo_set_rx_mode        = cpmac_set_multicast_list,
        .ndo_do_ioctl           = cpmac_ioctl,
-       .ndo_set_config         = cpmac_config,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
index 36aa109416c4c3a387a440795a8d3611cf3d4ded..d14c8da53160141102bc0e8bf82a80c0d95d14c9 100644 (file)
@@ -248,20 +248,31 @@ struct cpsw_ss_regs {
 #define TS_131              (1<<11) /* Time Sync Dest IP Addr 131 enable */
 #define TS_130              (1<<10) /* Time Sync Dest IP Addr 130 enable */
 #define TS_129              (1<<9)  /* Time Sync Dest IP Addr 129 enable */
-#define TS_BIT8             (1<<8)  /* ts_ttl_nonzero? */
+#define TS_TTL_NONZERO      (1<<8)  /* Time Sync Time To Live Non-zero enable */
+#define TS_ANNEX_F_EN       (1<<6)  /* Time Sync Annex F enable */
 #define TS_ANNEX_D_EN       (1<<4)  /* Time Sync Annex D enable */
 #define TS_LTYPE2_EN        (1<<3)  /* Time Sync LTYPE 2 enable */
 #define TS_LTYPE1_EN        (1<<2)  /* Time Sync LTYPE 1 enable */
 #define TS_TX_EN            (1<<1)  /* Time Sync Transmit Enable */
 #define TS_RX_EN            (1<<0)  /* Time Sync Receive Enable */
 
-#define CTRL_TS_BITS \
-       (TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 | TS_BIT8 | \
-        TS_ANNEX_D_EN | TS_LTYPE1_EN)
+#define CTRL_V2_TS_BITS \
+       (TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\
+        TS_TTL_NONZERO  | TS_ANNEX_D_EN | TS_LTYPE1_EN)
 
-#define CTRL_ALL_TS_MASK (CTRL_TS_BITS | TS_TX_EN | TS_RX_EN)
-#define CTRL_TX_TS_BITS  (CTRL_TS_BITS | TS_TX_EN)
-#define CTRL_RX_TS_BITS  (CTRL_TS_BITS | TS_RX_EN)
+#define CTRL_V2_ALL_TS_MASK (CTRL_V2_TS_BITS | TS_TX_EN | TS_RX_EN)
+#define CTRL_V2_TX_TS_BITS  (CTRL_V2_TS_BITS | TS_TX_EN)
+#define CTRL_V2_RX_TS_BITS  (CTRL_V2_TS_BITS | TS_RX_EN)
+
+
+#define CTRL_V3_TS_BITS \
+       (TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\
+        TS_TTL_NONZERO | TS_ANNEX_F_EN | TS_ANNEX_D_EN |\
+        TS_LTYPE1_EN)
+
+#define CTRL_V3_ALL_TS_MASK (CTRL_V3_TS_BITS | TS_TX_EN | TS_RX_EN)
+#define CTRL_V3_TX_TS_BITS  (CTRL_V3_TS_BITS | TS_TX_EN)
+#define CTRL_V3_RX_TS_BITS  (CTRL_V3_TS_BITS | TS_RX_EN)
 
 /* Bit definitions for the CPSW2_TS_SEQ_MTYPE register */
 #define TS_SEQ_ID_OFFSET_SHIFT   (16)    /* Time Sync Sequence ID Offset */
@@ -1376,13 +1387,27 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
                slave = &priv->slaves[priv->data.active_slave];
 
        ctrl = slave_read(slave, CPSW2_CONTROL);
-       ctrl &= ~CTRL_ALL_TS_MASK;
+       switch (priv->version) {
+       case CPSW_VERSION_2:
+               ctrl &= ~CTRL_V2_ALL_TS_MASK;
 
-       if (priv->cpts->tx_enable)
-               ctrl |= CTRL_TX_TS_BITS;
+               if (priv->cpts->tx_enable)
+                       ctrl |= CTRL_V2_TX_TS_BITS;
 
-       if (priv->cpts->rx_enable)
-               ctrl |= CTRL_RX_TS_BITS;
+               if (priv->cpts->rx_enable)
+                       ctrl |= CTRL_V2_RX_TS_BITS;
+       break;
+       case CPSW_VERSION_3:
+       default:
+               ctrl &= ~CTRL_V3_ALL_TS_MASK;
+
+               if (priv->cpts->tx_enable)
+                       ctrl |= CTRL_V3_TX_TS_BITS;
+
+               if (priv->cpts->rx_enable)
+                       ctrl |= CTRL_V3_RX_TS_BITS;
+       break;
+       }
 
        mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
 
@@ -1398,7 +1423,8 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
        struct hwtstamp_config cfg;
 
        if (priv->version != CPSW_VERSION_1 &&
-           priv->version != CPSW_VERSION_2)
+           priv->version != CPSW_VERSION_2 &&
+           priv->version != CPSW_VERSION_3)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
@@ -1443,6 +1469,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
                cpsw_hwtstamp_v1(priv);
                break;
        case CPSW_VERSION_2:
+       case CPSW_VERSION_3:
                cpsw_hwtstamp_v2(priv);
                break;
        default:
@@ -1459,7 +1486,8 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
        struct hwtstamp_config cfg;
 
        if (priv->version != CPSW_VERSION_1 &&
-           priv->version != CPSW_VERSION_2)
+           priv->version != CPSW_VERSION_2 &&
+           priv->version != CPSW_VERSION_3)
                return -EOPNOTSUPP;
 
        cfg.flags = 0;
index 243513980b51511a9c3054d71c8a270d63949cb1..6b56f85951e581826afc152109d0eee4b53dd08d 100644 (file)
@@ -236,13 +236,11 @@ static void cpts_overflow_check(struct work_struct *work)
        schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
 }
 
-#define CPTS_REF_CLOCK_NAME "cpsw_cpts_rft_clk"
-
-static void cpts_clk_init(struct cpts *cpts)
+static void cpts_clk_init(struct device *dev, struct cpts *cpts)
 {
-       cpts->refclk = clk_get(NULL, CPTS_REF_CLOCK_NAME);
+       cpts->refclk = devm_clk_get(dev, "cpts");
        if (IS_ERR(cpts->refclk)) {
-               pr_err("Failed to clk_get %s\n", CPTS_REF_CLOCK_NAME);
+               dev_err(dev, "Failed to get cpts refclk\n");
                cpts->refclk = NULL;
                return;
        }
@@ -252,7 +250,6 @@ static void cpts_clk_init(struct cpts *cpts)
 static void cpts_clk_release(struct cpts *cpts)
 {
        clk_disable(cpts->refclk);
-       clk_put(cpts->refclk);
 }
 
 static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
@@ -390,7 +387,7 @@ int cpts_register(struct device *dev, struct cpts *cpts,
        for (i = 0; i < CPTS_MAX_EVENTS; i++)
                list_add(&cpts->pool_data[i].list, &cpts->pool);
 
-       cpts_clk_init(cpts);
+       cpts_clk_init(dev, cpts);
        cpts_write32(cpts, CPTS_EN, control);
        cpts_write32(cpts, TS_PEND_EN, int_enable);
 
index 0cca9dec5d8277542a4439aed4bb8953f3943b29..34e97eca561c273030a0b5e8d7473dd3e4276798 100644 (file)
@@ -321,15 +321,14 @@ static int davinci_mdio_probe(struct platform_device *pdev)
        struct phy_device *phy;
        int ret, addr;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       data->bus = mdiobus_alloc();
+       data->bus = devm_mdiobus_alloc(dev);
        if (!data->bus) {
                dev_err(dev, "failed to alloc mii bus\n");
-               ret = -ENOMEM;
-               goto bail_out;
+               return -ENOMEM;
        }
 
        if (dev->of_node) {
@@ -349,12 +348,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)
        data->bus->parent       = dev;
        data->bus->priv         = data;
 
-       /* Select default pin state */
-       pinctrl_pm_select_default_state(&pdev->dev);
-
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
-       data->clk = clk_get(&pdev->dev, "fck");
+       data->clk = devm_clk_get(dev, "fck");
        if (IS_ERR(data->clk)) {
                dev_err(dev, "failed to get device clock\n");
                ret = PTR_ERR(data->clk);
@@ -367,24 +363,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)
        spin_lock_init(&data->lock);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(dev, "could not find register map resource\n");
-               ret = -ENOENT;
-               goto bail_out;
-       }
-
-       res = devm_request_mem_region(dev, res->start, resource_size(res),
-                                           dev_name(dev));
-       if (!res) {
-               dev_err(dev, "could not allocate register map resource\n");
-               ret = -ENXIO;
-               goto bail_out;
-       }
-
-       data->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (!data->regs) {
-               dev_err(dev, "could not map mdio registers\n");
-               ret = -ENOMEM;
+       data->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->regs)) {
+               ret = PTR_ERR(data->regs);
                goto bail_out;
        }
 
@@ -406,16 +387,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)
        return 0;
 
 bail_out:
-       if (data->bus)
-               mdiobus_free(data->bus);
-
-       if (data->clk)
-               clk_put(data->clk);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-       kfree(data);
-
        return ret;
 }
 
@@ -423,18 +397,12 @@ static int davinci_mdio_remove(struct platform_device *pdev)
 {
        struct davinci_mdio_data *data = platform_get_drvdata(pdev);
 
-       if (data->bus) {
+       if (data->bus)
                mdiobus_unregister(data->bus);
-               mdiobus_free(data->bus);
-       }
 
-       if (data->clk)
-               clk_put(data->clk);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-       kfree(data);
-
        return 0;
 }
 
index 8a049a2b44742aabe24221b12a6bcb2a4caf357f..f66ddaee0c877f1620ad123fd9ef8402703aa1a6 100644 (file)
@@ -19,7 +19,7 @@ if NET_VENDOR_VIA
 
 config VIA_RHINE
        tristate "VIA Rhine support"
-       depends on PCI
+       depends on (PCI || USE_OF)
        select CRC32
        select MII
        ---help---
index f61dc2b72bb2f43780ace58a503bd2e3b89f61a9..981be0154be393931d958f8310bd2e0572184d04 100644 (file)
@@ -94,6 +94,10 @@ static const int multicast_filter_limit = 32;
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -116,13 +120,6 @@ static const int multicast_filter_limit = 32;
 static const char version[] =
        "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker";
 
-/* This driver was written to use PCI memory space. Some early versions
-   of the Rhine may only work correctly with I/O space accesses. */
-#ifdef CONFIG_VIA_RHINE_MMIO
-#define USE_MMIO
-#else
-#endif
-
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
@@ -260,6 +257,12 @@ enum rhine_quirks {
        rq6patterns     = 0x0040,       /* 6 instead of 4 patterns for WOL */
        rqStatusWBRace  = 0x0080,       /* Tx Status Writeback Error possible */
        rqRhineI        = 0x0100,       /* See comment below */
+       rqIntPHY        = 0x0200,       /* Integrated PHY */
+       rqMgmt          = 0x0400,       /* Management adapter */
+       rqNeedEnMMIO    = 0x0800,       /* Whether the core needs to be
+                                        * switched from PIO mode to MMIO
+                                        * (only applies to PCI)
+                                        */
 };
 /*
  * rqRhineI: VT86C100A (aka Rhine-I) uses different bits to enable
@@ -279,6 +282,15 @@ static DEFINE_PCI_DEVICE_TABLE(rhine_pci_tbl) = {
 };
 MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
 
+/* OpenFirmware identifiers for platform-bus devices
+ * The .data field is currently only used to store quirks
+ */
+static u32 vt8500_quirks = rqWOL | rqForceReset | rq6patterns;
+static struct of_device_id rhine_of_tbl[] = {
+       { .compatible = "via,vt8500-rhine", .data = &vt8500_quirks },
+       { }     /* terminate list */
+};
+MODULE_DEVICE_TABLE(of, rhine_of_tbl);
 
 /* Offsets to the device registers. */
 enum register_offsets {
@@ -338,13 +350,11 @@ enum bcr1_bits {
        BCR1_MED1=0x80,         /* for VT6102 */
 };
 
-#ifdef USE_MMIO
 /* Registers we check that mmio and reg are the same. */
 static const int mmio_verify_registers[] = {
        RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD,
        0
 };
-#endif
 
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
@@ -446,7 +456,7 @@ struct rhine_private {
        unsigned char *tx_bufs;
        dma_addr_t tx_bufs_dma;
 
-       struct pci_dev *pdev;
+       int irq;
        long pioaddr;
        struct net_device *dev;
        struct napi_struct napi;
@@ -649,20 +659,46 @@ static void rhine_chip_reset(struct net_device *dev)
                   "failed" : "succeeded");
 }
 
-#ifdef USE_MMIO
 static void enable_mmio(long pioaddr, u32 quirks)
 {
        int n;
-       if (quirks & rqRhineI) {
-               /* More recent docs say that this bit is reserved ... */
-               n = inb(pioaddr + ConfigA) | 0x20;
-               outb(n, pioaddr + ConfigA);
-       } else {
-               n = inb(pioaddr + ConfigD) | 0x80;
-               outb(n, pioaddr + ConfigD);
+
+       if (quirks & rqNeedEnMMIO) {
+               if (quirks & rqRhineI) {
+                       /* More recent docs say that this bit is reserved */
+                       n = inb(pioaddr + ConfigA) | 0x20;
+                       outb(n, pioaddr + ConfigA);
+               } else {
+                       n = inb(pioaddr + ConfigD) | 0x80;
+                       outb(n, pioaddr + ConfigD);
+               }
        }
 }
-#endif
+
+static inline int verify_mmio(struct device *hwdev,
+                             long pioaddr,
+                             void __iomem *ioaddr,
+                             u32 quirks)
+{
+       if (quirks & rqNeedEnMMIO) {
+               int i = 0;
+
+               /* Check that selected MMIO registers match the PIO ones */
+               while (mmio_verify_registers[i]) {
+                       int reg = mmio_verify_registers[i++];
+                       unsigned char a = inb(pioaddr+reg);
+                       unsigned char b = readb(ioaddr+reg);
+
+                       if (a != b) {
+                               dev_err(hwdev,
+                                       "MMIO do not match PIO [%02x] (%02x != %02x)\n",
+                                       reg, a, b);
+                               return -EIO;
+                       }
+               }
+       }
+       return 0;
+}
 
 /*
  * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM
@@ -682,14 +718,12 @@ static void rhine_reload_eeprom(long pioaddr, struct net_device *dev)
        if (i > 512)
                pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__);
 
-#ifdef USE_MMIO
        /*
         * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable
         * MMIO. If reloading EEPROM was done first this could be avoided, but
         * it is not known if that still works with the "win98-reboot" problem.
         */
        enable_mmio(pioaddr, rp->quirks);
-#endif
 
        /* Turn off EEPROM-controlled wake-up (magic packet) */
        if (rp->quirks & rqWOL)
@@ -701,7 +735,7 @@ static void rhine_reload_eeprom(long pioaddr, struct net_device *dev)
 static void rhine_poll(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
-       const int irq = rp->pdev->irq;
+       const int irq = rp->irq;
 
        disable_irq(irq);
        rhine_interrupt(irq, dev);
@@ -846,7 +880,8 @@ static void rhine_hw_init(struct net_device *dev, long pioaddr)
                msleep(5);
 
        /* Reload EEPROM controlled bytes cleared by soft reset */
-       rhine_reload_eeprom(pioaddr, dev);
+       if (dev_is_pci(dev->dev.parent))
+               rhine_reload_eeprom(pioaddr, dev);
 }
 
 static const struct net_device_ops rhine_netdev_ops = {
@@ -867,125 +902,37 @@ static const struct net_device_ops rhine_netdev_ops = {
 #endif
 };
 
-static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int rhine_init_one_common(struct device *hwdev, u32 quirks,
+                                long pioaddr, void __iomem *ioaddr, int irq)
 {
        struct net_device *dev;
        struct rhine_private *rp;
-       int i, rc;
-       u32 quirks;
-       long pioaddr;
-       long memaddr;
-       void __iomem *ioaddr;
-       int io_size, phy_id;
+       int i, rc, phy_id;
        const char *name;
-#ifdef USE_MMIO
-       int bar = 1;
-#else
-       int bar = 0;
-#endif
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-       pr_info_once("%s\n", version);
-#endif
-
-       io_size = 256;
-       phy_id = 0;
-       quirks = 0;
-       name = "Rhine";
-       if (pdev->revision < VTunknown0) {
-               quirks = rqRhineI;
-               io_size = 128;
-       }
-       else if (pdev->revision >= VT6102) {
-               quirks = rqWOL | rqForceReset;
-               if (pdev->revision < VT6105) {
-                       name = "Rhine II";
-                       quirks |= rqStatusWBRace;       /* Rhine-II exclusive */
-               }
-               else {
-                       phy_id = 1;     /* Integrated PHY, phy_id fixed to 1 */
-                       if (pdev->revision >= VT6105_B0)
-                               quirks |= rq6patterns;
-                       if (pdev->revision < VT6105M)
-                               name = "Rhine III";
-                       else
-                               name = "Rhine III (Management Adapter)";
-               }
-       }
-
-       rc = pci_enable_device(pdev);
-       if (rc)
-               goto err_out;
 
        /* this should always be supported */
-       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       rc = dma_set_mask(hwdev, DMA_BIT_MASK(32));
        if (rc) {
-               dev_err(&pdev->dev,
-                       "32-bit PCI DMA addresses not supported by the card!?\n");
-               goto err_out_pci_disable;
-       }
-
-       /* sanity check */
-       if ((pci_resource_len(pdev, 0) < io_size) ||
-           (pci_resource_len(pdev, 1) < io_size)) {
-               rc = -EIO;
-               dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
-               goto err_out_pci_disable;
+               dev_err(hwdev, "32-bit DMA addresses not supported by the card!?\n");
+               goto err_out;
        }
 
-       pioaddr = pci_resource_start(pdev, 0);
-       memaddr = pci_resource_start(pdev, 1);
-
-       pci_set_master(pdev);
-
        dev = alloc_etherdev(sizeof(struct rhine_private));
        if (!dev) {
                rc = -ENOMEM;
-               goto err_out_pci_disable;
+               goto err_out;
        }
-       SET_NETDEV_DEV(dev, &pdev->dev);
+       SET_NETDEV_DEV(dev, hwdev);
 
        rp = netdev_priv(dev);
        rp->dev = dev;
        rp->quirks = quirks;
        rp->pioaddr = pioaddr;
-       rp->pdev = pdev;
+       rp->base = ioaddr;
+       rp->irq = irq;
        rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT);
 
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc)
-               goto err_out_free_netdev;
-
-       ioaddr = pci_iomap(pdev, bar, io_size);
-       if (!ioaddr) {
-               rc = -EIO;
-               dev_err(&pdev->dev,
-                       "ioremap failed for device %s, region 0x%X @ 0x%lX\n",
-                       pci_name(pdev), io_size, memaddr);
-               goto err_out_free_res;
-       }
-
-#ifdef USE_MMIO
-       enable_mmio(pioaddr, quirks);
-
-       /* Check that selected MMIO registers match the PIO ones */
-       i = 0;
-       while (mmio_verify_registers[i]) {
-               int reg = mmio_verify_registers[i++];
-               unsigned char a = inb(pioaddr+reg);
-               unsigned char b = readb(ioaddr+reg);
-               if (a != b) {
-                       rc = -EIO;
-                       dev_err(&pdev->dev,
-                               "MMIO do not match PIO [%02x] (%02x != %02x)\n",
-                               reg, a, b);
-                       goto err_out_unmap;
-               }
-       }
-#endif /* USE_MMIO */
-
-       rp->base = ioaddr;
+       phy_id = rp->quirks & rqIntPHY ? 1 : 0;
 
        u64_stats_init(&rp->tx_stats.syncp);
        u64_stats_init(&rp->rx_stats.syncp);
@@ -1030,7 +977,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rp->quirks & rqRhineI)
                dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
-       if (pdev->revision >= VT6105M)
+       if (rp->quirks & rqMgmt)
                dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
                                 NETIF_F_HW_VLAN_CTAG_RX |
                                 NETIF_F_HW_VLAN_CTAG_FILTER;
@@ -1038,18 +985,21 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* dev->name not defined before register_netdev()! */
        rc = register_netdev(dev);
        if (rc)
-               goto err_out_unmap;
+               goto err_out_free_netdev;
+
+       if (rp->quirks & rqRhineI)
+               name = "Rhine";
+       else if (rp->quirks & rqStatusWBRace)
+               name = "Rhine II";
+       else if (rp->quirks & rqMgmt)
+               name = "Rhine III (Management Adapter)";
+       else
+               name = "Rhine III";
 
        netdev_info(dev, "VIA %s at 0x%lx, %pM, IRQ %d\n",
-                   name,
-#ifdef USE_MMIO
-                   memaddr,
-#else
-                   (long)ioaddr,
-#endif
-                   dev->dev_addr, pdev->irq);
+                   name, (long)ioaddr, dev->dev_addr, rp->irq);
 
-       pci_set_drvdata(pdev, dev);
+       dev_set_drvdata(hwdev, dev);
 
        {
                u16 mii_cmd;
@@ -1078,41 +1028,158 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        return 0;
 
+err_out_free_netdev:
+       free_netdev(dev);
+err_out:
+       return rc;
+}
+
+static int rhine_init_one_pci(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
+{
+       struct device *hwdev = &pdev->dev;
+       int rc;
+       long pioaddr, memaddr;
+       void __iomem *ioaddr;
+       int io_size = pdev->revision < VTunknown0 ? 128 : 256;
+
+/* This driver was written to use PCI memory space. Some early versions
+ * of the Rhine may only work correctly with I/O space accesses.
+ * TODO: determine for which revisions this is true and assign the flag
+ *      in code as opposed to this Kconfig option (???)
+ */
+#ifdef CONFIG_VIA_RHINE_MMIO
+       u32 quirks = rqNeedEnMMIO;
+#else
+       u32 quirks = 0;
+#endif
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       pr_info_once("%s\n", version);
+#endif
+
+       rc = pci_enable_device(pdev);
+       if (rc)
+               goto err_out;
+
+       if (pdev->revision < VTunknown0) {
+               quirks |= rqRhineI;
+       } else if (pdev->revision >= VT6102) {
+               quirks |= rqWOL | rqForceReset;
+               if (pdev->revision < VT6105) {
+                       quirks |= rqStatusWBRace;
+               } else {
+                       quirks |= rqIntPHY;
+                       if (pdev->revision >= VT6105_B0)
+                               quirks |= rq6patterns;
+                       if (pdev->revision >= VT6105M)
+                               quirks |= rqMgmt;
+               }
+       }
+
+       /* sanity check */
+       if ((pci_resource_len(pdev, 0) < io_size) ||
+           (pci_resource_len(pdev, 1) < io_size)) {
+               rc = -EIO;
+               dev_err(hwdev, "Insufficient PCI resources, aborting\n");
+               goto err_out_pci_disable;
+       }
+
+       pioaddr = pci_resource_start(pdev, 0);
+       memaddr = pci_resource_start(pdev, 1);
+
+       pci_set_master(pdev);
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc)
+               goto err_out_pci_disable;
+
+       ioaddr = pci_iomap(pdev, (quirks & rqNeedEnMMIO ? 1 : 0), io_size);
+       if (!ioaddr) {
+               rc = -EIO;
+               dev_err(hwdev,
+                       "ioremap failed for device %s, region 0x%X @ 0x%lX\n",
+                       dev_name(hwdev), io_size, memaddr);
+               goto err_out_free_res;
+       }
+
+       enable_mmio(pioaddr, quirks);
+
+       rc = verify_mmio(hwdev, pioaddr, ioaddr, quirks);
+       if (rc)
+               goto err_out_unmap;
+
+       rc = rhine_init_one_common(&pdev->dev, quirks,
+                                  pioaddr, ioaddr, pdev->irq);
+       if (!rc)
+               return 0;
+
 err_out_unmap:
        pci_iounmap(pdev, ioaddr);
 err_out_free_res:
        pci_release_regions(pdev);
-err_out_free_netdev:
-       free_netdev(dev);
 err_out_pci_disable:
        pci_disable_device(pdev);
 err_out:
        return rc;
 }
 
+static int rhine_init_one_platform(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       const u32 *quirks;
+       int irq;
+       struct resource *res;
+       void __iomem *ioaddr;
+
+       match = of_match_device(rhine_of_tbl, &pdev->dev);
+       if (!match)
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ioaddr))
+               return PTR_ERR(ioaddr);
+
+       irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (!irq)
+               return -EINVAL;
+
+       quirks = match->data;
+       if (!quirks)
+               return -EINVAL;
+
+       return rhine_init_one_common(&pdev->dev, *quirks,
+                                    (long)ioaddr, ioaddr, irq);
+}
+
 static int alloc_ring(struct net_device* dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        void *ring;
        dma_addr_t ring_dma;
 
-       ring = pci_alloc_consistent(rp->pdev,
-                                   RX_RING_SIZE * sizeof(struct rx_desc) +
-                                   TX_RING_SIZE * sizeof(struct tx_desc),
-                                   &ring_dma);
+       ring = dma_alloc_coherent(hwdev,
+                                 RX_RING_SIZE * sizeof(struct rx_desc) +
+                                 TX_RING_SIZE * sizeof(struct tx_desc),
+                                 &ring_dma,
+                                 GFP_ATOMIC);
        if (!ring) {
                netdev_err(dev, "Could not allocate DMA memory\n");
                return -ENOMEM;
        }
        if (rp->quirks & rqRhineI) {
-               rp->tx_bufs = pci_alloc_consistent(rp->pdev,
-                                                  PKT_BUF_SZ * TX_RING_SIZE,
-                                                  &rp->tx_bufs_dma);
+               rp->tx_bufs = dma_alloc_coherent(hwdev,
+                                                PKT_BUF_SZ * TX_RING_SIZE,
+                                                &rp->tx_bufs_dma,
+                                                GFP_ATOMIC);
                if (rp->tx_bufs == NULL) {
-                       pci_free_consistent(rp->pdev,
-                                   RX_RING_SIZE * sizeof(struct rx_desc) +
-                                   TX_RING_SIZE * sizeof(struct tx_desc),
-                                   ring, ring_dma);
+                       dma_free_coherent(hwdev,
+                                         RX_RING_SIZE * sizeof(struct rx_desc) +
+                                         TX_RING_SIZE * sizeof(struct tx_desc),
+                                         ring, ring_dma);
                        return -ENOMEM;
                }
        }
@@ -1128,16 +1195,17 @@ static int alloc_ring(struct net_device* dev)
 static void free_ring(struct net_device* dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
 
-       pci_free_consistent(rp->pdev,
-                           RX_RING_SIZE * sizeof(struct rx_desc) +
-                           TX_RING_SIZE * sizeof(struct tx_desc),
-                           rp->rx_ring, rp->rx_ring_dma);
+       dma_free_coherent(hwdev,
+                         RX_RING_SIZE * sizeof(struct rx_desc) +
+                         TX_RING_SIZE * sizeof(struct tx_desc),
+                         rp->rx_ring, rp->rx_ring_dma);
        rp->tx_ring = NULL;
 
        if (rp->tx_bufs)
-               pci_free_consistent(rp->pdev, PKT_BUF_SZ * TX_RING_SIZE,
-                                   rp->tx_bufs, rp->tx_bufs_dma);
+               dma_free_coherent(hwdev, PKT_BUF_SZ * TX_RING_SIZE,
+                                 rp->tx_bufs, rp->tx_bufs_dma);
 
        rp->tx_bufs = NULL;
 
@@ -1146,6 +1214,7 @@ static void free_ring(struct net_device* dev)
 static void alloc_rbufs(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        dma_addr_t next;
        int i;
 
@@ -1174,9 +1243,9 @@ static void alloc_rbufs(struct net_device *dev)
                        break;
 
                rp->rx_skbuff_dma[i] =
-                       pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz,
-                                      PCI_DMA_FROMDEVICE);
-               if (dma_mapping_error(&rp->pdev->dev, rp->rx_skbuff_dma[i])) {
+                       dma_map_single(hwdev, skb->data, rp->rx_buf_sz,
+                                      DMA_FROM_DEVICE);
+               if (dma_mapping_error(hwdev, rp->rx_skbuff_dma[i])) {
                        rp->rx_skbuff_dma[i] = 0;
                        dev_kfree_skb(skb);
                        break;
@@ -1190,6 +1259,7 @@ static void alloc_rbufs(struct net_device *dev)
 static void free_rbufs(struct net_device* dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        int i;
 
        /* Free all the skbuffs in the Rx queue. */
@@ -1197,9 +1267,9 @@ static void free_rbufs(struct net_device* dev)
                rp->rx_ring[i].rx_status = 0;
                rp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
                if (rp->rx_skbuff[i]) {
-                       pci_unmap_single(rp->pdev,
+                       dma_unmap_single(hwdev,
                                         rp->rx_skbuff_dma[i],
-                                        rp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                                        rp->rx_buf_sz, DMA_FROM_DEVICE);
                        dev_kfree_skb(rp->rx_skbuff[i]);
                }
                rp->rx_skbuff[i] = NULL;
@@ -1230,6 +1300,7 @@ static void alloc_tbufs(struct net_device* dev)
 static void free_tbufs(struct net_device* dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        int i;
 
        for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1238,10 +1309,10 @@ static void free_tbufs(struct net_device* dev)
                rp->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
                if (rp->tx_skbuff[i]) {
                        if (rp->tx_skbuff_dma[i]) {
-                               pci_unmap_single(rp->pdev,
+                               dma_unmap_single(hwdev,
                                                 rp->tx_skbuff_dma[i],
                                                 rp->tx_skbuff[i]->len,
-                                                PCI_DMA_TODEVICE);
+                                                DMA_TO_DEVICE);
                        }
                        dev_kfree_skb(rp->tx_skbuff[i]);
                }
@@ -1469,7 +1540,7 @@ static void init_registers(struct net_device *dev)
 
        rhine_set_rx_mode(dev);
 
-       if (rp->pdev->revision >= VT6105M)
+       if (rp->quirks & rqMgmt)
                rhine_init_cam_filter(dev);
 
        napi_enable(&rp->napi);
@@ -1581,16 +1652,15 @@ static int rhine_open(struct net_device *dev)
        void __iomem *ioaddr = rp->base;
        int rc;
 
-       rc = request_irq(rp->pdev->irq, rhine_interrupt, IRQF_SHARED, dev->name,
-                       dev);
+       rc = request_irq(rp->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev);
        if (rc)
                return rc;
 
-       netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->pdev->irq);
+       netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->irq);
 
        rc = alloc_ring(dev);
        if (rc) {
-               free_irq(rp->pdev->irq, dev);
+               free_irq(rp->irq, dev);
                return rc;
        }
        alloc_rbufs(dev);
@@ -1659,6 +1729,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                                  struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        void __iomem *ioaddr = rp->base;
        unsigned entry;
 
@@ -1695,9 +1766,9 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                                                       rp->tx_bufs));
        } else {
                rp->tx_skbuff_dma[entry] =
-                       pci_map_single(rp->pdev, skb->data, skb->len,
-                                      PCI_DMA_TODEVICE);
-               if (dma_mapping_error(&rp->pdev->dev, rp->tx_skbuff_dma[entry])) {
+                       dma_map_single(hwdev, skb->data, skb->len,
+                                      DMA_TO_DEVICE);
+               if (dma_mapping_error(hwdev, rp->tx_skbuff_dma[entry])) {
                        dev_kfree_skb_any(skb);
                        rp->tx_skbuff_dma[entry] = 0;
                        dev->stats.tx_dropped++;
@@ -1788,6 +1859,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
 static void rhine_tx(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
 
        /* find and cleanup dirty tx descriptors */
@@ -1831,10 +1903,10 @@ static void rhine_tx(struct net_device *dev)
                }
                /* Free the original skb. */
                if (rp->tx_skbuff_dma[entry]) {
-                       pci_unmap_single(rp->pdev,
+                       dma_unmap_single(hwdev,
                                         rp->tx_skbuff_dma[entry],
                                         rp->tx_skbuff[entry]->len,
-                                        PCI_DMA_TODEVICE);
+                                        DMA_TO_DEVICE);
                }
                dev_consume_skb_any(rp->tx_skbuff[entry]);
                rp->tx_skbuff[entry] = NULL;
@@ -1863,6 +1935,7 @@ static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
 static int rhine_rx(struct net_device *dev, int limit)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
        int count;
        int entry = rp->cur_rx % RX_RING_SIZE;
 
@@ -1924,19 +1997,19 @@ static int rhine_rx(struct net_device *dev, int limit)
                        if (pkt_len < rx_copybreak)
                                skb = netdev_alloc_skb_ip_align(dev, pkt_len);
                        if (skb) {
-                               pci_dma_sync_single_for_cpu(rp->pdev,
-                                                           rp->rx_skbuff_dma[entry],
-                                                           rp->rx_buf_sz,
-                                                           PCI_DMA_FROMDEVICE);
+                               dma_sync_single_for_cpu(hwdev,
+                                                       rp->rx_skbuff_dma[entry],
+                                                       rp->rx_buf_sz,
+                                                       DMA_FROM_DEVICE);
 
                                skb_copy_to_linear_data(skb,
                                                 rp->rx_skbuff[entry]->data,
                                                 pkt_len);
                                skb_put(skb, pkt_len);
-                               pci_dma_sync_single_for_device(rp->pdev,
-                                                              rp->rx_skbuff_dma[entry],
-                                                              rp->rx_buf_sz,
-                                                              PCI_DMA_FROMDEVICE);
+                               dma_sync_single_for_device(hwdev,
+                                                          rp->rx_skbuff_dma[entry],
+                                                          rp->rx_buf_sz,
+                                                          DMA_FROM_DEVICE);
                        } else {
                                skb = rp->rx_skbuff[entry];
                                if (skb == NULL) {
@@ -1945,10 +2018,10 @@ static int rhine_rx(struct net_device *dev, int limit)
                                }
                                rp->rx_skbuff[entry] = NULL;
                                skb_put(skb, pkt_len);
-                               pci_unmap_single(rp->pdev,
+                               dma_unmap_single(hwdev,
                                                 rp->rx_skbuff_dma[entry],
                                                 rp->rx_buf_sz,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        }
 
                        if (unlikely(desc_length & DescTag))
@@ -1979,10 +2052,11 @@ static int rhine_rx(struct net_device *dev, int limit)
                        if (skb == NULL)
                                break;  /* Better luck next round. */
                        rp->rx_skbuff_dma[entry] =
-                               pci_map_single(rp->pdev, skb->data,
+                               dma_map_single(hwdev, skb->data,
                                               rp->rx_buf_sz,
-                                              PCI_DMA_FROMDEVICE);
-                       if (dma_mapping_error(&rp->pdev->dev, rp->rx_skbuff_dma[entry])) {
+                                              DMA_FROM_DEVICE);
+                       if (dma_mapping_error(hwdev,
+                                             rp->rx_skbuff_dma[entry])) {
                                dev_kfree_skb(skb);
                                rp->rx_skbuff_dma[entry] = 0;
                                break;
@@ -2103,7 +2177,7 @@ static void rhine_set_rx_mode(struct net_device *dev)
                /* Too many to match, or accept all multicasts. */
                iowrite32(0xffffffff, ioaddr + MulticastFilter0);
                iowrite32(0xffffffff, ioaddr + MulticastFilter1);
-       } else if (rp->pdev->revision >= VT6105M) {
+       } else if (rp->quirks & rqMgmt) {
                int i = 0;
                u32 mCAMmask = 0;       /* 32 mCAMs (6105M and better) */
                netdev_for_each_mc_addr(ha, dev) {
@@ -2125,7 +2199,7 @@ static void rhine_set_rx_mode(struct net_device *dev)
                iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
        }
        /* enable/disable VLAN receive filtering */
-       if (rp->pdev->revision >= VT6105M) {
+       if (rp->quirks & rqMgmt) {
                if (dev->flags & IFF_PROMISC)
                        BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
                else
@@ -2136,11 +2210,11 @@ static void rhine_set_rx_mode(struct net_device *dev)
 
 static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct rhine_private *rp = netdev_priv(dev);
+       struct device *hwdev = dev->dev.parent;
 
        strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-       strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
+       strlcpy(info->bus_info, dev_name(hwdev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -2277,7 +2351,7 @@ static int rhine_close(struct net_device *dev)
        /* Stop the chip's Tx and Rx processes. */
        iowrite16(CmdStop, ioaddr + ChipCmd);
 
-       free_irq(rp->pdev->irq, dev);
+       free_irq(rp->irq, dev);
        free_rbufs(dev);
        free_tbufs(dev);
        free_ring(dev);
@@ -2286,7 +2360,7 @@ static int rhine_close(struct net_device *dev)
 }
 
 
-static void rhine_remove_one(struct pci_dev *pdev)
+static void rhine_remove_one_pci(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
@@ -2300,7 +2374,21 @@ static void rhine_remove_one(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static void rhine_shutdown (struct pci_dev *pdev)
+static int rhine_remove_one_platform(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct rhine_private *rp = netdev_priv(dev);
+
+       unregister_netdev(dev);
+
+       iounmap(rp->base);
+
+       free_netdev(dev);
+
+       return 0;
+}
+
+static void rhine_shutdown_pci(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
@@ -2354,8 +2442,7 @@ static void rhine_shutdown (struct pci_dev *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int rhine_suspend(struct device *device)
 {
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct net_device *dev = pci_get_drvdata(pdev);
+       struct net_device *dev = dev_get_drvdata(device);
        struct rhine_private *rp = netdev_priv(dev);
 
        if (!netif_running(dev))
@@ -2367,23 +2454,21 @@ static int rhine_suspend(struct device *device)
 
        netif_device_detach(dev);
 
-       rhine_shutdown(pdev);
+       if (dev_is_pci(device))
+               rhine_shutdown_pci(to_pci_dev(device));
 
        return 0;
 }
 
 static int rhine_resume(struct device *device)
 {
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct net_device *dev = pci_get_drvdata(pdev);
+       struct net_device *dev = dev_get_drvdata(device);
        struct rhine_private *rp = netdev_priv(dev);
 
        if (!netif_running(dev))
                return 0;
 
-#ifdef USE_MMIO
        enable_mmio(rp->pioaddr, rp->quirks);
-#endif
        rhine_power_init(dev);
        free_tbufs(dev);
        free_rbufs(dev);
@@ -2408,15 +2493,26 @@ static SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume);
 
 #endif /* !CONFIG_PM_SLEEP */
 
-static struct pci_driver rhine_driver = {
+static struct pci_driver rhine_driver_pci = {
        .name           = DRV_NAME,
        .id_table       = rhine_pci_tbl,
-       .probe          = rhine_init_one,
-       .remove         = rhine_remove_one,
-       .shutdown       = rhine_shutdown,
+       .probe          = rhine_init_one_pci,
+       .remove         = rhine_remove_one_pci,
+       .shutdown       = rhine_shutdown_pci,
        .driver.pm      = RHINE_PM_OPS,
 };
 
+static struct platform_driver rhine_driver_platform = {
+       .probe          = rhine_init_one_platform,
+       .remove         = rhine_remove_one_platform,
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = rhine_of_tbl,
+               .pm             = RHINE_PM_OPS,
+       }
+};
+
 static struct dmi_system_id rhine_dmi_table[] __initdata = {
        {
                .ident = "EPIA-M",
@@ -2437,6 +2533,8 @@ static struct dmi_system_id rhine_dmi_table[] __initdata = {
 
 static int __init rhine_init(void)
 {
+       int ret_pci, ret_platform;
+
 /* when a module, this is printed whether or not devices are found in probe */
 #ifdef MODULE
        pr_info("%s\n", version);
@@ -2449,13 +2547,19 @@ static int __init rhine_init(void)
        else if (avoid_D3)
                pr_info("avoid_D3 set\n");
 
-       return pci_register_driver(&rhine_driver);
+       ret_pci = pci_register_driver(&rhine_driver_pci);
+       ret_platform = platform_driver_register(&rhine_driver_platform);
+       if ((ret_pci < 0) && (ret_platform < 0))
+               return ret_pci;
+
+       return 0;
 }
 
 
 static void __exit rhine_cleanup(void)
 {
-       pci_unregister_driver(&rhine_driver);
+       platform_driver_unregister(&rhine_driver_platform);
+       pci_unregister_driver(&rhine_driver_pci);
 }
 
 
index d18f711d0b0cd45ae50cc30cc09a9468d4e40d22..4b7df5a5c966a619a988a37894606e4673c5a6bd 100644 (file)
 #include <linux/hyperv.h>
 #include <linux/rndis.h>
 
-/* Fwd declaration */
-struct hv_netvsc_packet;
-struct ndis_tcp_ip_checksum_info;
+/* RSS related */
+#define OID_GEN_RECEIVE_SCALE_CAPABILITIES 0x00010203  /* query only */
+#define OID_GEN_RECEIVE_SCALE_PARAMETERS 0x00010204  /* query and set */
 
-/* Represent the xfer page packet which contains 1 or more netvsc packet */
-struct xferpage_packet {
-       struct list_head list_ent;
-       u32 status;
+#define NDIS_OBJECT_TYPE_RSS_CAPABILITIES 0x88
+#define NDIS_OBJECT_TYPE_RSS_PARAMETERS 0x89
 
-       /* # of netvsc packets this xfer packet contains */
-       u32 count;
+#define NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2 2
+#define NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2 2
+
+struct ndis_obj_header {
+       u8 type;
+       u8 rev;
+       u16 size;
+} __packed;
+
+/* ndis_recv_scale_cap/cap_flag */
+#define NDIS_RSS_CAPS_MESSAGE_SIGNALED_INTERRUPTS 0x01000000
+#define NDIS_RSS_CAPS_CLASSIFICATION_AT_ISR       0x02000000
+#define NDIS_RSS_CAPS_CLASSIFICATION_AT_DPC       0x04000000
+#define NDIS_RSS_CAPS_USING_MSI_X                 0x08000000
+#define NDIS_RSS_CAPS_RSS_AVAILABLE_ON_PORTS      0x10000000
+#define NDIS_RSS_CAPS_SUPPORTS_MSI_X              0x20000000
+#define NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV4          0x00000100
+#define NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6          0x00000200
+#define NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6_EX       0x00000400
+
+struct ndis_recv_scale_cap { /* NDIS_RECEIVE_SCALE_CAPABILITIES */
+       struct ndis_obj_header hdr;
+       u32 cap_flag;
+       u32 num_int_msg;
+       u32 num_recv_que;
+       u16 num_indirect_tabent;
+} __packed;
+
+
+/* ndis_recv_scale_param flags */
+#define NDIS_RSS_PARAM_FLAG_BASE_CPU_UNCHANGED     0x0001
+#define NDIS_RSS_PARAM_FLAG_HASH_INFO_UNCHANGED    0x0002
+#define NDIS_RSS_PARAM_FLAG_ITABLE_UNCHANGED       0x0004
+#define NDIS_RSS_PARAM_FLAG_HASH_KEY_UNCHANGED     0x0008
+#define NDIS_RSS_PARAM_FLAG_DISABLE_RSS            0x0010
+
+/* Hash info bits */
+#define NDIS_HASH_FUNC_TOEPLITZ 0x00000001
+#define NDIS_HASH_IPV4          0x00000100
+#define NDIS_HASH_TCP_IPV4      0x00000200
+#define NDIS_HASH_IPV6          0x00000400
+#define NDIS_HASH_IPV6_EX       0x00000800
+#define NDIS_HASH_TCP_IPV6      0x00001000
+#define NDIS_HASH_TCP_IPV6_EX   0x00002000
+
+#define NDIS_RSS_INDIRECTION_TABLE_MAX_SIZE_REVISION_2 (128 * 4)
+#define NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2   40
+
+#define ITAB_NUM 128
+#define HASH_KEYLEN NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2
+extern u8 netvsc_hash_key[];
+
+struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */
+       struct ndis_obj_header hdr;
+
+       /* Qualifies the rest of the information */
+       u16 flag;
+
+       /* The base CPU number to do receive processing. not used */
+       u16 base_cpu_number;
+
+       /* This describes the hash function and type being enabled */
+       u32 hashinfo;
+
+       /* The size of indirection table array */
+       u16 indirect_tabsize;
+
+       /* The offset of the indirection table from the beginning of this
+        * structure
+        */
+       u32 indirect_taboffset;
+
+       /* The size of the hash secret key */
+       u16 hashkey_size;
+
+       /* The offset of the secret key from the beginning of this structure */
+       u32 kashkey_offset;
+
+       u32 processor_masks_offset;
+       u32 num_processor_masks;
+       u32 processor_masks_entry_size;
 };
 
+/* Fwd declaration */
+struct ndis_tcp_ip_checksum_info;
+
 /*
  * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
  * within the RNDIS
  */
 struct hv_netvsc_packet {
        /* Bookkeeping stuff */
-       struct list_head list_ent;
        u32 status;
 
        struct hv_device *device;
        bool is_data_pkt;
        u16 vlan_tci;
 
-       /*
-        * Valid only for receives when we break a xfer page packet
-        * into multiple netvsc packets
-        */
-       struct xferpage_packet *xfer_page_pkt;
+       u16 q_idx;
+       struct vmbus_channel *channel;
 
-       union {
-               struct {
-                       u64 recv_completion_tid;
-                       void *recv_completion_ctx;
-                       void (*recv_completion)(void *context);
-               } recv;
-               struct {
-                       u64 send_completion_tid;
-                       void *send_completion_ctx;
-                       void (*send_completion)(void *context);
-               } send;
-       } completion;
+       u64 send_completion_tid;
+       void *send_completion_ctx;
+       void (*send_completion)(void *context);
+
+       u32 send_buf_index;
 
        /* This points to the memory after page_buf */
        struct rndis_message *rndis_msg;
@@ -120,6 +189,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
 int netvsc_recv_callback(struct hv_device *device_obj,
                        struct hv_netvsc_packet *packet,
                        struct ndis_tcp_ip_checksum_info *csum_info);
+void netvsc_channel_cb(void *context);
 int rndis_filter_open(struct hv_device *dev);
 int rndis_filter_close(struct hv_device *dev);
 int rndis_filter_device_add(struct hv_device *dev,
@@ -514,14 +584,16 @@ struct nvsp_message {
 
 #define NETVSC_RECEIVE_BUFFER_SIZE             (1024*1024*16)  /* 16MB */
 #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY      (1024*1024*15)  /* 15MB */
+#define NETVSC_SEND_BUFFER_SIZE                        (1024 * 1024)   /* 1MB */
+#define NETVSC_INVALID_INDEX                   -1
 
-#define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
-/* Preallocated receive packets */
-#define NETVSC_RECEIVE_PACKETLIST_COUNT                256
+#define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
 #define NETVSC_PACKET_SIZE                      2048
 
+#define VRSS_SEND_TAB_SIZE 16
+
 /* Per netvsc channel-specific */
 struct netvsc_device {
        struct hv_device *dev;
@@ -532,12 +604,6 @@ struct netvsc_device {
        wait_queue_head_t wait_drain;
        bool start_remove;
        bool destroy;
-       /*
-        * List of free preallocated hv_netvsc_packet to represent receive
-        * packet
-        */
-       struct list_head recv_pkt_list;
-       spinlock_t recv_pkt_list_lock;
 
        /* Receive buffer allocated by us but manages by NetVSP */
        void *recv_buf;
@@ -546,6 +612,15 @@ struct netvsc_device {
        u32 recv_section_cnt;
        struct nvsp_1_receive_buffer_section *recv_section;
 
+       /* Send buffer allocated by us */
+       void *send_buf;
+       u32 send_buf_size;
+       u32 send_buf_gpadl_handle;
+       u32 send_section_cnt;
+       u32 send_section_size;
+       unsigned long *send_section_map;
+       int map_words;
+
        /* Used for NetVSP initialization protocol */
        struct completion channel_init_wait;
        struct nvsp_message channel_init_pkt;
@@ -555,10 +630,20 @@ struct netvsc_device {
 
        struct net_device *ndev;
 
+       struct vmbus_channel *chn_table[NR_CPUS];
+       u32 send_table[VRSS_SEND_TAB_SIZE];
+       u32 num_chn;
+       atomic_t queue_sends[NR_CPUS];
+
        /* Holds rndis device info */
        void *extension;
-       /* The recive buffer for this device */
+
+       int ring_size;
+
+       /* The primary channel callback buffer */
        unsigned char cb_buffer[NETVSC_PACKET_SIZE];
+       /* The sub channel callback buffer */
+       unsigned char *sub_cb_buf;
 };
 
 /* NdisInitialize message */
index f7629ecefa84a6d9c2d1cbb7b308a3d46a359915..c041f63a6d3053f51d5e3f6651bc1db0d0d6d25c 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/if_ether.h>
+#include <asm/sync_bitops.h>
 
 #include "hyperv_net.h"
 
@@ -80,7 +81,7 @@ get_in_err:
 }
 
 
-static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
+static int netvsc_destroy_buf(struct netvsc_device *net_device)
 {
        struct nvsp_message *revoke_packet;
        int ret = 0;
@@ -146,10 +147,62 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
                net_device->recv_section = NULL;
        }
 
+       /* Deal with the send buffer we may have setup.
+        * If we got a  send section size, it means we received a
+        * SendsendBufferComplete msg (ie sent
+        * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
+        * to send a revoke msg here
+        */
+       if (net_device->send_section_size) {
+               /* Send the revoke receive buffer */
+               revoke_packet = &net_device->revoke_packet;
+               memset(revoke_packet, 0, sizeof(struct nvsp_message));
+
+               revoke_packet->hdr.msg_type =
+                       NVSP_MSG1_TYPE_REVOKE_SEND_BUF;
+               revoke_packet->msg.v1_msg.revoke_recv_buf.id = 0;
+
+               ret = vmbus_sendpacket(net_device->dev->channel,
+                                      revoke_packet,
+                                      sizeof(struct nvsp_message),
+                                      (unsigned long)revoke_packet,
+                                      VM_PKT_DATA_INBAND, 0);
+               /* If we failed here, we might as well return and
+                * have a leak rather than continue and a bugchk
+                */
+               if (ret != 0) {
+                       netdev_err(ndev, "unable to send "
+                                  "revoke send buffer to netvsp\n");
+                       return ret;
+               }
+       }
+       /* Teardown the gpadl on the vsp end */
+       if (net_device->send_buf_gpadl_handle) {
+               ret = vmbus_teardown_gpadl(net_device->dev->channel,
+                                          net_device->send_buf_gpadl_handle);
+
+               /* If we failed here, we might as well return and have a leak
+                * rather than continue and a bugchk
+                */
+               if (ret != 0) {
+                       netdev_err(ndev,
+                                  "unable to teardown send buffer's gpadl\n");
+                       return ret;
+               }
+               net_device->recv_buf_gpadl_handle = 0;
+       }
+       if (net_device->send_buf) {
+               /* Free up the receive buffer */
+               free_pages((unsigned long)net_device->send_buf,
+                          get_order(net_device->send_buf_size));
+               net_device->send_buf = NULL;
+       }
+       kfree(net_device->send_section_map);
+
        return ret;
 }
 
-static int netvsc_init_recv_buf(struct hv_device *device)
+static int netvsc_init_buf(struct hv_device *device)
 {
        int ret = 0;
        int t;
@@ -248,10 +301,90 @@ static int netvsc_init_recv_buf(struct hv_device *device)
                goto cleanup;
        }
 
+       /* Now setup the send buffer.
+        */
+       net_device->send_buf =
+               (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
+                                        get_order(net_device->send_buf_size));
+       if (!net_device->send_buf) {
+               netdev_err(ndev, "unable to allocate send "
+                          "buffer of size %d\n", net_device->send_buf_size);
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       /* Establish the gpadl handle for this buffer on this
+        * channel.  Note: This call uses the vmbus connection rather
+        * than the channel to establish the gpadl handle.
+        */
+       ret = vmbus_establish_gpadl(device->channel, net_device->send_buf,
+                                   net_device->send_buf_size,
+                                   &net_device->send_buf_gpadl_handle);
+       if (ret != 0) {
+               netdev_err(ndev,
+                          "unable to establish send buffer's gpadl\n");
+               goto cleanup;
+       }
+
+       /* Notify the NetVsp of the gpadl handle */
+       init_packet = &net_device->channel_init_pkt;
+       memset(init_packet, 0, sizeof(struct nvsp_message));
+       init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF;
+       init_packet->msg.v1_msg.send_recv_buf.gpadl_handle =
+               net_device->send_buf_gpadl_handle;
+       init_packet->msg.v1_msg.send_recv_buf.id = 0;
+
+       /* Send the gpadl notification request */
+       ret = vmbus_sendpacket(device->channel, init_packet,
+                              sizeof(struct nvsp_message),
+                              (unsigned long)init_packet,
+                              VM_PKT_DATA_INBAND,
+                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+       if (ret != 0) {
+               netdev_err(ndev,
+                          "unable to send send buffer's gpadl to netvsp\n");
+               goto cleanup;
+       }
+
+       t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
+       BUG_ON(t == 0);
+
+       /* Check the response */
+       if (init_packet->msg.v1_msg.
+           send_send_buf_complete.status != NVSP_STAT_SUCCESS) {
+               netdev_err(ndev, "Unable to complete send buffer "
+                          "initialization with NetVsp - status %d\n",
+                          init_packet->msg.v1_msg.
+                          send_recv_buf_complete.status);
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       /* Parse the response */
+       net_device->send_section_size = init_packet->msg.
+                               v1_msg.send_send_buf_complete.section_size;
+
+       /* Section count is simply the size divided by the section size.
+        */
+       net_device->send_section_cnt =
+               net_device->send_buf_size/net_device->send_section_size;
+
+       dev_info(&device->device, "Send section size: %d, Section count:%d\n",
+                net_device->send_section_size, net_device->send_section_cnt);
+
+       /* Setup state for managing the send buffer. */
+       net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt,
+                                            BITS_PER_LONG);
+
+       net_device->send_section_map =
+               kzalloc(net_device->map_words * sizeof(ulong), GFP_KERNEL);
+       if (net_device->send_section_map == NULL)
+               goto cleanup;
+
        goto exit;
 
 cleanup:
-       netvsc_destroy_recv_buf(net_device);
+       netvsc_destroy_buf(net_device);
 
 exit:
        return ret;
@@ -369,8 +502,9 @@ static int netvsc_connect_vsp(struct hv_device *device)
                net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
        else
                net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+       net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
 
-       ret = netvsc_init_recv_buf(device);
+       ret = netvsc_init_buf(device);
 
 cleanup:
        return ret;
@@ -378,7 +512,7 @@ cleanup:
 
 static void netvsc_disconnect_vsp(struct netvsc_device *net_device)
 {
-       netvsc_destroy_recv_buf(net_device);
+       netvsc_destroy_buf(net_device);
 }
 
 /*
@@ -387,7 +521,6 @@ static void netvsc_disconnect_vsp(struct netvsc_device *net_device)
 int netvsc_device_remove(struct hv_device *device)
 {
        struct netvsc_device *net_device;
-       struct hv_netvsc_packet *netvsc_packet, *pos;
        unsigned long flags;
 
        net_device = hv_get_drvdata(device);
@@ -416,11 +549,8 @@ int netvsc_device_remove(struct hv_device *device)
        vmbus_close(device->channel);
 
        /* Release all resources */
-       list_for_each_entry_safe(netvsc_packet, pos,
-                                &net_device->recv_pkt_list, list_ent) {
-               list_del(&netvsc_packet->list_ent);
-               kfree(netvsc_packet);
-       }
+       if (net_device->sub_cb_buf)
+               vfree(net_device->sub_cb_buf);
 
        kfree(net_device);
        return 0;
@@ -444,6 +574,12 @@ static inline u32 hv_ringbuf_avail_percent(
        return avail_write * 100 / ring_info->ring_datasize;
 }
 
+static inline void netvsc_free_send_slot(struct netvsc_device *net_device,
+                                        u32 index)
+{
+       sync_change_bit(index, net_device->send_section_map);
+}
+
 static void netvsc_send_completion(struct netvsc_device *net_device,
                                   struct hv_device *device,
                                   struct vmpacket_descriptor *packet)
@@ -451,6 +587,7 @@ static void netvsc_send_completion(struct netvsc_device *net_device,
        struct nvsp_message *nvsp_packet;
        struct hv_netvsc_packet *nvsc_packet;
        struct net_device *ndev;
+       u32 send_index;
 
        ndev = net_device->ndev;
 
@@ -461,7 +598,9 @@ static void netvsc_send_completion(struct netvsc_device *net_device,
            (nvsp_packet->hdr.msg_type ==
             NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
            (nvsp_packet->hdr.msg_type ==
-            NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE)) {
+            NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE) ||
+           (nvsp_packet->hdr.msg_type ==
+            NVSP_MSG5_TYPE_SUBCHANNEL)) {
                /* Copy the response back */
                memcpy(&net_device->channel_init_pkt, nvsp_packet,
                       sizeof(struct nvsp_message));
@@ -469,28 +608,39 @@ static void netvsc_send_completion(struct netvsc_device *net_device,
        } else if (nvsp_packet->hdr.msg_type ==
                   NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
                int num_outstanding_sends;
+               u16 q_idx = 0;
+               struct vmbus_channel *channel = device->channel;
+               int queue_sends;
 
                /* Get the send context */
                nvsc_packet = (struct hv_netvsc_packet *)(unsigned long)
                        packet->trans_id;
 
                /* Notify the layer above us */
-               if (nvsc_packet)
-                       nvsc_packet->completion.send.send_completion(
-                               nvsc_packet->completion.send.
-                               send_completion_ctx);
+               if (nvsc_packet) {
+                       send_index = nvsc_packet->send_buf_index;
+                       if (send_index != NETVSC_INVALID_INDEX)
+                               netvsc_free_send_slot(net_device, send_index);
+                       q_idx = nvsc_packet->q_idx;
+                       channel = nvsc_packet->channel;
+                       nvsc_packet->send_completion(nvsc_packet->
+                                                    send_completion_ctx);
+               }
 
                num_outstanding_sends =
                        atomic_dec_return(&net_device->num_outstanding_sends);
+               queue_sends = atomic_dec_return(&net_device->
+                                               queue_sends[q_idx]);
 
                if (net_device->destroy && num_outstanding_sends == 0)
                        wake_up(&net_device->wait_drain);
 
-               if (netif_queue_stopped(ndev) && !net_device->start_remove &&
-                       (hv_ringbuf_avail_percent(&device->channel->outbound)
-                       > RING_AVAIL_PERCENT_HIWATER ||
-                       num_outstanding_sends < 1))
-                               netif_wake_queue(ndev);
+               if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
+                   !net_device->start_remove &&
+                   (hv_ringbuf_avail_percent(&channel->outbound) >
+                    RING_AVAIL_PERCENT_HIWATER || queue_sends < 1))
+                               netif_tx_wake_queue(netdev_get_tx_queue(
+                                                   ndev, q_idx));
        } else {
                netdev_err(ndev, "Unknown send completion packet type- "
                           "%d received!!\n", nvsp_packet->hdr.msg_type);
@@ -498,6 +648,52 @@ static void netvsc_send_completion(struct netvsc_device *net_device,
 
 }
 
+static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
+{
+       unsigned long index;
+       u32 max_words = net_device->map_words;
+       unsigned long *map_addr = (unsigned long *)net_device->send_section_map;
+       u32 section_cnt = net_device->send_section_cnt;
+       int ret_val = NETVSC_INVALID_INDEX;
+       int i;
+       int prev_val;
+
+       for (i = 0; i < max_words; i++) {
+               if (!~(map_addr[i]))
+                       continue;
+               index = ffz(map_addr[i]);
+               prev_val = sync_test_and_set_bit(index, &map_addr[i]);
+               if (prev_val)
+                       continue;
+               if ((index + (i * BITS_PER_LONG)) >= section_cnt)
+                       break;
+               ret_val = (index + (i * BITS_PER_LONG));
+               break;
+       }
+       return ret_val;
+}
+
+u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
+                           unsigned int section_index,
+                           struct hv_netvsc_packet *packet)
+{
+       char *start = net_device->send_buf;
+       char *dest = (start + (section_index * net_device->send_section_size));
+       int i;
+       u32 msg_size = 0;
+
+       for (i = 0; i < packet->page_buf_cnt; i++) {
+               char *src = phys_to_virt(packet->page_buf[i].pfn << PAGE_SHIFT);
+               u32 offset = packet->page_buf[i].offset;
+               u32 len = packet->page_buf[i].len;
+
+               memcpy(dest, (src + offset), len);
+               msg_size += len;
+               dest += len;
+       }
+       return msg_size;
+}
+
 int netvsc_send(struct hv_device *device,
                        struct hv_netvsc_packet *packet)
 {
@@ -505,7 +701,12 @@ int netvsc_send(struct hv_device *device,
        int ret = 0;
        struct nvsp_message sendMessage;
        struct net_device *ndev;
+       struct vmbus_channel *out_channel = NULL;
        u64 req_id;
+       unsigned int section_index = NETVSC_INVALID_INDEX;
+       u32 msg_size = 0;
+       struct sk_buff *skb;
+
 
        net_device = get_outbound_net_device(device);
        if (!net_device)
@@ -521,25 +722,46 @@ int netvsc_send(struct hv_device *device,
                sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 1;
        }
 
-       /* Not using send buffer section */
+       /* Attempt to send via sendbuf */
+       if (packet->total_data_buflen < net_device->send_section_size) {
+               section_index = netvsc_get_next_send_section(net_device);
+               if (section_index != NETVSC_INVALID_INDEX) {
+                       msg_size = netvsc_copy_to_send_buf(net_device,
+                                                          section_index,
+                                                          packet);
+                       skb = (struct sk_buff *)
+                             (unsigned long)packet->send_completion_tid;
+                       if (skb)
+                               dev_kfree_skb_any(skb);
+                       packet->page_buf_cnt = 0;
+               }
+       }
+       packet->send_buf_index = section_index;
+
+
        sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_index =
-               0xFFFFFFFF;
-       sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0;
+               section_index;
+       sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = msg_size;
 
-       if (packet->completion.send.send_completion)
+       if (packet->send_completion)
                req_id = (ulong)packet;
        else
                req_id = 0;
 
+       out_channel = net_device->chn_table[packet->q_idx];
+       if (out_channel == NULL)
+               out_channel = device->channel;
+       packet->channel = out_channel;
+
        if (packet->page_buf_cnt) {
-               ret = vmbus_sendpacket_pagebuffer(device->channel,
+               ret = vmbus_sendpacket_pagebuffer(out_channel,
                                                  packet->page_buf,
                                                  packet->page_buf_cnt,
                                                  &sendMessage,
                                                  sizeof(struct nvsp_message),
                                                  req_id);
        } else {
-               ret = vmbus_sendpacket(device->channel, &sendMessage,
+               ret = vmbus_sendpacket(out_channel, &sendMessage,
                                sizeof(struct nvsp_message),
                                req_id,
                                VM_PKT_DATA_INBAND,
@@ -548,17 +770,24 @@ int netvsc_send(struct hv_device *device,
 
        if (ret == 0) {
                atomic_inc(&net_device->num_outstanding_sends);
-               if (hv_ringbuf_avail_percent(&device->channel->outbound) <
+               atomic_inc(&net_device->queue_sends[packet->q_idx]);
+
+               if (hv_ringbuf_avail_percent(&out_channel->outbound) <
                        RING_AVAIL_PERCENT_LOWATER) {
-                       netif_stop_queue(ndev);
+                       netif_tx_stop_queue(netdev_get_tx_queue(
+                                           ndev, packet->q_idx));
+
                        if (atomic_read(&net_device->
-                               num_outstanding_sends) < 1)
-                               netif_wake_queue(ndev);
+                               queue_sends[packet->q_idx]) < 1)
+                               netif_tx_wake_queue(netdev_get_tx_queue(
+                                                   ndev, packet->q_idx));
                }
        } else if (ret == -EAGAIN) {
-               netif_stop_queue(ndev);
-               if (atomic_read(&net_device->num_outstanding_sends) < 1) {
-                       netif_wake_queue(ndev);
+               netif_tx_stop_queue(netdev_get_tx_queue(
+                                   ndev, packet->q_idx));
+               if (atomic_read(&net_device->queue_sends[packet->q_idx]) < 1) {
+                       netif_tx_wake_queue(netdev_get_tx_queue(
+                                           ndev, packet->q_idx));
                        ret = -ENOSPC;
                }
        } else {
@@ -570,6 +799,7 @@ int netvsc_send(struct hv_device *device,
 }
 
 static void netvsc_send_recv_completion(struct hv_device *device,
+                                       struct vmbus_channel *channel,
                                        struct netvsc_device *net_device,
                                        u64 transaction_id, u32 status)
 {
@@ -587,7 +817,7 @@ static void netvsc_send_recv_completion(struct hv_device *device,
 
 retry_send_cmplt:
        /* Send the completion */
-       ret = vmbus_sendpacket(device->channel, &recvcompMessage,
+       ret = vmbus_sendpacket(channel, &recvcompMessage,
                               sizeof(struct nvsp_message), transaction_id,
                               VM_PKT_COMP, 0);
        if (ret == 0) {
@@ -613,76 +843,20 @@ retry_send_cmplt:
        }
 }
 
-/* Send a receive completion packet to RNDIS device (ie NetVsp) */
-static void netvsc_receive_completion(void *context)
-{
-       struct hv_netvsc_packet *packet = context;
-       struct hv_device *device = packet->device;
-       struct netvsc_device *net_device;
-       u64 transaction_id = 0;
-       bool fsend_receive_comp = false;
-       unsigned long flags;
-       struct net_device *ndev;
-       u32 status = NVSP_STAT_NONE;
-
-       /*
-        * Even though it seems logical to do a GetOutboundNetDevice() here to
-        * send out receive completion, we are using GetInboundNetDevice()
-        * since we may have disable outbound traffic already.
-        */
-       net_device = get_inbound_net_device(device);
-       if (!net_device)
-               return;
-       ndev = net_device->ndev;
-
-       /* Overloading use of the lock. */
-       spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
-
-       if (packet->status != NVSP_STAT_SUCCESS)
-               packet->xfer_page_pkt->status = NVSP_STAT_FAIL;
-
-       packet->xfer_page_pkt->count--;
-
-       /*
-        * Last one in the line that represent 1 xfer page packet.
-        * Return the xfer page packet itself to the freelist
-        */
-       if (packet->xfer_page_pkt->count == 0) {
-               fsend_receive_comp = true;
-               transaction_id = packet->completion.recv.recv_completion_tid;
-               status = packet->xfer_page_pkt->status;
-               list_add_tail(&packet->xfer_page_pkt->list_ent,
-                             &net_device->recv_pkt_list);
-
-       }
-
-       /* Put the packet back */
-       list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
-       spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
-
-       /* Send a receive completion for the xfer page packet */
-       if (fsend_receive_comp)
-               netvsc_send_recv_completion(device, net_device, transaction_id,
-                                       status);
-
-}
-
 static void netvsc_receive(struct netvsc_device *net_device,
+                       struct vmbus_channel *channel,
                        struct hv_device *device,
                        struct vmpacket_descriptor *packet)
 {
        struct vmtransfer_page_packet_header *vmxferpage_packet;
        struct nvsp_message *nvsp_packet;
-       struct hv_netvsc_packet *netvsc_packet = NULL;
-       /* struct netvsc_driver *netvscDriver; */
-       struct xferpage_packet *xferpage_packet = NULL;
+       struct hv_netvsc_packet nv_pkt;
+       struct hv_netvsc_packet *netvsc_packet = &nv_pkt;
+       u32 status = NVSP_STAT_SUCCESS;
        int i;
        int count = 0;
-       unsigned long flags;
        struct net_device *ndev;
 
-       LIST_HEAD(listHead);
-
        ndev = net_device->ndev;
 
        /*
@@ -715,77 +889,14 @@ static void netvsc_receive(struct netvsc_device *net_device,
                return;
        }
 
-       /*
-        * Grab free packets (range count + 1) to represent this xfer
-        * page packet. +1 to represent the xfer page packet itself.
-        * We grab it here so that we know exactly how many we can
-        * fulfil
-        */
-       spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
-       while (!list_empty(&net_device->recv_pkt_list)) {
-               list_move_tail(net_device->recv_pkt_list.next, &listHead);
-               if (++count == vmxferpage_packet->range_cnt + 1)
-                       break;
-       }
-       spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
-
-       /*
-        * We need at least 2 netvsc pkts (1 to represent the xfer
-        * page and at least 1 for the range) i.e. we can handled
-        * some of the xfer page packet ranges...
-        */
-       if (count < 2) {
-               netdev_err(ndev, "Got only %d netvsc pkt...needed "
-                       "%d pkts. Dropping this xfer page packet completely!\n",
-                       count, vmxferpage_packet->range_cnt + 1);
-
-               /* Return it to the freelist */
-               spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
-               for (i = count; i != 0; i--) {
-                       list_move_tail(listHead.next,
-                                      &net_device->recv_pkt_list);
-               }
-               spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
-                                      flags);
-
-               netvsc_send_recv_completion(device, net_device,
-                                           vmxferpage_packet->d.trans_id,
-                                           NVSP_STAT_FAIL);
-
-               return;
-       }
-
-       /* Remove the 1st packet to represent the xfer page packet itself */
-       xferpage_packet = (struct xferpage_packet *)listHead.next;
-       list_del(&xferpage_packet->list_ent);
-       xferpage_packet->status = NVSP_STAT_SUCCESS;
-
-       /* This is how much we can satisfy */
-       xferpage_packet->count = count - 1;
-
-       if (xferpage_packet->count != vmxferpage_packet->range_cnt) {
-               netdev_err(ndev, "Needed %d netvsc pkts to satisfy "
-                       "this xfer page...got %d\n",
-                       vmxferpage_packet->range_cnt, xferpage_packet->count);
-       }
+       count = vmxferpage_packet->range_cnt;
+       netvsc_packet->device = device;
+       netvsc_packet->channel = channel;
 
        /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
-       for (i = 0; i < (count - 1); i++) {
-               netvsc_packet = (struct hv_netvsc_packet *)listHead.next;
-               list_del(&netvsc_packet->list_ent);
-
+       for (i = 0; i < count; i++) {
                /* Initialize the netvsc packet */
                netvsc_packet->status = NVSP_STAT_SUCCESS;
-               netvsc_packet->xfer_page_pkt = xferpage_packet;
-               netvsc_packet->completion.recv.recv_completion =
-                                       netvsc_receive_completion;
-               netvsc_packet->completion.recv.recv_completion_ctx =
-                                       netvsc_packet;
-               netvsc_packet->device = device;
-               /* Save this so that we can send it back */
-               netvsc_packet->completion.recv.recv_completion_tid =
-                                       vmxferpage_packet->d.trans_id;
-
                netvsc_packet->data = (void *)((unsigned long)net_device->
                        recv_buf + vmxferpage_packet->ranges[i].byte_offset);
                netvsc_packet->total_data_buflen =
@@ -794,16 +905,53 @@ static void netvsc_receive(struct netvsc_device *net_device,
                /* Pass it to the upper layer */
                rndis_filter_receive(device, netvsc_packet);
 
-               netvsc_receive_completion(netvsc_packet->
-                               completion.recv.recv_completion_ctx);
+               if (netvsc_packet->status != NVSP_STAT_SUCCESS)
+                       status = NVSP_STAT_FAIL;
+       }
+
+       netvsc_send_recv_completion(device, channel, net_device,
+                                   vmxferpage_packet->d.trans_id, status);
+}
+
+
+static void netvsc_send_table(struct hv_device *hdev,
+                             struct vmpacket_descriptor *vmpkt)
+{
+       struct netvsc_device *nvscdev;
+       struct net_device *ndev;
+       struct nvsp_message *nvmsg;
+       int i;
+       u32 count, *tab;
+
+       nvscdev = get_outbound_net_device(hdev);
+       if (!nvscdev)
+               return;
+       ndev = nvscdev->ndev;
+
+       nvmsg = (struct nvsp_message *)((unsigned long)vmpkt +
+                                       (vmpkt->offset8 << 3));
+
+       if (nvmsg->hdr.msg_type != NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE)
+               return;
+
+       count = nvmsg->msg.v5_msg.send_table.count;
+       if (count != VRSS_SEND_TAB_SIZE) {
+               netdev_err(ndev, "Received wrong send-table size:%u\n", count);
+               return;
        }
 
+       tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table +
+                     nvmsg->msg.v5_msg.send_table.offset);
+
+       for (i = 0; i < count; i++)
+               nvscdev->send_table[i] = tab[i];
 }
 
-static void netvsc_channel_cb(void *context)
+void netvsc_channel_cb(void *context)
 {
        int ret;
-       struct hv_device *device = context;
+       struct vmbus_channel *channel = (struct vmbus_channel *)context;
+       struct hv_device *device;
        struct netvsc_device *net_device;
        u32 bytes_recvd;
        u64 request_id;
@@ -812,14 +960,19 @@ static void netvsc_channel_cb(void *context)
        int bufferlen = NETVSC_PACKET_SIZE;
        struct net_device *ndev;
 
+       if (channel->primary_channel != NULL)
+               device = channel->primary_channel->device_obj;
+       else
+               device = channel->device_obj;
+
        net_device = get_inbound_net_device(device);
        if (!net_device)
                return;
        ndev = net_device->ndev;
-       buffer = net_device->cb_buffer;
+       buffer = get_per_channel_state(channel);
 
        do {
-               ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
+               ret = vmbus_recvpacket_raw(channel, buffer, bufferlen,
                                           &bytes_recvd, &request_id);
                if (ret == 0) {
                        if (bytes_recvd > 0) {
@@ -831,8 +984,12 @@ static void netvsc_channel_cb(void *context)
                                        break;
 
                                case VM_PKT_DATA_USING_XFER_PAGES:
-                                       netvsc_receive(net_device,
-                                                       device, desc);
+                                       netvsc_receive(net_device, channel,
+                                                      device, desc);
+                                       break;
+
+                               case VM_PKT_DATA_INBAND:
+                                       netvsc_send_table(device, desc);
                                        break;
 
                                default:
@@ -880,11 +1037,9 @@ static void netvsc_channel_cb(void *context)
 int netvsc_device_add(struct hv_device *device, void *additional_info)
 {
        int ret = 0;
-       int i;
        int ring_size =
        ((struct netvsc_device_info *)additional_info)->ring_size;
        struct netvsc_device *net_device;
-       struct hv_netvsc_packet *packet, *pos;
        struct net_device *ndev;
 
        net_device = alloc_net_device(device);
@@ -893,6 +1048,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
                goto cleanup;
        }
 
+       net_device->ring_size = ring_size;
+
        /*
         * Coming into this function, struct net_device * is
         * registered as the driver private data.
@@ -903,24 +1060,14 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
        ndev = net_device->ndev;
 
        /* Initialize the NetVSC channel extension */
-       spin_lock_init(&net_device->recv_pkt_list_lock);
-
-       INIT_LIST_HEAD(&net_device->recv_pkt_list);
-
-       for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
-               packet = kzalloc(sizeof(struct hv_netvsc_packet), GFP_KERNEL);
-               if (!packet)
-                       break;
-
-               list_add_tail(&packet->list_ent,
-                             &net_device->recv_pkt_list);
-       }
        init_completion(&net_device->channel_init_wait);
 
+       set_per_channel_state(device->channel, net_device->cb_buffer);
+
        /* Open the channel */
        ret = vmbus_open(device->channel, ring_size * PAGE_SIZE,
                         ring_size * PAGE_SIZE, NULL, 0,
-                        netvsc_channel_cb, device);
+                        netvsc_channel_cb, device->channel);
 
        if (ret != 0) {
                netdev_err(ndev, "unable to open channel: %d\n", ret);
@@ -930,6 +1077,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
        /* Channel is opened */
        pr_info("hv_netvsc channel opened successfully\n");
 
+       net_device->chn_table[0] = device->channel;
+
        /* Connect with the NetVsp */
        ret = netvsc_connect_vsp(device);
        if (ret != 0) {
@@ -946,16 +1095,8 @@ close:
 
 cleanup:
 
-       if (net_device) {
-               list_for_each_entry_safe(packet, pos,
-                                        &net_device->recv_pkt_list,
-                                        list_ent) {
-                       list_del(&packet->list_ent);
-                       kfree(packet);
-               }
-
+       if (net_device)
                kfree(net_device);
-       }
 
        return ret;
 }
index 31e55fba7cadd03d9e19221139727272b9eeec77..64c7816a5d6a19b1c65f9cfda66da9b89b992ba9 100644 (file)
@@ -101,7 +101,7 @@ static int netvsc_open(struct net_device *net)
                return ret;
        }
 
-       netif_start_queue(net);
+       netif_tx_start_all_queues(net);
 
        nvdev = hv_get_drvdata(device_obj);
        rdev = nvdev->extension;
@@ -149,15 +149,98 @@ static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
        return ppi;
 }
 
+union sub_key {
+       u64 k;
+       struct {
+               u8 pad[3];
+               u8 kb;
+               u32 ka;
+       };
+};
+
+/* Toeplitz hash function
+ * data: network byte order
+ * return: host byte order
+ */
+static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen)
+{
+       union sub_key subk;
+       int k_next = 4;
+       u8 dt;
+       int i, j;
+       u32 ret = 0;
+
+       subk.k = 0;
+       subk.ka = ntohl(*(u32 *)key);
+
+       for (i = 0; i < dlen; i++) {
+               subk.kb = key[k_next];
+               k_next = (k_next + 1) % klen;
+               dt = data[i];
+               for (j = 0; j < 8; j++) {
+                       if (dt & 0x80)
+                               ret ^= subk.ka;
+                       dt <<= 1;
+                       subk.k <<= 1;
+               }
+       }
+
+       return ret;
+}
+
+static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
+{
+       struct iphdr *iphdr;
+       int data_len;
+       bool ret = false;
+
+       if (eth_hdr(skb)->h_proto != htons(ETH_P_IP))
+               return false;
+
+       iphdr = ip_hdr(skb);
+
+       if (iphdr->version == 4) {
+               if (iphdr->protocol == IPPROTO_TCP)
+                       data_len = 12;
+               else
+                       data_len = 8;
+               *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN,
+                                 (u8 *)&iphdr->saddr, data_len);
+               ret = true;
+       }
+
+       return ret;
+}
+
+static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
+                       void *accel_priv, select_queue_fallback_t fallback)
+{
+       struct net_device_context *net_device_ctx = netdev_priv(ndev);
+       struct hv_device *hdev =  net_device_ctx->device_ctx;
+       struct netvsc_device *nvsc_dev = hv_get_drvdata(hdev);
+       u32 hash;
+       u16 q_idx = 0;
+
+       if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1)
+               return 0;
+
+       if (netvsc_set_hash(&hash, skb))
+               q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
+                       ndev->real_num_tx_queues;
+
+       return q_idx;
+}
+
 static void netvsc_xmit_completion(void *context)
 {
        struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
        struct sk_buff *skb = (struct sk_buff *)
-               (unsigned long)packet->completion.send.send_completion_tid;
+               (unsigned long)packet->send_completion_tid;
+       u32 index = packet->send_buf_index;
 
        kfree(packet);
 
-       if (skb)
+       if (skb && (index == NETVSC_INVALID_INDEX))
                dev_kfree_skb_any(skb);
 }
 
@@ -333,6 +416,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        packet->vlan_tci = skb->vlan_tci;
 
+       packet->q_idx = skb_get_queue_mapping(skb);
+
        packet->is_data_pkt = true;
        packet->total_data_buflen = skb->len;
 
@@ -341,9 +426,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
                                (num_data_pgs * sizeof(struct hv_page_buffer)));
 
        /* Set the completion routine */
-       packet->completion.send.send_completion = netvsc_xmit_completion;
-       packet->completion.send.send_completion_ctx = packet;
-       packet->completion.send.send_completion_tid = (unsigned long)skb;
+       packet->send_completion = netvsc_xmit_completion;
+       packet->send_completion_ctx = packet;
+       packet->send_completion_tid = (unsigned long)skb;
 
        isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
 
@@ -382,6 +467,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
        if (skb_is_gso(skb))
                goto do_lso;
 
+       if ((skb->ip_summed == CHECKSUM_NONE) ||
+           (skb->ip_summed == CHECKSUM_UNNECESSARY))
+               goto do_send;
+
        rndis_msg_size += NDIS_CSUM_PPI_SIZE;
        ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
                            TCPIP_CHKSUM_PKTINFO);
@@ -554,6 +643,10 @@ int netvsc_recv_callback(struct hv_device *device_obj,
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                       packet->vlan_tci);
 
+       skb_record_rx_queue(skb, packet->channel->
+                           offermsg.offer.sub_channel_index %
+                           net->real_num_rx_queues);
+
        net->stats.rx_packets++;
        net->stats.rx_bytes += packet->total_data_buflen;
 
@@ -602,7 +695,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        hv_set_drvdata(hdev, ndev);
        device_info.ring_size = ring_size;
        rndis_filter_device_add(hdev, &device_info);
-       netif_wake_queue(ndev);
+       netif_tx_wake_all_queues(ndev);
 
        return 0;
 }
@@ -648,6 +741,7 @@ static const struct net_device_ops device_ops = {
        .ndo_change_mtu =               netvsc_change_mtu,
        .ndo_validate_addr =            eth_validate_addr,
        .ndo_set_mac_address =          netvsc_set_mac_addr,
+       .ndo_select_queue =             netvsc_select_queue,
 };
 
 /*
@@ -694,9 +788,11 @@ static int netvsc_probe(struct hv_device *dev,
        struct net_device *net = NULL;
        struct net_device_context *net_device_ctx;
        struct netvsc_device_info device_info;
+       struct netvsc_device *nvdev;
        int ret;
 
-       net = alloc_etherdev(sizeof(struct net_device_context));
+       net = alloc_etherdev_mq(sizeof(struct net_device_context),
+                               num_online_cpus());
        if (!net)
                return -ENOMEM;
 
@@ -729,6 +825,12 @@ static int netvsc_probe(struct hv_device *dev,
        }
        memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
 
+       nvdev = hv_get_drvdata(dev);
+       netif_set_real_num_tx_queues(net, nvdev->num_chn);
+       netif_set_real_num_rx_queues(net, nvdev->num_chn);
+       dev_info(&dev->device, "real num tx,rx queues:%u, %u\n",
+                net->real_num_tx_queues, net->real_num_rx_queues);
+
        ret = register_netdev(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
index 143a98caf618a90cd45ac002005c506f5ca14a33..99c527adae5bf1ee154b2a02eb0f93a6df32e333 100644 (file)
@@ -31,7 +31,7 @@
 #include "hyperv_net.h"
 
 
-#define RNDIS_EXT_LEN 100
+#define RNDIS_EXT_LEN PAGE_SIZE
 struct rndis_request {
        struct list_head list_ent;
        struct completion  wait_event;
@@ -94,6 +94,8 @@ static struct rndis_request *get_rndis_request(struct rndis_device *dev,
        rndis_msg->ndis_msg_type = msg_type;
        rndis_msg->msg_len = msg_len;
 
+       request->pkt.q_idx = 0;
+
        /*
         * Set the request id. This field is always after the rndis header for
         * request/response packet types so we just used the SetRequest as a
@@ -234,7 +236,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
                        packet->page_buf[0].len;
        }
 
-       packet->completion.send.send_completion = NULL;
+       packet->send_completion = NULL;
 
        ret = netvsc_send(dev->net_dev->dev, packet);
        return ret;
@@ -399,8 +401,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
        pkt->total_data_buflen = rndis_pkt->data_len;
        pkt->data = (void *)((unsigned long)pkt->data + data_offset);
 
-       pkt->is_data_pkt = true;
-
        vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
        if (vlan) {
                pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
@@ -509,6 +509,19 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
        query->info_buflen = 0;
        query->dev_vc_handle = 0;
 
+       if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) {
+               struct ndis_recv_scale_cap *cap;
+
+               request->request_msg.msg_len +=
+                       sizeof(struct ndis_recv_scale_cap);
+               query->info_buflen = sizeof(struct ndis_recv_scale_cap);
+               cap = (struct ndis_recv_scale_cap *)((unsigned long)query +
+                                                    query->info_buf_offset);
+               cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES;
+               cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
+               cap->hdr.size = sizeof(struct ndis_recv_scale_cap);
+       }
+
        ret = rndis_filter_send_request(dev, request);
        if (ret != 0)
                goto cleanup;
@@ -695,6 +708,89 @@ cleanup:
        return ret;
 }
 
+u8 netvsc_hash_key[HASH_KEYLEN] = {
+       0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+       0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
+       0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
+       0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
+       0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
+};
+
+int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
+{
+       struct net_device *ndev = rdev->net_dev->ndev;
+       struct rndis_request *request;
+       struct rndis_set_request *set;
+       struct rndis_set_complete *set_complete;
+       u32 extlen = sizeof(struct ndis_recv_scale_param) +
+                    4*ITAB_NUM + HASH_KEYLEN;
+       struct ndis_recv_scale_param *rssp;
+       u32 *itab;
+       u8 *keyp;
+       int i, t, ret;
+
+       request = get_rndis_request(
+                       rdev, RNDIS_MSG_SET,
+                       RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
+       if (!request)
+               return -ENOMEM;
+
+       set = &request->request_msg.msg.set_req;
+       set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS;
+       set->info_buflen = extlen;
+       set->info_buf_offset = sizeof(struct rndis_set_request);
+       set->dev_vc_handle = 0;
+
+       rssp = (struct ndis_recv_scale_param *)(set + 1);
+       rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS;
+       rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
+       rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
+       rssp->flag = 0;
+       rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
+                        NDIS_HASH_TCP_IPV4;
+       rssp->indirect_tabsize = 4*ITAB_NUM;
+       rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
+       rssp->hashkey_size = HASH_KEYLEN;
+       rssp->kashkey_offset = rssp->indirect_taboffset +
+                              rssp->indirect_tabsize;
+
+       /* Set indirection table entries */
+       itab = (u32 *)(rssp + 1);
+       for (i = 0; i < ITAB_NUM; i++)
+               itab[i] = i % num_queue;
+
+       /* Set hask key values */
+       keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset);
+       for (i = 0; i < HASH_KEYLEN; i++)
+               keyp[i] = netvsc_hash_key[i];
+
+
+       ret = rndis_filter_send_request(rdev, request);
+       if (ret != 0)
+               goto cleanup;
+
+       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+       if (t == 0) {
+               netdev_err(ndev, "timeout before we got a set response...\n");
+               /* can't put_rndis_request, since we may still receive a
+                * send-completion.
+                */
+               return -ETIMEDOUT;
+       } else {
+               set_complete = &request->response_msg.msg.set_complete;
+               if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+                       netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
+                                  set_complete->status);
+                       ret = -EINVAL;
+               }
+       }
+
+cleanup:
+       put_rndis_request(rdev, request);
+       return ret;
+}
+
+
 static int rndis_filter_query_device_link_status(struct rndis_device *dev)
 {
        u32 size = sizeof(u32);
@@ -886,6 +982,28 @@ static int rndis_filter_close_device(struct rndis_device *dev)
        return ret;
 }
 
+static void netvsc_sc_open(struct vmbus_channel *new_sc)
+{
+       struct netvsc_device *nvscdev;
+       u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
+       int ret;
+
+       nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj);
+
+       if (chn_index >= nvscdev->num_chn)
+               return;
+
+       set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) *
+                             NETVSC_PACKET_SIZE);
+
+       ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
+                        nvscdev->ring_size * PAGE_SIZE, NULL, 0,
+                        netvsc_channel_cb, new_sc);
+
+       if (ret == 0)
+               nvscdev->chn_table[chn_index] = new_sc;
+}
+
 int rndis_filter_device_add(struct hv_device *dev,
                                  void *additional_info)
 {
@@ -894,6 +1012,10 @@ int rndis_filter_device_add(struct hv_device *dev,
        struct rndis_device *rndis_device;
        struct netvsc_device_info *device_info = additional_info;
        struct ndis_offload_params offloads;
+       struct nvsp_message *init_packet;
+       int t;
+       struct ndis_recv_scale_cap rsscap;
+       u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
 
        rndis_device = get_rndis_device();
        if (!rndis_device)
@@ -913,6 +1035,7 @@ int rndis_filter_device_add(struct hv_device *dev,
 
        /* Initialize the rndis device */
        net_device = hv_get_drvdata(dev);
+       net_device->num_chn = 1;
 
        net_device->extension = rndis_device;
        rndis_device->net_dev = net_device;
@@ -952,7 +1075,6 @@ int rndis_filter_device_add(struct hv_device *dev,
        if (ret)
                goto err_dev_remv;
 
-
        rndis_filter_query_device_link_status(rndis_device);
 
        device_info->link_state = rndis_device->link_state;
@@ -961,7 +1083,66 @@ int rndis_filter_device_add(struct hv_device *dev,
                 rndis_device->hw_mac_adr,
                 device_info->link_state ? "down" : "up");
 
-       return ret;
+       if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
+               return 0;
+
+       /* vRSS setup */
+       memset(&rsscap, 0, rsscap_size);
+       ret = rndis_filter_query_device(rndis_device,
+                                       OID_GEN_RECEIVE_SCALE_CAPABILITIES,
+                                       &rsscap, &rsscap_size);
+       if (ret || rsscap.num_recv_que < 2)
+               goto out;
+
+       net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ?
+                              num_online_cpus() : rsscap.num_recv_que;
+       if (net_device->num_chn == 1)
+               goto out;
+
+       net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) *
+                                        NETVSC_PACKET_SIZE);
+       if (!net_device->sub_cb_buf) {
+               net_device->num_chn = 1;
+               dev_info(&dev->device, "No memory for subchannels.\n");
+               goto out;
+       }
+
+       vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
+
+       init_packet = &net_device->channel_init_pkt;
+       memset(init_packet, 0, sizeof(struct nvsp_message));
+       init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL;
+       init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE;
+       init_packet->msg.v5_msg.subchn_req.num_subchannels =
+                                               net_device->num_chn - 1;
+       ret = vmbus_sendpacket(dev->channel, init_packet,
+                              sizeof(struct nvsp_message),
+                              (unsigned long)init_packet,
+                              VM_PKT_DATA_INBAND,
+                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+       if (ret)
+               goto out;
+       t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
+       if (t == 0) {
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+       if (init_packet->msg.v5_msg.subchn_comp.status !=
+           NVSP_STAT_SUCCESS) {
+               ret = -ENODEV;
+               goto out;
+       }
+       net_device->num_chn = 1 +
+               init_packet->msg.v5_msg.subchn_comp.num_subchannels;
+
+       vmbus_are_subchannels_present(dev->channel);
+
+       ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
+
+out:
+       if (ret)
+               net_device->num_chn = 1;
+       return 0; /* return 0 because primary channel can be used alone */
 
 err_dev_remv:
        rndis_filter_device_remove(dev);
index e36f194673a45a2035a15830571e4e2c02039839..4517b149ed0786946e44eb1a699fe232c2fbd166 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -692,10 +693,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        if (rc < 0)
                goto err_rx;
 
-       rc = at86rf230_start(dev);
-
-       return rc;
-
+       return at86rf230_start(dev);
 err_rx:
        at86rf230_start(dev);
 err:
@@ -963,33 +961,24 @@ static irqreturn_t at86rf230_isr_level(int irq, void *data)
        return at86rf230_isr(irq, data);
 }
 
-static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol)
-{
-       return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol);
-}
-
 static int at86rf230_hw_init(struct at86rf230_local *lp)
 {
-       struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data;
-       int rc, irq_pol;
-       u8 status;
+       int rc, irq_pol, irq_type;
+       u8 dvdd;
        u8 csma_seed[2];
 
-       rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
-       if (rc)
-               return rc;
-
        rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF);
        if (rc)
                return rc;
 
+       irq_type = irq_get_trigger_type(lp->spi->irq);
        /* configure irq polarity, defaults to high active */
-       if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
+       if (irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
                irq_pol = IRQ_ACTIVE_LOW;
        else
                irq_pol = IRQ_ACTIVE_HIGH;
 
-       rc = at86rf230_irq_polarity(lp, irq_pol);
+       rc = at86rf230_write_subreg(lp, SR_IRQ_POLARITY, irq_pol);
        if (rc)
                return rc;
 
@@ -1017,10 +1006,10 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
        /* Wait the next SLEEP cycle */
        msleep(100);
 
-       rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
+       rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd);
        if (rc)
                return rc;
-       if (!status) {
+       if (!dvdd) {
                dev_err(&lp->spi->dev, "DVDD error\n");
                return -EINVAL;
        }
@@ -1032,7 +1021,6 @@ static struct at86rf230_platform_data *
 at86rf230_get_pdata(struct spi_device *spi)
 {
        struct at86rf230_platform_data *pdata;
-       const char *irq_type;
 
        if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node)
                return spi->dev.platform_data;
@@ -1044,19 +1032,6 @@ at86rf230_get_pdata(struct spi_device *spi)
        pdata->rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
        pdata->slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0);
 
-       pdata->irq_type = IRQF_TRIGGER_RISING;
-       of_property_read_string(spi->dev.of_node, "irq-type", &irq_type);
-       if (!strcmp(irq_type, "level-high"))
-               pdata->irq_type = IRQF_TRIGGER_HIGH;
-       else if (!strcmp(irq_type, "level-low"))
-               pdata->irq_type = IRQF_TRIGGER_LOW;
-       else if (!strcmp(irq_type, "edge-rising"))
-               pdata->irq_type = IRQF_TRIGGER_RISING;
-       else if (!strcmp(irq_type, "edge-falling"))
-               pdata->irq_type = IRQF_TRIGGER_FALLING;
-       else
-               dev_warn(&spi->dev, "wrong irq-type specified using edge-rising\n");
-
        spi->dev.platform_data = pdata;
 done:
        return pdata;
@@ -1071,7 +1046,7 @@ static int at86rf230_probe(struct spi_device *spi)
        u8 part = 0, version = 0, status;
        irq_handler_t irq_handler;
        work_func_t irq_worker;
-       int rc;
+       int rc, irq_type;
        const char *chip;
        struct ieee802154_ops *ops = NULL;
 
@@ -1087,27 +1062,17 @@ static int at86rf230_probe(struct spi_device *spi)
        }
 
        if (gpio_is_valid(pdata->rstn)) {
-               rc = gpio_request(pdata->rstn, "rstn");
+               rc = devm_gpio_request_one(&spi->dev, pdata->rstn,
+                                          GPIOF_OUT_INIT_HIGH, "rstn");
                if (rc)
                        return rc;
        }
 
        if (gpio_is_valid(pdata->slp_tr)) {
-               rc = gpio_request(pdata->slp_tr, "slp_tr");
-               if (rc)
-                       goto err_slp_tr;
-       }
-
-       if (gpio_is_valid(pdata->rstn)) {
-               rc = gpio_direction_output(pdata->rstn, 1);
-               if (rc)
-                       goto err_gpio_dir;
-       }
-
-       if (gpio_is_valid(pdata->slp_tr)) {
-               rc = gpio_direction_output(pdata->slp_tr, 0);
+               rc = devm_gpio_request_one(&spi->dev, pdata->slp_tr,
+                                          GPIOF_OUT_INIT_LOW, "slp_tr");
                if (rc)
-                       goto err_gpio_dir;
+                       return rc;
        }
 
        /* Reset */
@@ -1121,13 +1086,12 @@ static int at86rf230_probe(struct spi_device *spi)
 
        rc = __at86rf230_detect_device(spi, &man_id, &part, &version);
        if (rc < 0)
-               goto err_gpio_dir;
+               return rc;
 
        if (man_id != 0x001f) {
                dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
                        man_id >> 8, man_id & 0xFF);
-               rc = -EINVAL;
-               goto err_gpio_dir;
+               return -EINVAL;
        }
 
        switch (part) {
@@ -1154,16 +1118,12 @@ static int at86rf230_probe(struct spi_device *spi)
        }
 
        dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version);
-       if (!ops) {
-               rc = -ENOTSUPP;
-               goto err_gpio_dir;
-       }
+       if (!ops)
+               return -ENOTSUPP;
 
        dev = ieee802154_alloc_device(sizeof(*lp), ops);
-       if (!dev) {
-               rc = -ENOMEM;
-               goto err_gpio_dir;
-       }
+       if (!dev)
+               return -ENOMEM;
 
        lp = dev->priv;
        lp->dev = dev;
@@ -1176,7 +1136,8 @@ static int at86rf230_probe(struct spi_device *spi)
        dev->extra_tx_headroom = 0;
        dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
 
-       if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+       irq_type = irq_get_trigger_type(spi->irq);
+       if (irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
                irq_worker = at86rf230_irqwork;
                irq_handler = at86rf230_isr;
        } else {
@@ -1202,75 +1163,65 @@ static int at86rf230_probe(struct spi_device *spi)
        if (rc)
                goto err_hw_init;
 
-       rc = request_irq(spi->irq, irq_handler,
-                        IRQF_SHARED | pdata->irq_type,
-                        dev_name(&spi->dev), lp);
+       /* Read irq status register to reset irq line */
+       rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
        if (rc)
                goto err_hw_init;
 
-       /* Read irq status register to reset irq line */
-       rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
+       rc = devm_request_irq(&spi->dev, spi->irq, irq_handler, IRQF_SHARED,
+                             dev_name(&spi->dev), lp);
        if (rc)
-               goto err_irq;
+               goto err_hw_init;
 
        rc = ieee802154_register_device(lp->dev);
        if (rc)
-               goto err_irq;
+               goto err_hw_init;
 
        return rc;
 
-err_irq:
-       free_irq(spi->irq, lp);
 err_hw_init:
        flush_work(&lp->irqwork);
-       spi_set_drvdata(spi, NULL);
        mutex_destroy(&lp->bmux);
        ieee802154_free_device(lp->dev);
 
-err_gpio_dir:
-       if (gpio_is_valid(pdata->slp_tr))
-               gpio_free(pdata->slp_tr);
-err_slp_tr:
-       if (gpio_is_valid(pdata->rstn))
-               gpio_free(pdata->rstn);
        return rc;
 }
 
 static int at86rf230_remove(struct spi_device *spi)
 {
        struct at86rf230_local *lp = spi_get_drvdata(spi);
-       struct at86rf230_platform_data *pdata = spi->dev.platform_data;
 
        /* mask all at86rf230 irq's */
        at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
        ieee802154_unregister_device(lp->dev);
-
-       free_irq(spi->irq, lp);
        flush_work(&lp->irqwork);
-
-       if (gpio_is_valid(pdata->slp_tr))
-               gpio_free(pdata->slp_tr);
-       if (gpio_is_valid(pdata->rstn))
-               gpio_free(pdata->rstn);
-
        mutex_destroy(&lp->bmux);
        ieee802154_free_device(lp->dev);
-
        dev_dbg(&spi->dev, "unregistered at86rf230\n");
+
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_OF)
-static struct of_device_id at86rf230_of_match[] = {
+static const struct of_device_id at86rf230_of_match[] = {
        { .compatible = "atmel,at86rf230", },
        { .compatible = "atmel,at86rf231", },
        { .compatible = "atmel,at86rf233", },
        { .compatible = "atmel,at86rf212", },
        { },
 };
-#endif
+MODULE_DEVICE_TABLE(of, at86rf230_of_match);
+
+static const struct spi_device_id at86rf230_device_id[] = {
+       { .name = "at86rf230", },
+       { .name = "at86rf231", },
+       { .name = "at86rf233", },
+       { .name = "at86rf212", },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, at86rf230_device_id);
 
 static struct spi_driver at86rf230_driver = {
+       .id_table = at86rf230_device_id,
        .driver = {
                .of_match_table = of_match_ptr(at86rf230_of_match),
                .name   = "at86rf230",
index cadf52e224645f1f5f06f588447686015bf67e3a..e3fe9a286136a92a09708727295f42ef4b1254aa 100644 (file)
@@ -217,21 +217,17 @@ crc_init_out:
 static u32 sh_sir_find_sclk(struct clk *irda_clk)
 {
        struct cpufreq_frequency_table *freq_table = irda_clk->freq_table;
+       struct cpufreq_frequency_table *pos;
        struct clk *pclk = clk_get(NULL, "peripheral_clk");
        u32 limit, min = 0xffffffff, tmp;
-       int i, index = 0;
+       int index = 0;
 
        limit = clk_get_rate(pclk);
        clk_put(pclk);
 
        /* IrDA can not set over peripheral_clk */
-       for (i = 0;
-            freq_table[i].frequency != CPUFREQ_TABLE_END;
-            i++) {
-               u32 freq = freq_table[i].frequency;
-
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
+       cpufreq_for_each_valid_entry(pos, freq_table) {
+               u32 freq = pos->frequency;
 
                /* IrDA should not over peripheral_clk */
                if (freq > limit)
@@ -240,7 +236,7 @@ static u32 sh_sir_find_sclk(struct clk *irda_clk)
                tmp = freq % SCLK_BASE;
                if (tmp < min) {
                        min = tmp;
-                       index = i;
+                       index = pos - freq_table;
                }
        }
 
index 753a8c23d15d9af1e138ec6fda410aeda32d288b..f0118d1a3e4687573b6d59191842bf222cb5736e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/if_link.h>
 #include <linux/if_macvlan.h>
 #include <linux/hash.h>
+#include <linux/workqueue.h>
 #include <net/rtnetlink.h>
 #include <net/xfrm.h>
 
@@ -40,10 +41,18 @@ struct macvlan_port {
        struct hlist_head       vlan_hash[MACVLAN_HASH_SIZE];
        struct list_head        vlans;
        struct rcu_head         rcu;
+       struct sk_buff_head     bc_queue;
+       struct work_struct      bc_work;
        bool                    passthru;
        int                     count;
 };
 
+struct macvlan_skb_cb {
+       const struct macvlan_dev *src;
+};
+
+#define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0]))
+
 static void macvlan_port_destroy(struct net_device *dev);
 
 static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev)
@@ -120,7 +129,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
        struct net_device *dev = vlan->dev;
 
        if (local)
-               return dev_forward_skb(dev, skb);
+               return __dev_forward_skb(dev, skb);
 
        skb->dev = dev;
        if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
@@ -128,7 +137,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
        else
                skb->pkt_type = PACKET_MULTICAST;
 
-       return netif_rx(skb);
+       return 0;
 }
 
 static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
@@ -175,32 +184,32 @@ static void macvlan_broadcast(struct sk_buff *skb,
                        if (likely(nskb))
                                err = macvlan_broadcast_one(
                                        nskb, vlan, eth,
-                                       mode == MACVLAN_MODE_BRIDGE);
+                                       mode == MACVLAN_MODE_BRIDGE) ?:
+                                     netif_rx_ni(nskb);
                        macvlan_count_rx(vlan, skb->len + ETH_HLEN,
                                         err == NET_RX_SUCCESS, 1);
                }
        }
 }
 
-/* called under rcu_read_lock() from netif_receive_skb */
-static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
+static void macvlan_process_broadcast(struct work_struct *w)
 {
-       struct macvlan_port *port;
-       struct sk_buff *skb = *pskb;
-       const struct ethhdr *eth = eth_hdr(skb);
-       const struct macvlan_dev *vlan;
-       const struct macvlan_dev *src;
-       struct net_device *dev;
-       unsigned int len = 0;
-       int ret = NET_RX_DROP;
+       struct macvlan_port *port = container_of(w, struct macvlan_port,
+                                                bc_work);
+       struct sk_buff *skb;
+       struct sk_buff_head list;
+
+       skb_queue_head_init(&list);
+
+       spin_lock_bh(&port->bc_queue.lock);
+       skb_queue_splice_tail_init(&port->bc_queue, &list);
+       spin_unlock_bh(&port->bc_queue.lock);
+
+       while ((skb = __skb_dequeue(&list))) {
+               const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src;
+
+               rcu_read_lock();
 
-       port = macvlan_port_get_rcu(skb->dev);
-       if (is_multicast_ether_addr(eth->h_dest)) {
-               skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
-               if (!skb)
-                       return RX_HANDLER_CONSUMED;
-               eth = eth_hdr(skb);
-               src = macvlan_hash_lookup(port, eth->h_source);
                if (!src)
                        /* frame comes from an external address */
                        macvlan_broadcast(skb, port, NULL,
@@ -213,20 +222,80 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
                        macvlan_broadcast(skb, port, src->dev,
                                          MACVLAN_MODE_VEPA |
                                          MACVLAN_MODE_BRIDGE);
-               else if (src->mode == MACVLAN_MODE_BRIDGE)
+               else
                        /*
                         * flood only to VEPA ports, bridge ports
                         * already saw the frame on the way out.
                         */
                        macvlan_broadcast(skb, port, src->dev,
                                          MACVLAN_MODE_VEPA);
-               else {
+
+               rcu_read_unlock();
+
+               kfree_skb(skb);
+       }
+}
+
+static void macvlan_broadcast_enqueue(struct macvlan_port *port,
+                                     struct sk_buff *skb)
+{
+       struct sk_buff *nskb;
+       int err = -ENOMEM;
+
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (!nskb)
+               goto err;
+
+       spin_lock(&port->bc_queue.lock);
+       if (skb_queue_len(&port->bc_queue) < skb->dev->tx_queue_len) {
+               __skb_queue_tail(&port->bc_queue, nskb);
+               err = 0;
+       }
+       spin_unlock(&port->bc_queue.lock);
+
+       if (err)
+               goto free_nskb;
+
+       schedule_work(&port->bc_work);
+       return;
+
+free_nskb:
+       kfree_skb(nskb);
+err:
+       atomic_long_inc(&skb->dev->rx_dropped);
+}
+
+/* called under rcu_read_lock() from netif_receive_skb */
+static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
+{
+       struct macvlan_port *port;
+       struct sk_buff *skb = *pskb;
+       const struct ethhdr *eth = eth_hdr(skb);
+       const struct macvlan_dev *vlan;
+       const struct macvlan_dev *src;
+       struct net_device *dev;
+       unsigned int len = 0;
+       int ret = NET_RX_DROP;
+
+       port = macvlan_port_get_rcu(skb->dev);
+       if (is_multicast_ether_addr(eth->h_dest)) {
+               skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
+               if (!skb)
+                       return RX_HANDLER_CONSUMED;
+               eth = eth_hdr(skb);
+               src = macvlan_hash_lookup(port, eth->h_source);
+               if (src && src->mode != MACVLAN_MODE_VEPA &&
+                   src->mode != MACVLAN_MODE_BRIDGE) {
                        /* forward to original port. */
                        vlan = src;
-                       ret = macvlan_broadcast_one(skb, vlan, eth, 0);
+                       ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?:
+                             netif_rx(skb);
                        goto out;
                }
 
+               MACVLAN_SKB_CB(skb)->src = src;
+               macvlan_broadcast_enqueue(port, skb);
+
                return RX_HANDLER_PASS;
        }
 
@@ -263,11 +332,9 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
        const struct macvlan_dev *vlan = netdev_priv(dev);
        const struct macvlan_port *port = vlan->port;
        const struct macvlan_dev *dest;
-       __u8 ip_summed = skb->ip_summed;
 
        if (vlan->mode == MACVLAN_MODE_BRIDGE) {
                const struct ethhdr *eth = (void *)skb->data;
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
 
                /* send to other bridge ports directly */
                if (is_multicast_ether_addr(eth->h_dest)) {
@@ -285,7 +352,6 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
 xmit_world:
-       skb->ip_summed = ip_summed;
        skb->dev = vlan->lowerdev;
        return dev_queue_xmit(skb);
 }
@@ -764,6 +830,9 @@ static int macvlan_port_create(struct net_device *dev)
        for (i = 0; i < MACVLAN_HASH_SIZE; i++)
                INIT_HLIST_HEAD(&port->vlan_hash[i]);
 
+       skb_queue_head_init(&port->bc_queue);
+       INIT_WORK(&port->bc_work, macvlan_process_broadcast);
+
        err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
        if (err)
                kfree(port);
@@ -776,6 +845,7 @@ static void macvlan_port_destroy(struct net_device *dev)
 {
        struct macvlan_port *port = macvlan_port_get_rtnl(dev);
 
+       cancel_work_sync(&port->bc_work);
        dev->priv_flags &= ~IFF_MACVLAN_PORT;
        netdev_rx_handler_unregister(dev);
        kfree_rcu(port, rcu);
index ff111a89e17f9c66561d79916d8d57e282c119d2..3381c4f91a8cc236df0df8be59bd586538480498 100644 (file)
@@ -322,6 +322,15 @@ static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb)
                        segs = nskb;
                }
        } else {
+               /* If we receive a partial checksum and the tap side
+                * doesn't support checksum offload, compute the checksum.
+                * Note: it doesn't matter which checksum feature to
+                *        check, we either support them all or none.
+                */
+               if (skb->ip_summed == CHECKSUM_PARTIAL &&
+                   !(features & NETIF_F_ALL_CSUM) &&
+                   skb_checksum_help(skb))
+                       goto drop;
                skb_queue_tail(&q->sk.sk_receive_queue, skb);
        }
 
index 643464d5a727b3b937fbe803072861de15a1414f..6c622aedbae111842b0e8ec86aede54653b84ec6 100644 (file)
@@ -144,41 +144,11 @@ static int at803x_resume(struct phy_device *phydev)
 
 static int at803x_config_init(struct phy_device *phydev)
 {
-       int val;
        int ret;
-       u32 features;
-
-       features = SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI |
-                  SUPPORTED_FIBRE | SUPPORTED_BNC;
-
-       val = phy_read(phydev, MII_BMSR);
-       if (val < 0)
-               return val;
-
-       if (val & BMSR_ANEGCAPABLE)
-               features |= SUPPORTED_Autoneg;
-       if (val & BMSR_100FULL)
-               features |= SUPPORTED_100baseT_Full;
-       if (val & BMSR_100HALF)
-               features |= SUPPORTED_100baseT_Half;
-       if (val & BMSR_10FULL)
-               features |= SUPPORTED_10baseT_Full;
-       if (val & BMSR_10HALF)
-               features |= SUPPORTED_10baseT_Half;
-
-       if (val & BMSR_ESTATEN) {
-               val = phy_read(phydev, MII_ESTATUS);
-               if (val < 0)
-                       return val;
-
-               if (val & ESTATUS_1000_TFULL)
-                       features |= SUPPORTED_1000baseT_Full;
-               if (val & ESTATUS_1000_THALF)
-                       features |= SUPPORTED_1000baseT_Half;
-       }
 
-       phydev->supported = features;
-       phydev->advertising = features;
+       ret = genphy_config_init(phydev);
+       if (ret < 0)
+               return ret;
 
        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
                ret = phy_write(phydev, AT803X_DEBUG_ADDR,
@@ -283,8 +253,7 @@ static int __init atheros_init(void)
 
 static void __exit atheros_exit(void)
 {
-       return phy_drivers_unregister(at803x_driver,
-                                     ARRAY_SIZE(at803x_driver));
+       phy_drivers_unregister(at803x_driver, ARRAY_SIZE(at803x_driver));
 }
 
 module_init(atheros_init);
index 76f54b32a120832f2ce212c129592a6f30ab83df..68a9a3867c0f233cff2ff93d7954dfef598e6941 100644 (file)
@@ -69,6 +69,73 @@ struct mii_bus *mdiobus_alloc_size(size_t size)
 }
 EXPORT_SYMBOL(mdiobus_alloc_size);
 
+static void _devm_mdiobus_free(struct device *dev, void *res)
+{
+       mdiobus_free(*(struct mii_bus **)res);
+}
+
+static int devm_mdiobus_match(struct device *dev, void *res, void *data)
+{
+       struct mii_bus **r = res;
+
+       if (WARN_ON(!r || !*r))
+               return 0;
+
+       return *r == data;
+}
+
+/**
+ * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size()
+ * @dev:               Device to allocate mii_bus for
+ * @sizeof_priv:       Space to allocate for private structure.
+ *
+ * Managed mdiobus_alloc_size. mii_bus allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * If an mii_bus allocated with this function needs to be freed separately,
+ * devm_mdiobus_free() must be used.
+ *
+ * RETURNS:
+ * Pointer to allocated mii_bus on success, NULL on failure.
+ */
+struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv)
+{
+       struct mii_bus **ptr, *bus;
+
+       ptr = devres_alloc(_devm_mdiobus_free, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return NULL;
+
+       /* use raw alloc_dr for kmalloc caller tracing */
+       bus = mdiobus_alloc_size(sizeof_priv);
+       if (bus) {
+               *ptr = bus;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return bus;
+}
+EXPORT_SYMBOL_GPL(devm_mdiobus_alloc);
+
+/**
+ * devm_mdiobus_free - Resource-managed mdiobus_free()
+ * @dev:               Device this mii_bus belongs to
+ * @bus:               the mii_bus associated with the device
+ *
+ * Free mii_bus allocated with devm_mdiobus_alloc_size().
+ */
+void devm_mdiobus_free(struct device *dev, struct mii_bus *bus)
+{
+       int rc;
+
+       rc = devres_release(dev, _devm_mdiobus_free,
+                           devm_mdiobus_match, bus);
+       WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_mdiobus_free);
+
 /**
  * mdiobus_release - mii_bus device release callback
  * @d: the target struct device that contains the mii_bus
index 5ad971a55c5d9f21ffb3ded8e9d5704534095d21..d849684231c14919727cb66d5e6e37b14278943d 100644 (file)
@@ -246,13 +246,13 @@ static int ksz9021_load_values_from_of(struct phy_device *phydev,
        if (val1 != -1)
                newval = ((newval & 0xfff0) | ((val1 / PS_TO_REG) & 0xf) << 0);
 
-       if (val2 != -1)
+       if (val2 != -2)
                newval = ((newval & 0xff0f) | ((val2 / PS_TO_REG) & 0xf) << 4);
 
-       if (val3 != -1)
+       if (val3 != -3)
                newval = ((newval & 0xf0ff) | ((val3 / PS_TO_REG) & 0xf) << 8);
 
-       if (val4 != -1)
+       if (val4 != -4)
                newval = ((newval & 0x0fff) | ((val4 / PS_TO_REG) & 0xf) << 12);
 
        return kszphy_extended_write(phydev, reg, newval);
index 1b6d09aef42748bcbba6d4fe88ca68d6ea83c852..a972056b22498c15596a88f6b348e0f066ddb85b 100644 (file)
@@ -765,6 +765,17 @@ void phy_state_machine(struct work_struct *work)
                        break;
 
                if (phydev->link) {
+                       if (AUTONEG_ENABLE == phydev->autoneg) {
+                               err = phy_aneg_done(phydev);
+                               if (err < 0)
+                                       break;
+
+                               if (!err) {
+                                       phydev->state = PHY_AN;
+                                       phydev->link_timeout = PHY_AN_TIMEOUT;
+                                       break;
+                               }
+                       }
                        phydev->state = PHY_RUNNING;
                        netif_carrier_on(phydev->attached_dev);
                        phydev->adjust_link(phydev->attached_dev);
index 0ce606624296a80492b18d89a27634614aad5497..466ae3e063220179580c48d351ceaa0eac5ee615 100644 (file)
@@ -1067,7 +1067,7 @@ int genphy_soft_reset(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_soft_reset);
 
-static int genphy_config_init(struct phy_device *phydev)
+int genphy_config_init(struct phy_device *phydev)
 {
        int val;
        u32 features;
@@ -1118,6 +1118,7 @@ static int gen10g_soft_reset(struct phy_device *phydev)
        /* Do nothing for now */
        return 0;
 }
+EXPORT_SYMBOL(genphy_config_init);
 
 static int gen10g_config_init(struct phy_device *phydev)
 {
index 11f34813e23fb5423ccf90cf9d25e208ed2275f3..180c49479c42f9b4a19f070056b782923de5084c 100644 (file)
@@ -249,8 +249,7 @@ static int __init smsc_init(void)
 
 static void __exit smsc_exit(void)
 {
-       return phy_drivers_unregister(smsc_phy_driver,
-               ARRAY_SIZE(smsc_phy_driver));
+       phy_drivers_unregister(smsc_phy_driver, ARRAY_SIZE(smsc_phy_driver));
 }
 
 MODULE_DESCRIPTION("SMSC PHY driver");
index 14372c65a7e8209b5f97da6416ef80d1f41a522c..5dc0935da99c52a07ba7c09da27503b8ee0b2695 100644 (file)
@@ -319,8 +319,7 @@ static int __init vsc82xx_init(void)
 
 static void __exit vsc82xx_exit(void)
 {
-       return phy_drivers_unregister(vsc82xx_driver,
-               ARRAY_SIZE(vsc82xx_driver));
+       phy_drivers_unregister(vsc82xx_driver, ARRAY_SIZE(vsc82xx_driver));
 }
 
 module_init(vsc82xx_init);
index cc70ecfc70626789183e462c8b51d13f0c7fc8aa..ad4a94e9ff57c77574820fe3e188b12986feff55 100644 (file)
@@ -429,13 +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);
+       spin_lock_bh(&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);
+               spin_unlock_bh(&sl->lock);
                sl_unlock(sl);
                return;
        }
@@ -443,7 +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);
+       spin_unlock_bh(&sl->lock);
 }
 
 static void sl_tx_timeout(struct net_device *dev)
index 33008c1d1d678756ae8fbae13238763c24cc603e..767fe61b5ac995323fa4d3e2d1b2d7ac3869ec00 100644 (file)
@@ -2834,8 +2834,10 @@ static int team_device_event(struct notifier_block *unused,
        case NETDEV_UP:
                if (netif_carrier_ok(dev))
                        team_port_change_check(port, true);
+               break;
        case NETDEV_DOWN:
                team_port_change_check(port, false);
+               break;
        case NETDEV_CHANGE:
                if (netif_running(port->dev))
                        team_port_change_check(port,
index 549dbac710ed5f576f84cedf375df8588e5a7dc5..9a2bd11943ebf391a5678c7ded07ee0bc7b50f5e 100644 (file)
@@ -785,7 +785,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
            skb_out->len > CDC_NCM_MIN_TX_PKT)
                memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0,
                       ctx->tx_max - skb_out->len);
-       else if ((skb_out->len % dev->maxpacket) == 0)
+       else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0)
                *skb_put(skb_out, 1) = 0;       /* force short packet */
 
        /* set final frame length */
index e3458e3c44f146653048aba99295670caabd4db5..83208d4fdc5983aa963dbf1640732c17706ef9a2 100644 (file)
@@ -669,6 +669,22 @@ static const struct usb_device_id products[] = {
        {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(0x16d8, 0x6003, 0)},    /* CMOTech 6003 */
+       {QMI_FIXED_INTF(0x16d8, 0x6007, 0)},    /* CMOTech CHE-628S */
+       {QMI_FIXED_INTF(0x16d8, 0x6008, 0)},    /* CMOTech CMU-301 */
+       {QMI_FIXED_INTF(0x16d8, 0x6280, 0)},    /* CMOTech CHU-628 */
+       {QMI_FIXED_INTF(0x16d8, 0x7001, 0)},    /* CMOTech CHU-720S */
+       {QMI_FIXED_INTF(0x16d8, 0x7002, 0)},    /* CMOTech 7002 */
+       {QMI_FIXED_INTF(0x16d8, 0x7003, 4)},    /* CMOTech CHU-629K */
+       {QMI_FIXED_INTF(0x16d8, 0x7004, 3)},    /* CMOTech 7004 */
+       {QMI_FIXED_INTF(0x16d8, 0x7006, 5)},    /* CMOTech CGU-629 */
+       {QMI_FIXED_INTF(0x16d8, 0x700a, 4)},    /* CMOTech CHU-629S */
+       {QMI_FIXED_INTF(0x16d8, 0x7211, 0)},    /* CMOTech CHU-720I */
+       {QMI_FIXED_INTF(0x16d8, 0x7212, 0)},    /* CMOTech 7212 */
+       {QMI_FIXED_INTF(0x16d8, 0x7213, 0)},    /* CMOTech 7213 */
+       {QMI_FIXED_INTF(0x16d8, 0x7251, 1)},    /* CMOTech 7251 */
+       {QMI_FIXED_INTF(0x16d8, 0x7252, 1)},    /* CMOTech 7252 */
+       {QMI_FIXED_INTF(0x16d8, 0x7253, 1)},    /* CMOTech 7253 */
        {QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
        {QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
        {QMI_FIXED_INTF(0x19d2, 0x0017, 3)},
@@ -730,16 +746,28 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 19)},   /* Sierra Wireless MC7710 in QMI mode */
+       {QMI_FIXED_INTF(0x1199, 0x68c0, 8)},    /* Sierra Wireless MC73xx */
+       {QMI_FIXED_INTF(0x1199, 0x68c0, 10)},   /* Sierra Wireless MC73xx */
+       {QMI_FIXED_INTF(0x1199, 0x68c0, 11)},   /* Sierra Wireless MC73xx */
        {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
+       {QMI_FIXED_INTF(0x1199, 0x901f, 8)},    /* Sierra Wireless EM7355 */
+       {QMI_FIXED_INTF(0x1199, 0x9041, 8)},    /* Sierra Wireless MC7305/MC7355 */
        {QMI_FIXED_INTF(0x1199, 0x9051, 8)},    /* Netgear AirCard 340U */
        {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},    /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
+       {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},    /* Alcatel L800MA */
        {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(0x1bc7, 0x1201, 2)},    /* Telit LE920 */
        {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)},    /* Olivetti Olicard 200 */
+       {QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)},    /* Olivetti Olicard 500 */
        {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},    /* Cinterion PLxx */
        {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)},    /* Cinterion PHxx,PXxx */
+       {QMI_FIXED_INTF(0x413c, 0x81a2, 8)},    /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x413c, 0x81a3, 8)},    /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x413c, 0x81a4, 8)},    /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x413c, 0x81a8, 8)},    /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x413c, 0x81a9, 8)},    /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index 7b687469199b58357a74490cb266e4d47534c097..b852bb368acc8cefd64f6d06caa0e0a18ecda04e 100644 (file)
@@ -1285,7 +1285,7 @@ static int virtnet_set_channels(struct net_device *dev,
        if (channels->rx_count || channels->tx_count || channels->other_count)
                return -EINVAL;
 
-       if (queue_pairs > vi->max_queue_pairs)
+       if (queue_pairs > vi->max_queue_pairs || queue_pairs == 0)
                return -EINVAL;
 
        get_online_cpus();
@@ -1724,6 +1724,13 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
                vi->has_cvq = true;
 
+       if (vi->any_header_sg) {
+               if (vi->mergeable_rx_bufs)
+                       dev->needed_headroom = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+               else
+                       dev->needed_headroom = sizeof(struct virtio_net_hdr);
+       }
+
        /* Use single tx/rx queue pair as default */
        vi->curr_queue_pairs = 1;
        vi->max_queue_pairs = max_queue_pairs;
index 82355d5d155a86921be733cc40deefcbaa6b7116..1dfee9a7fbf7854179ba1bac9fd5bc265fd31b31 100644 (file)
@@ -127,6 +127,7 @@ struct vxlan_dev {
        struct list_head  next;         /* vxlan's per namespace list */
        struct vxlan_sock *vn_sock;     /* listening socket */
        struct net_device *dev;
+       struct net        *net;         /* netns for packet i/o */
        struct vxlan_rdst default_dst;  /* default destination */
        union vxlan_addr  saddr;        /* source address */
        __be16            dst_port;
@@ -389,8 +390,8 @@ static inline size_t vxlan_nlmsg_size(void)
                + nla_total_size(sizeof(struct nda_cacheinfo));
 }
 
-static void vxlan_fdb_notify(struct vxlan_dev *vxlan,
-                            struct vxlan_fdb *fdb, int type)
+static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
+                            struct vxlan_rdst *rd, int type)
 {
        struct net *net = dev_net(vxlan->dev);
        struct sk_buff *skb;
@@ -400,8 +401,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan,
        if (skb == NULL)
                goto errout;
 
-       err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0,
-                            first_remote_rtnl(fdb));
+       err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0, rd);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in vxlan_nlmsg_size() */
                WARN_ON(err == -EMSGSIZE);
@@ -427,10 +427,7 @@ static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
                .remote_vni = VXLAN_N_VID,
        };
 
-       INIT_LIST_HEAD(&f.remotes);
-       list_add_rcu(&remote.list, &f.remotes);
-
-       vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH);
+       vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH);
 }
 
 static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN])
@@ -438,11 +435,11 @@ static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN])
        struct vxlan_fdb f = {
                .state = NUD_STALE,
        };
+       struct vxlan_rdst remote = { };
 
-       INIT_LIST_HEAD(&f.remotes);
        memcpy(f.eth_addr, eth_addr, ETH_ALEN);
 
-       vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH);
+       vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH);
 }
 
 /* Hash Ethernet address */
@@ -533,7 +530,8 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
 
 /* Add/update destinations for multicast */
 static int vxlan_fdb_append(struct vxlan_fdb *f,
-                           union vxlan_addr *ip, __be16 port, __u32 vni, __u32 ifindex)
+                           union vxlan_addr *ip, __be16 port, __u32 vni,
+                           __u32 ifindex, struct vxlan_rdst **rdp)
 {
        struct vxlan_rdst *rd;
 
@@ -551,6 +549,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
 
        list_add_tail_rcu(&rd->list, &f->remotes);
 
+       *rdp = rd;
        return 1;
 }
 
@@ -690,6 +689,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                            __be16 port, __u32 vni, __u32 ifindex,
                            __u8 ndm_flags)
 {
+       struct vxlan_rdst *rd = NULL;
        struct vxlan_fdb *f;
        int notify = 0;
 
@@ -726,7 +726,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                if ((flags & NLM_F_APPEND) &&
                    (is_multicast_ether_addr(f->eth_addr) ||
                     is_zero_ether_addr(f->eth_addr))) {
-                       int rc = vxlan_fdb_append(f, ip, port, vni, ifindex);
+                       int rc = vxlan_fdb_append(f, ip, port, vni, ifindex,
+                                                 &rd);
 
                        if (rc < 0)
                                return rc;
@@ -756,15 +757,18 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                INIT_LIST_HEAD(&f->remotes);
                memcpy(f->eth_addr, mac, ETH_ALEN);
 
-               vxlan_fdb_append(f, ip, port, vni, ifindex);
+               vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
 
                ++vxlan->addrcnt;
                hlist_add_head_rcu(&f->hlist,
                                   vxlan_fdb_head(vxlan, mac));
        }
 
-       if (notify)
-               vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH);
+       if (notify) {
+               if (rd == NULL)
+                       rd = first_remote_rtnl(f);
+               vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH);
+       }
 
        return 0;
 }
@@ -785,7 +789,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
                    "delete %pM\n", f->eth_addr);
 
        --vxlan->addrcnt;
-       vxlan_fdb_notify(vxlan, f, RTM_DELNEIGH);
+       vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH);
 
        hlist_del_rcu(&f->hlist);
        call_rcu(&f->rcu, vxlan_fdb_free);
@@ -919,6 +923,7 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
         */
        if (rd && !list_is_singular(&f->remotes)) {
                list_del_rcu(&rd->list);
+               vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH);
                kfree_rcu(rd, rcu);
                goto out;
        }
@@ -993,7 +998,7 @@ static bool vxlan_snoop(struct net_device *dev,
 
                rdst->remote_ip = *src_ip;
                f->updated = jiffies;
-               vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH);
+               vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH);
        } else {
                /* learned new entry */
                spin_lock(&vxlan->hash_lock);
@@ -1199,6 +1204,7 @@ static void vxlan_rcv(struct vxlan_sock *vs,
 
        remote_ip = &vxlan->default_dst.remote_ip;
        skb_reset_mac_header(skb);
+       skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev)));
        skb->protocol = eth_type_trans(skb, vxlan->dev);
 
        /* Ignore packet loops (and multicast echo) */
@@ -1614,7 +1620,8 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
                           struct dst_entry *dst, struct sk_buff *skb,
                           struct net_device *dev, struct in6_addr *saddr,
                           struct in6_addr *daddr, __u8 prio, __u8 ttl,
-                          __be16 src_port, __be16 dst_port, __be32 vni)
+                          __be16 src_port, __be16 dst_port, __be32 vni,
+                          bool xnet)
 {
        struct ipv6hdr *ip6h;
        struct vxlanhdr *vxh;
@@ -1627,7 +1634,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
                skb->encapsulation = 1;
        }
 
-       skb_scrub_packet(skb, false);
+       skb_scrub_packet(skb, xnet);
 
        min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len
                        + VXLAN_HLEN + sizeof(struct ipv6hdr)
@@ -1707,7 +1714,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
 int vxlan_xmit_skb(struct vxlan_sock *vs,
                   struct rtable *rt, struct sk_buff *skb,
                   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
-                  __be16 src_port, __be16 dst_port, __be32 vni)
+                  __be16 src_port, __be16 dst_port, __be32 vni, bool xnet)
 {
        struct vxlanhdr *vxh;
        struct udphdr *uh;
@@ -1756,7 +1763,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
                return err;
 
        return iptunnel_xmit(vs->sock->sk, rt, skb, src, dst, IPPROTO_UDP,
-                            tos, ttl, df, false);
+                            tos, ttl, df, xnet);
 }
 EXPORT_SYMBOL_GPL(vxlan_xmit_skb);
 
@@ -1849,7 +1856,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                fl4.daddr = dst->sin.sin_addr.s_addr;
                fl4.saddr = vxlan->saddr.sin.sin_addr.s_addr;
 
-               rt = ip_route_output_key(dev_net(dev), &fl4);
+               rt = ip_route_output_key(vxlan->net, &fl4);
                if (IS_ERR(rt)) {
                        netdev_dbg(dev, "no route to %pI4\n",
                                   &dst->sin.sin_addr.s_addr);
@@ -1870,7 +1877,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                        struct vxlan_dev *dst_vxlan;
 
                        ip_rt_put(rt);
-                       dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port);
+                       dst_vxlan = vxlan_find_vni(vxlan->net, vni, dst_port);
                        if (!dst_vxlan)
                                goto tx_error;
                        vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -1883,7 +1890,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb,
                                     fl4.saddr, dst->sin.sin_addr.s_addr,
                                     tos, ttl, df, src_port, dst_port,
-                                    htonl(vni << 8));
+                                    htonl(vni << 8),
+                                    !net_eq(vxlan->net, dev_net(vxlan->dev)));
 
                if (err < 0)
                        goto rt_tx_error;
@@ -1923,7 +1931,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                        struct vxlan_dev *dst_vxlan;
 
                        dst_release(ndst);
-                       dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port);
+                       dst_vxlan = vxlan_find_vni(vxlan->net, vni, dst_port);
                        if (!dst_vxlan)
                                goto tx_error;
                        vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -1934,7 +1942,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 
                err = vxlan6_xmit_skb(vxlan->vn_sock, ndst, skb,
                                      dev, &fl6.saddr, &fl6.daddr, 0, ttl,
-                                     src_port, dst_port, htonl(vni << 8));
+                                     src_port, dst_port, htonl(vni << 8),
+                                     !net_eq(vxlan->net, dev_net(vxlan->dev)));
 #endif
        }
 
@@ -2078,7 +2087,7 @@ static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
 static int vxlan_init(struct net_device *dev)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
-       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
+       struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
        struct vxlan_sock *vs;
 
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
@@ -2086,7 +2095,7 @@ static int vxlan_init(struct net_device *dev)
                return -ENOMEM;
 
        spin_lock(&vn->sock_lock);
-       vs = vxlan_find_sock(dev_net(dev), vxlan->dst_port);
+       vs = vxlan_find_sock(vxlan->net, vxlan->dst_port);
        if (vs) {
                /* If we have a socket with same port already, reuse it */
                atomic_inc(&vs->refcnt);
@@ -2168,8 +2177,8 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
 /* Cleanup timer and forwarding table on shutdown */
 static int vxlan_stop(struct net_device *dev)
 {
-       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
+       struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
        if (vs && vxlan_addr_multicast(&vxlan->default_dst.remote_ip) &&
@@ -2198,7 +2207,7 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
        struct net_device *lowerdev;
        int max_mtu;
 
-       lowerdev = __dev_get_by_index(dev_net(dev), dst->remote_ifindex);
+       lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex);
        if (lowerdev == NULL)
                return eth_change_mtu(dev, new_mtu);
 
@@ -2281,7 +2290,6 @@ static void vxlan_setup(struct net_device *dev)
 
        dev->tx_queue_len = 0;
        dev->features   |= NETIF_F_LLTX;
-       dev->features   |= NETIF_F_NETNS_LOCAL;
        dev->features   |= NETIF_F_SG | NETIF_F_HW_CSUM;
        dev->features   |= NETIF_F_RXCSUM;
        dev->features   |= NETIF_F_GSO_SOFTWARE;
@@ -2574,7 +2582,7 @@ EXPORT_SYMBOL_GPL(vxlan_sock_add);
 static void vxlan_sock_work(struct work_struct *work)
 {
        struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, sock_work);
-       struct net *net = dev_net(vxlan->dev);
+       struct net *net = vxlan->net;
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        __be16 port = vxlan->dst_port;
        struct vxlan_sock *nvs;
@@ -2601,6 +2609,8 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
        if (!data[IFLA_VXLAN_ID])
                return -EINVAL;
 
+       vxlan->net = dev_net(dev);
+
        vni = nla_get_u32(data[IFLA_VXLAN_ID]);
        dst->remote_vni = vni;
 
@@ -2735,8 +2745,8 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
 
 static void vxlan_dellink(struct net_device *dev, struct list_head *head)
 {
-       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
+       struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
 
        spin_lock(&vn->sock_lock);
        if (!hlist_unhashed(&vxlan->hlist))
@@ -2901,8 +2911,33 @@ static __net_init int vxlan_init_net(struct net *net)
        return 0;
 }
 
+static void __net_exit vxlan_exit_net(struct net *net)
+{
+       struct vxlan_net *vn = net_generic(net, vxlan_net_id);
+       struct vxlan_dev *vxlan, *next;
+       struct net_device *dev, *aux;
+       LIST_HEAD(list);
+
+       rtnl_lock();
+       for_each_netdev_safe(net, dev, aux)
+               if (dev->rtnl_link_ops == &vxlan_link_ops)
+                       unregister_netdevice_queue(dev, &list);
+
+       list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) {
+               /* If vxlan->dev is in the same netns, it has already been added
+                * to the list by the previous loop.
+                */
+               if (!net_eq(dev_net(vxlan->dev), net))
+                       unregister_netdevice_queue(dev, &list);
+       }
+
+       unregister_netdevice_many(&list);
+       rtnl_unlock();
+}
+
 static struct pernet_operations vxlan_net_ops = {
        .init = vxlan_init_net,
+       .exit = vxlan_exit_net,
        .id   = &vxlan_net_id,
        .size = sizeof(struct vxlan_net),
 };
index 507d9a9ee69ad4b61ece2d334434691801682efe..f92050617ae682e02bb48b6676a16298ae2dfa4f 100644 (file)
@@ -1090,7 +1090,8 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
        return ret;
 }
 
-static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void ar5523_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                        u32 queues, bool drop)
 {
        struct ar5523 *ar = hw->priv;
 
index a1f0996288508e3cad8ecd8e03f33153980e593e..17d221abd58c0bb70d72a6fbf14f1e7422f8ced5 100644 (file)
@@ -175,7 +175,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
        return 0;
 }
 
-int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
+int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
 {
        struct bmi_cmd cmd;
        union bmi_resp resp;
@@ -184,7 +184,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
        int ret;
 
        ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
-                  address, *param);
+                  address, param);
 
        if (ar->bmi.done_sent) {
                ath10k_warn("command disallowed\n");
@@ -193,7 +193,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
 
        cmd.id            = __cpu_to_le32(BMI_EXECUTE);
        cmd.execute.addr  = __cpu_to_le32(address);
-       cmd.execute.param = __cpu_to_le32(*param);
+       cmd.execute.param = __cpu_to_le32(param);
 
        ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
        if (ret) {
@@ -204,10 +204,13 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
        if (resplen < sizeof(resp.execute)) {
                ath10k_warn("invalid execute response length (%d)\n",
                            resplen);
-               return ret;
+               return -EIO;
        }
 
-       *param = __le32_to_cpu(resp.execute.result);
+       *result = __le32_to_cpu(resp.execute.result);
+
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
+
        return 0;
 }
 
index 8d81ce1cec216c7b55fa1c0ab47b65cc41cafb0d..3a9bdf51c96a212bb98166e42b7f292179c999cf 100644 (file)
@@ -217,7 +217,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
                ret;                                                    \
        })
 
-int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param);
+int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result);
 int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address);
 int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length);
 int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
index a79499c8235009f701073c83b3974d66d183e001..1e4cad8632b527346915a9b3d0545216f881580c 100644 (file)
@@ -840,35 +840,17 @@ void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
 
 static int ath10k_ce_init_src_ring(struct ath10k *ar,
                                   unsigned int ce_id,
-                                  struct ath10k_ce_pipe *ce_state,
                                   const struct ce_attr *attr)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_ce_ring *src_ring;
-       unsigned int nentries = attr->src_nentries;
-       unsigned int ce_nbytes;
-       u32 ctrl_addr = ath10k_ce_base_address(ce_id);
-       dma_addr_t base_addr;
-       char *ptr;
-
-       nentries = roundup_pow_of_two(nentries);
-
-       if (ce_state->src_ring) {
-               WARN_ON(ce_state->src_ring->nentries != nentries);
-               return 0;
-       }
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
+       struct ath10k_ce_ring *src_ring = ce_state->src_ring;
+       u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
 
-       ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *));
-       ptr = kzalloc(ce_nbytes, GFP_KERNEL);
-       if (ptr == NULL)
-               return -ENOMEM;
+       nentries = roundup_pow_of_two(attr->src_nentries);
 
-       ce_state->src_ring = (struct ath10k_ce_ring *)ptr;
-       src_ring = ce_state->src_ring;
-
-       ptr += sizeof(struct ath10k_ce_ring);
-       src_ring->nentries = nentries;
-       src_ring->nentries_mask = nentries - 1;
+       memset(src_ring->per_transfer_context, 0,
+              nentries * sizeof(*src_ring->per_transfer_context));
 
        src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
        src_ring->sw_index &= src_ring->nentries_mask;
@@ -878,21 +860,87 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
                ath10k_ce_src_ring_write_index_get(ar, ctrl_addr);
        src_ring->write_index &= src_ring->nentries_mask;
 
-       src_ring->per_transfer_context = (void **)ptr;
+       ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr,
+                                        src_ring->base_addr_ce_space);
+       ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries);
+       ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max);
+       ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0);
+       ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
+       ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
+
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot init ce src ring id %d entries %d base_addr %p\n",
+                  ce_id, nentries, src_ring->base_addr_owner_space);
+
+       return 0;
+}
+
+static int ath10k_ce_init_dest_ring(struct ath10k *ar,
+                                   unsigned int ce_id,
+                                   const struct ce_attr *attr)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
+       struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
+       u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
+
+       nentries = roundup_pow_of_two(attr->dest_nentries);
+
+       memset(dest_ring->per_transfer_context, 0,
+              nentries * sizeof(*dest_ring->per_transfer_context));
+
+       dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
+       dest_ring->sw_index &= dest_ring->nentries_mask;
+       dest_ring->write_index =
+               ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr);
+       dest_ring->write_index &= dest_ring->nentries_mask;
+
+       ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr,
+                                         dest_ring->base_addr_ce_space);
+       ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries);
+       ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0);
+       ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
+       ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
+
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot ce dest ring id %d entries %d base_addr %p\n",
+                  ce_id, nentries, dest_ring->base_addr_owner_space);
+
+       return 0;
+}
+
+static struct ath10k_ce_ring *
+ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
+                        const struct ce_attr *attr)
+{
+       struct ath10k_ce_ring *src_ring;
+       u32 nentries = attr->src_nentries;
+       dma_addr_t base_addr;
+
+       nentries = roundup_pow_of_two(nentries);
+
+       src_ring = kzalloc(sizeof(*src_ring) +
+                          (nentries *
+                           sizeof(*src_ring->per_transfer_context)),
+                          GFP_KERNEL);
+       if (src_ring == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       src_ring->nentries = nentries;
+       src_ring->nentries_mask = nentries - 1;
 
        /*
         * Legacy platforms that do not support cache
         * coherent DMA are unsupported
         */
        src_ring->base_addr_owner_space_unaligned =
-               pci_alloc_consistent(ar_pci->pdev,
-                                    (nentries * sizeof(struct ce_desc) +
-                                     CE_DESC_RING_ALIGN),
-                                    &base_addr);
+               dma_alloc_coherent(ar->dev,
+                                  (nentries * sizeof(struct ce_desc) +
+                                   CE_DESC_RING_ALIGN),
+                                  &base_addr, GFP_KERNEL);
        if (!src_ring->base_addr_owner_space_unaligned) {
-               kfree(ce_state->src_ring);
-               ce_state->src_ring = NULL;
-               return -ENOMEM;
+               kfree(src_ring);
+               return ERR_PTR(-ENOMEM);
        }
 
        src_ring->base_addr_ce_space_unaligned = base_addr;
@@ -912,88 +960,54 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
                kmalloc((nentries * sizeof(struct ce_desc) +
                         CE_DESC_RING_ALIGN), GFP_KERNEL);
        if (!src_ring->shadow_base_unaligned) {
-               pci_free_consistent(ar_pci->pdev,
-                                   (nentries * sizeof(struct ce_desc) +
-                                    CE_DESC_RING_ALIGN),
-                                   src_ring->base_addr_owner_space,
-                                   src_ring->base_addr_ce_space);
-               kfree(ce_state->src_ring);
-               ce_state->src_ring = NULL;
-               return -ENOMEM;
+               dma_free_coherent(ar->dev,
+                                 (nentries * sizeof(struct ce_desc) +
+                                  CE_DESC_RING_ALIGN),
+                                 src_ring->base_addr_owner_space,
+                                 src_ring->base_addr_ce_space);
+               kfree(src_ring);
+               return ERR_PTR(-ENOMEM);
        }
 
        src_ring->shadow_base = PTR_ALIGN(
                        src_ring->shadow_base_unaligned,
                        CE_DESC_RING_ALIGN);
 
-       ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr,
-                                        src_ring->base_addr_ce_space);
-       ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries);
-       ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max);
-       ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0);
-       ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
-       ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
-
-       ath10k_dbg(ATH10K_DBG_BOOT,
-                  "boot ce src ring id %d entries %d base_addr %p\n",
-                  ce_id, nentries, src_ring->base_addr_owner_space);
-
-       return 0;
+       return src_ring;
 }
 
-static int ath10k_ce_init_dest_ring(struct ath10k *ar,
-                                   unsigned int ce_id,
-                                   struct ath10k_ce_pipe *ce_state,
-                                   const struct ce_attr *attr)
+static struct ath10k_ce_ring *
+ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
+                         const struct ce_attr *attr)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_ce_ring *dest_ring;
-       unsigned int nentries = attr->dest_nentries;
-       unsigned int ce_nbytes;
-       u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+       u32 nentries;
        dma_addr_t base_addr;
-       char *ptr;
 
-       nentries = roundup_pow_of_two(nentries);
+       nentries = roundup_pow_of_two(attr->dest_nentries);
 
-       if (ce_state->dest_ring) {
-               WARN_ON(ce_state->dest_ring->nentries != nentries);
-               return 0;
-       }
-
-       ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *));
-       ptr = kzalloc(ce_nbytes, GFP_KERNEL);
-       if (ptr == NULL)
-               return -ENOMEM;
-
-       ce_state->dest_ring = (struct ath10k_ce_ring *)ptr;
-       dest_ring = ce_state->dest_ring;
+       dest_ring = kzalloc(sizeof(*dest_ring) +
+                           (nentries *
+                            sizeof(*dest_ring->per_transfer_context)),
+                           GFP_KERNEL);
+       if (dest_ring == NULL)
+               return ERR_PTR(-ENOMEM);
 
-       ptr += sizeof(struct ath10k_ce_ring);
        dest_ring->nentries = nentries;
        dest_ring->nentries_mask = nentries - 1;
 
-       dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
-       dest_ring->sw_index &= dest_ring->nentries_mask;
-       dest_ring->write_index =
-               ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr);
-       dest_ring->write_index &= dest_ring->nentries_mask;
-
-       dest_ring->per_transfer_context = (void **)ptr;
-
        /*
         * Legacy platforms that do not support cache
         * coherent DMA are unsupported
         */
        dest_ring->base_addr_owner_space_unaligned =
-               pci_alloc_consistent(ar_pci->pdev,
-                                    (nentries * sizeof(struct ce_desc) +
-                                     CE_DESC_RING_ALIGN),
-                                    &base_addr);
+               dma_alloc_coherent(ar->dev,
+                                  (nentries * sizeof(struct ce_desc) +
+                                   CE_DESC_RING_ALIGN),
+                                  &base_addr, GFP_KERNEL);
        if (!dest_ring->base_addr_owner_space_unaligned) {
-               kfree(ce_state->dest_ring);
-               ce_state->dest_ring = NULL;
-               return -ENOMEM;
+               kfree(dest_ring);
+               return ERR_PTR(-ENOMEM);
        }
 
        dest_ring->base_addr_ce_space_unaligned = base_addr;
@@ -1012,39 +1026,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
                        dest_ring->base_addr_ce_space_unaligned,
                        CE_DESC_RING_ALIGN);
 
-       ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr,
-                                         dest_ring->base_addr_ce_space);
-       ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries);
-       ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0);
-       ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
-       ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
-
-       ath10k_dbg(ATH10K_DBG_BOOT,
-                  "boot ce dest ring id %d entries %d base_addr %p\n",
-                  ce_id, nentries, dest_ring->base_addr_owner_space);
-
-       return 0;
-}
-
-static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar,
-                                            unsigned int ce_id,
-                                            const struct ce_attr *attr)
-{
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
-       u32 ctrl_addr = ath10k_ce_base_address(ce_id);
-
-       spin_lock_bh(&ar_pci->ce_lock);
-
-       ce_state->ar = ar;
-       ce_state->id = ce_id;
-       ce_state->ctrl_addr = ctrl_addr;
-       ce_state->attr_flags = attr->flags;
-       ce_state->src_sz_max = attr->src_sz_max;
-
-       spin_unlock_bh(&ar_pci->ce_lock);
-
-       return ce_state;
+       return dest_ring;
 }
 
 /*
@@ -1054,11 +1036,11 @@ static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar,
  * initialization. It may be that only one side or the other is
  * initialized by software/firmware.
  */
-struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
-                               unsigned int ce_id,
-                               const struct ce_attr *attr)
+int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
+                       const struct ce_attr *attr)
 {
-       struct ath10k_ce_pipe *ce_state;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
        int ret;
 
        /*
@@ -1074,64 +1056,128 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 
        ret = ath10k_pci_wake(ar);
        if (ret)
-               return NULL;
+               return ret;
 
-       ce_state = ath10k_ce_init_state(ar, ce_id, attr);
-       if (!ce_state) {
-               ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id);
-               goto out;
-       }
+       spin_lock_bh(&ar_pci->ce_lock);
+       ce_state->ar = ar;
+       ce_state->id = ce_id;
+       ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
+       ce_state->attr_flags = attr->flags;
+       ce_state->src_sz_max = attr->src_sz_max;
+       spin_unlock_bh(&ar_pci->ce_lock);
 
        if (attr->src_nentries) {
-               ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr);
+               ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
                if (ret) {
                        ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
                                   ce_id, ret);
-                       ath10k_ce_deinit(ce_state);
-                       ce_state = NULL;
                        goto out;
                }
        }
 
        if (attr->dest_nentries) {
-               ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr);
+               ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
                if (ret) {
                        ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
                                   ce_id, ret);
-                       ath10k_ce_deinit(ce_state);
-                       ce_state = NULL;
                        goto out;
                }
        }
 
 out:
        ath10k_pci_sleep(ar);
-       return ce_state;
+       return ret;
 }
 
-void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state)
+static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
+{
+       u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+
+       ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0);
+       ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0);
+       ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, 0);
+       ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, 0);
+}
+
+static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
+{
+       u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+
+       ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0);
+       ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0);
+       ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, 0);
+}
+
+void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
+{
+       int ret;
+
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return;
+
+       ath10k_ce_deinit_src_ring(ar, ce_id);
+       ath10k_ce_deinit_dest_ring(ar, ce_id);
+
+       ath10k_pci_sleep(ar);
+}
+
+int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
+                        const struct ce_attr *attr)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
+       int ret;
+
+       if (attr->src_nentries) {
+               ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
+               if (IS_ERR(ce_state->src_ring)) {
+                       ret = PTR_ERR(ce_state->src_ring);
+                       ath10k_err("failed to allocate copy engine source ring %d: %d\n",
+                                  ce_id, ret);
+                       ce_state->src_ring = NULL;
+                       return ret;
+               }
+       }
+
+       if (attr->dest_nentries) {
+               ce_state->dest_ring = ath10k_ce_alloc_dest_ring(ar, ce_id,
+                                                               attr);
+               if (IS_ERR(ce_state->dest_ring)) {
+                       ret = PTR_ERR(ce_state->dest_ring);
+                       ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
+                                  ce_id, ret);
+                       ce_state->dest_ring = NULL;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)
 {
-       struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
 
        if (ce_state->src_ring) {
                kfree(ce_state->src_ring->shadow_base_unaligned);
-               pci_free_consistent(ar_pci->pdev,
-                                   (ce_state->src_ring->nentries *
-                                    sizeof(struct ce_desc) +
-                                    CE_DESC_RING_ALIGN),
-                                   ce_state->src_ring->base_addr_owner_space,
-                                   ce_state->src_ring->base_addr_ce_space);
+               dma_free_coherent(ar->dev,
+                                 (ce_state->src_ring->nentries *
+                                  sizeof(struct ce_desc) +
+                                  CE_DESC_RING_ALIGN),
+                                 ce_state->src_ring->base_addr_owner_space,
+                                 ce_state->src_ring->base_addr_ce_space);
                kfree(ce_state->src_ring);
        }
 
        if (ce_state->dest_ring) {
-               pci_free_consistent(ar_pci->pdev,
-                                   (ce_state->dest_ring->nentries *
-                                    sizeof(struct ce_desc) +
-                                    CE_DESC_RING_ALIGN),
-                                   ce_state->dest_ring->base_addr_owner_space,
-                                   ce_state->dest_ring->base_addr_ce_space);
+               dma_free_coherent(ar->dev,
+                                 (ce_state->dest_ring->nentries *
+                                  sizeof(struct ce_desc) +
+                                  CE_DESC_RING_ALIGN),
+                                 ce_state->dest_ring->base_addr_owner_space,
+                                 ce_state->dest_ring->base_addr_ce_space);
                kfree(ce_state->dest_ring);
        }
 
index 8eb7f99ed992277b0efb3e7ae4f971b8e4eb7557..fd0bc3561e42a9ea4d84644524b9f19b4cdfb207 100644 (file)
@@ -104,7 +104,8 @@ struct ath10k_ce_ring {
        void *shadow_base_unaligned;
        struct ce_desc *shadow_base;
 
-       void **per_transfer_context;
+       /* keep last */
+       void *per_transfer_context[0];
 };
 
 struct ath10k_ce_pipe {
@@ -210,10 +211,12 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
 
 /*==================CE Engine Initialization=======================*/
 
-/* Initialize an instance of a CE */
-struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
-                               unsigned int ce_id,
-                               const struct ce_attr *attr);
+int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
+                       const struct ce_attr *attr);
+void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
+int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
+                         const struct ce_attr *attr);
+void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
 
 /*==================CE Engine Shutdown=======================*/
 /*
@@ -236,8 +239,6 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
                               unsigned int *nbytesp,
                               unsigned int *transfer_idp);
 
-void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
-
 /*==================CE Interrupt Handlers====================*/
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
index ebc5fc2ede75cbac75da3a2f789a946d4e1274ad..6abde37fb339c981f2c772af9ef908f5a32a66be 100644 (file)
@@ -249,30 +249,40 @@ exit:
 
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
-       u32 address = ar->hw_params.patch_load_addr;
-       u32 exec_param;
+       u32 result, address = ar->hw_params.patch_load_addr;
        int ret;
 
        /* OTP is optional */
 
-       if (!ar->otp_data || !ar->otp_len)
+       if (!ar->otp_data || !ar->otp_len) {
+               ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
+                           ar->otp_data, ar->otp_len);
                return 0;
+       }
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
+                  address, ar->otp_len);
 
        ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
        if (ret) {
                ath10k_err("could not write otp (%d)\n", ret);
-               goto exit;
+               return ret;
        }
 
-       exec_param = 0;
-       ret = ath10k_bmi_execute(ar, address, &exec_param);
+       ret = ath10k_bmi_execute(ar, address, 0, &result);
        if (ret) {
                ath10k_err("could not execute otp (%d)\n", ret);
-               goto exit;
+               return ret;
        }
 
-exit:
-       return ret;
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+
+       if (result != 0) {
+               ath10k_err("otp calibration failed: %d", result);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 static int ath10k_download_fw(struct ath10k *ar)
@@ -389,8 +399,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        /* first fetch the firmware file (firmware-*.bin) */
        ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
        if (IS_ERR(ar->firmware)) {
-               ath10k_err("Could not fetch firmware file '%s': %ld\n",
-                          name, PTR_ERR(ar->firmware));
+               ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
+                          ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
                return PTR_ERR(ar->firmware);
        }
 
@@ -401,14 +411,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
 
        if (len < magic_len) {
-               ath10k_err("firmware image too small to contain magic: %zu\n",
-                          len);
+               ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
+                          ar->hw_params.fw.dir, name, len);
                ret = -EINVAL;
                goto err;
        }
 
        if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
-               ath10k_err("Invalid firmware magic\n");
+               ath10k_err("invalid firmware magic\n");
                ret = -EINVAL;
                goto err;
        }
@@ -430,7 +440,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                data += sizeof(*hdr);
 
                if (len < ie_len) {
-                       ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n",
+                       ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
                                   ie_id, len, ie_len);
                        ret = -EINVAL;
                        goto err;
@@ -513,8 +523,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        }
 
        if (!ar->firmware_data || !ar->firmware_len) {
-               ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n",
-                           name);
+               ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
+                           ar->hw_params.fw.dir, name);
                ret = -ENOMEDIUM;
                goto err;
        }
@@ -531,7 +541,9 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                                         ar->hw_params.fw.board);
        if (IS_ERR(ar->board)) {
                ret = PTR_ERR(ar->board);
-               ath10k_err("could not fetch board data (%d)\n", ret);
+               ath10k_err("could not fetch board data '%s/%s' (%d)\n",
+                          ar->hw_params.fw.dir, ar->hw_params.fw.board,
+                          ret);
                goto err;
        }
 
@@ -549,19 +561,21 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
 {
        int ret;
 
+       ar->fw_api = 2;
+       ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
        ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
-       if (ret == 0) {
-               ar->fw_api = 2;
-               goto out;
-       }
+       if (ret == 0)
+               goto success;
+
+       ar->fw_api = 1;
+       ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
        ret = ath10k_core_fetch_firmware_api_1(ar);
        if (ret)
                return ret;
 
-       ar->fw_api = 1;
-
-out:
+success:
        ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
 
        return 0;
@@ -572,16 +586,22 @@ static int ath10k_init_download_firmware(struct ath10k *ar)
        int ret;
 
        ret = ath10k_download_board_data(ar);
-       if (ret)
+       if (ret) {
+               ath10k_err("failed to download board data: %d\n", ret);
                return ret;
+       }
 
        ret = ath10k_download_and_run_otp(ar);
-       if (ret)
+       if (ret) {
+               ath10k_err("failed to run otp: %d\n", ret);
                return ret;
+       }
 
        ret = ath10k_download_fw(ar);
-       if (ret)
+       if (ret) {
+               ath10k_err("failed to download firmware: %d\n", ret);
                return ret;
+       }
 
        return ret;
 }
@@ -835,9 +855,12 @@ int ath10k_core_start(struct ath10k *ar)
        INIT_LIST_HEAD(&ar->arvifs);
 
        if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
-               ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n",
-                           ar->hw_params.name, ar->target_version,
-                           ar->hw->wiphy->fw_version, ar->fw_api,
+               ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+                           ar->hw_params.name,
+                           ar->target_version,
+                           ar->chip_id,
+                           ar->hw->wiphy->fw_version,
+                           ar->fw_api,
                            ar->htt.target_version_major,
                            ar->htt.target_version_minor);
 
index 0e71979d837cf90888c74e4d85035c2a4d6fd4ef..2c1dfd71914688ec80bb4849031458943c986293 100644 (file)
@@ -119,6 +119,7 @@ struct ath10k_peer_stat {
        u8 peer_macaddr[ETH_ALEN];
        u32 peer_rssi;
        u32 peer_tx_rate;
+       u32 peer_rx_rate; /* 10x only */
 };
 
 struct ath10k_target_stats {
@@ -130,6 +131,12 @@ struct ath10k_target_stats {
        u32 cycle_count;
        u32 phy_err_count;
        u32 chan_tx_power;
+       u32 ack_rx_bad;
+       u32 rts_bad;
+       u32 rts_good;
+       u32 fcs_bad;
+       u32 no_beacons;
+       u32 mib_int_count;
 
        /* PDEV TX stats */
        s32 comp_queued;
@@ -260,6 +267,8 @@ struct ath10k_vif {
        u8 fixed_rate;
        u8 fixed_nss;
        u8 force_sgi;
+       bool use_cts_prot;
+       int num_legacy_stations;
 };
 
 struct ath10k_vif_iter {
@@ -419,13 +428,18 @@ struct ath10k {
        struct cfg80211_chan_def chandef;
 
        int free_vdev_map;
+       bool promisc;
+       bool monitor;
        int monitor_vdev_id;
-       bool monitor_enabled;
-       bool monitor_present;
+       bool monitor_started;
        unsigned int filter_flags;
        unsigned long dev_flags;
        u32 dfs_block_radar_events;
 
+       /* protected by conf_mutex */
+       bool radar_enabled;
+       int num_started_vdevs;
+
        struct wmi_pdev_set_wmm_params_arg wmm_params;
        struct completion install_key_done;
 
index 6debd281350aeb840978606212655fba6d6fb7a3..1b7ff4ba122ce42af61265eae30d8fb98d97201e 100644 (file)
@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
        u8 *tmp = ev->data;
        struct ath10k_target_stats *stats;
        int num_pdev_stats, num_vdev_stats, num_peer_stats;
-       struct wmi_pdev_stats *ps;
+       struct wmi_pdev_stats_10x *ps;
        int i;
 
        spin_lock_bh(&ar->data_lock);
@@ -173,7 +173,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
        num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
 
        if (num_pdev_stats) {
-               ps = (struct wmi_pdev_stats *)tmp;
+               ps = (struct wmi_pdev_stats_10x *)tmp;
 
                stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
                stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
@@ -228,7 +228,18 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
                stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
                stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
 
-               tmp += sizeof(struct wmi_pdev_stats);
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
+                            ar->fw_features)) {
+                       stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad);
+                       stats->rts_bad = __le32_to_cpu(ps->rts_bad);
+                       stats->rts_good = __le32_to_cpu(ps->rts_good);
+                       stats->fcs_bad = __le32_to_cpu(ps->fcs_bad);
+                       stats->no_beacons = __le32_to_cpu(ps->no_beacons);
+                       stats->mib_int_count = __le32_to_cpu(ps->mib_int_count);
+                       tmp += sizeof(struct wmi_pdev_stats_10x);
+               } else {
+                       tmp += sizeof(struct wmi_pdev_stats_old);
+               }
        }
 
        /* 0 or max vdevs */
@@ -243,22 +254,29 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
        }
 
        if (num_peer_stats) {
-               struct wmi_peer_stats *peer_stats;
+               struct wmi_peer_stats_10x *peer_stats;
                struct ath10k_peer_stat *s;
 
                stats->peers = num_peer_stats;
 
                for (i = 0; i < num_peer_stats; i++) {
-                       peer_stats = (struct wmi_peer_stats *)tmp;
+                       peer_stats = (struct wmi_peer_stats_10x *)tmp;
                        s = &stats->peer_stat[i];
 
-                       WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
-                                                  s->peer_macaddr);
+                       memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr,
+                              ETH_ALEN);
                        s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
                        s->peer_tx_rate =
                                __le32_to_cpu(peer_stats->peer_tx_rate);
-
-                       tmp += sizeof(struct wmi_peer_stats);
+                       if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
+                                    ar->fw_features)) {
+                               s->peer_rx_rate =
+                                       __le32_to_cpu(peer_stats->peer_rx_rate);
+                               tmp += sizeof(struct wmi_peer_stats_10x);
+
+                       } else {
+                               tmp += sizeof(struct wmi_peer_stats_old);
+                       }
                }
        }
 
@@ -272,7 +290,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
        struct ath10k *ar = file->private_data;
        struct ath10k_target_stats *fw_stats;
        char *buf = NULL;
-       unsigned int len = 0, buf_len = 2500;
+       unsigned int len = 0, buf_len = 8000;
        ssize_t ret_cnt = 0;
        long left;
        int i;
@@ -320,6 +338,16 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
                         "Cycle count", fw_stats->cycle_count);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
                         "PHY error count", fw_stats->phy_err_count);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "RTS bad count", fw_stats->rts_bad);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "RTS good count", fw_stats->rts_good);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "FCS bad count", fw_stats->fcs_bad);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "No beacon count", fw_stats->no_beacons);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "MIB int count", fw_stats->mib_int_count);
 
        len += scnprintf(buf + len, buf_len - len, "\n");
        len += scnprintf(buf + len, buf_len - len, "%30s\n",
@@ -411,8 +439,8 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
                         "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
 
        len += scnprintf(buf + len, buf_len - len, "\n");
-       len += scnprintf(buf + len, buf_len - len, "%30s\n",
-                        "ath10k PEER stats");
+       len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n",
+                        "ath10k PEER stats", fw_stats->peers);
        len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
                                 "=================");
 
@@ -425,6 +453,9 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
                len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
                                 "Peer TX rate",
                                 fw_stats->peer_stat[i].peer_tx_rate);
+               len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                                "Peer RX rate",
+                                fw_stats->peer_stat[i].peer_rx_rate);
                len += scnprintf(buf + len, buf_len - len, "\n");
        }
        spin_unlock_bh(&ar->data_lock);
@@ -451,27 +482,37 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
                                             char __user *user_buf,
                                             size_t count, loff_t *ppos)
 {
-       const char buf[] = "To simulate firmware crash write the keyword"
-                          " `crash` to this file.\nThis will force firmware"
-                          " to report a crash to the host system.\n";
+       const char buf[] = "To simulate firmware crash write one of the"
+                          " keywords to this file:\n `soft` - this will send"
+                          " WMI_FORCE_FW_HANG_ASSERT to firmware if FW"
+                          " supports that command.\n `hard` - this will send"
+                          " to firmware command with illegal parameters"
+                          " causing firmware crash.\n";
+
        return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
 }
 
+/* Simulate firmware crash:
+ * 'soft': Call wmi command causing firmware hang. This firmware hang is
+ * recoverable by warm firmware reset.
+ * 'hard': Force firmware crash by setting any vdev parameter for not allowed
+ * vdev id. This is hard firmware crash because it is recoverable only by cold
+ * firmware reset.
+ */
 static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
                                              const char __user *user_buf,
                                              size_t count, loff_t *ppos)
 {
        struct ath10k *ar = file->private_data;
-       char buf[32] = {};
+       char buf[32];
        int ret;
 
        mutex_lock(&ar->conf_mutex);
 
        simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
-       if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) {
-               ret = -EINVAL;
-               goto exit;
-       }
+
+       /* make sure that buf is null terminated */
+       buf[sizeof(buf) - 1] = 0;
 
        if (ar->state != ATH10K_STATE_ON &&
            ar->state != ATH10K_STATE_RESTARTED) {
@@ -479,14 +520,30 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
                goto exit;
        }
 
-       ath10k_info("simulating firmware crash\n");
+       /* drop the possible '\n' from the end */
+       if (buf[count - 1] == '\n') {
+               buf[count - 1] = 0;
+               count--;
+       }
 
-       ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
-       if (ret)
-               ath10k_warn("failed to force fw hang (%d)\n", ret);
+       if (!strcmp(buf, "soft")) {
+               ath10k_info("simulating soft firmware crash\n");
+               ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
+       } else if (!strcmp(buf, "hard")) {
+               ath10k_info("simulating hard firmware crash\n");
+               ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
+                                       ar->wmi.vdev_param->rts_threshold, 0);
+       } else {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (ret) {
+               ath10k_warn("failed to simulate firmware crash: %d\n", ret);
+               goto exit;
+       }
 
-       if (ret == 0)
-               ret = count;
+       ret = count;
 
 exit:
        mutex_unlock(&ar->conf_mutex);
index 7f1bccd3597f1bb2a3b40d5a482f308e99e9e27c..5b58dbb174161a5ead5a8a5865fac70ba7e1b056 100644 (file)
@@ -157,6 +157,9 @@ int ath10k_htc_send(struct ath10k_htc *htc,
                        goto err_pull;
                }
                ep->tx_credits -= credits;
+               ath10k_dbg(ATH10K_DBG_HTC,
+                          "htc ep %d consumed %d credits (total %d)\n",
+                          eid, credits, ep->tx_credits);
                spin_unlock_bh(&htc->tx_lock);
        }
 
@@ -185,6 +188,9 @@ err_credits:
        if (ep->tx_credit_flow_enabled) {
                spin_lock_bh(&htc->tx_lock);
                ep->tx_credits += credits;
+               ath10k_dbg(ATH10K_DBG_HTC,
+                          "htc ep %d reverted %d credits back (total %d)\n",
+                          eid, credits, ep->tx_credits);
                spin_unlock_bh(&htc->tx_lock);
 
                if (ep->ep_ops.ep_tx_credits)
@@ -234,12 +240,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
                if (report->eid >= ATH10K_HTC_EP_COUNT)
                        break;
 
-               ath10k_dbg(ATH10K_DBG_HTC, "ep %d got %d credits\n",
-                          report->eid, report->credits);
-
                ep = &htc->endpoint[report->eid];
                ep->tx_credits += report->credits;
 
+               ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
+                          report->eid, report->credits, ep->tx_credits);
+
                if (ep->ep_ops.ep_tx_credits) {
                        spin_unlock_bh(&htc->tx_lock);
                        ep->ep_ops.ep_tx_credits(htc->ar);
index 654867fc1ae73bbd7a13cf4dc61f8ac89a0b7823..645a563e3fb9675a5c545277cec88b68a757fff0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/bug.h>
 #include <linux/interrupt.h>
 #include <linux/dmapool.h>
+#include <net/mac80211.h>
 
 #include "htc.h"
 #include "rx_desc.h"
@@ -1172,23 +1173,6 @@ struct htt_peer_unmap_event {
        u16 peer_id;
 };
 
-struct htt_rx_info {
-       struct sk_buff *skb;
-       enum htt_rx_mpdu_status status;
-       enum htt_rx_mpdu_encrypt_type encrypt_type;
-       s8 signal;
-       struct {
-               u8 info0;
-               u32 info1;
-               u32 info2;
-       } rate;
-
-       u32 tsf;
-       bool fcs_err;
-       bool amsdu_more;
-       bool mic_err;
-};
-
 struct ath10k_htt_txbuf {
        struct htt_data_tx_desc_frag frags[2];
        struct ath10k_htc_hdr htc_hdr;
@@ -1289,6 +1273,9 @@ struct ath10k_htt {
        struct tasklet_struct txrx_compl_task;
        struct sk_buff_head tx_compl_q;
        struct sk_buff_head rx_compl_q;
+
+       /* rx_status template */
+       struct ieee80211_rx_status rx_status;
 };
 
 #define RX_HTT_HDR_STATUS_LEN 64
index cdcbe2de95f97d602cb086c301f0778aad5bc49c..f85a3cf6da3103d6f909b80715a1d0763fce7a39 100644 (file)
@@ -297,6 +297,7 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb)
        }
 }
 
+/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
 static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                                   u8 **fw_desc, int *fw_desc_len,
                                   struct sk_buff **head_msdu,
@@ -310,7 +311,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 
        if (htt->rx_confused) {
                ath10k_warn("htt is confused. refusing rx\n");
-               return 0;
+               return -1;
        }
 
        msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt);
@@ -442,6 +443,9 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
        }
        *tail_msdu = msdu;
 
+       if (*head_msdu == NULL)
+               msdu_chaining = -1;
+
        /*
         * Don't refill the ring yet.
         *
@@ -636,6 +640,190 @@ struct amsdu_subframe_hdr {
        __be16 len;
 } __packed;
 
+static const u8 rx_legacy_rate_idx[] = {
+       3,      /* 0x00  - 11Mbps  */
+       2,      /* 0x01  - 5.5Mbps */
+       1,      /* 0x02  - 2Mbps   */
+       0,      /* 0x03  - 1Mbps   */
+       3,      /* 0x04  - 11Mbps  */
+       2,      /* 0x05  - 5.5Mbps */
+       1,      /* 0x06  - 2Mbps   */
+       0,      /* 0x07  - 1Mbps   */
+       10,     /* 0x08  - 48Mbps  */
+       8,      /* 0x09  - 24Mbps  */
+       6,      /* 0x0A  - 12Mbps  */
+       4,      /* 0x0B  - 6Mbps   */
+       11,     /* 0x0C  - 54Mbps  */
+       9,      /* 0x0D  - 36Mbps  */
+       7,      /* 0x0E  - 18Mbps  */
+       5,      /* 0x0F  - 9Mbps   */
+};
+
+static void ath10k_htt_rx_h_rates(struct ath10k *ar,
+                                 enum ieee80211_band band,
+                                 u8 info0, u32 info1, u32 info2,
+                                 struct ieee80211_rx_status *status)
+{
+       u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
+       u8 preamble = 0;
+
+       /* Check if valid fields */
+       if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
+               return;
+
+       preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
+
+       switch (preamble) {
+       case HTT_RX_LEGACY:
+               cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
+               rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
+               rate_idx = 0;
+
+               if (rate < 0x08 || rate > 0x0F)
+                       break;
+
+               switch (band) {
+               case IEEE80211_BAND_2GHZ:
+                       if (cck)
+                               rate &= ~BIT(3);
+                       rate_idx = rx_legacy_rate_idx[rate];
+                       break;
+               case IEEE80211_BAND_5GHZ:
+                       rate_idx = rx_legacy_rate_idx[rate];
+                       /* We are using same rate table registering
+                          HW - ath10k_rates[]. In case of 5GHz skip
+                          CCK rates, so -4 here */
+                       rate_idx -= 4;
+                       break;
+               default:
+                       break;
+               }
+
+               status->rate_idx = rate_idx;
+               break;
+       case HTT_RX_HT:
+       case HTT_RX_HT_WITH_TXBF:
+               /* HT-SIG - Table 20-11 in info1 and info2 */
+               mcs = info1 & 0x1F;
+               nss = mcs >> 3;
+               bw = (info1 >> 7) & 1;
+               sgi = (info2 >> 7) & 1;
+
+               status->rate_idx = mcs;
+               status->flag |= RX_FLAG_HT;
+               if (sgi)
+                       status->flag |= RX_FLAG_SHORT_GI;
+               if (bw)
+                       status->flag |= RX_FLAG_40MHZ;
+               break;
+       case HTT_RX_VHT:
+       case HTT_RX_VHT_WITH_TXBF:
+               /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
+                  TODO check this */
+               mcs = (info2 >> 4) & 0x0F;
+               nss = ((info1 >> 10) & 0x07) + 1;
+               bw = info1 & 3;
+               sgi = info2 & 1;
+
+               status->rate_idx = mcs;
+               status->vht_nss = nss;
+
+               if (sgi)
+                       status->flag |= RX_FLAG_SHORT_GI;
+
+               switch (bw) {
+               /* 20MHZ */
+               case 0:
+                       break;
+               /* 40MHZ */
+               case 1:
+                       status->flag |= RX_FLAG_40MHZ;
+                       break;
+               /* 80MHZ */
+               case 2:
+                       status->vht_flag |= RX_VHT_FLAG_80MHZ;
+               }
+
+               status->flag |= RX_FLAG_VHT;
+               break;
+       default:
+               break;
+       }
+}
+
+static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt,
+                                     struct ieee80211_rx_status *rx_status,
+                                     struct sk_buff *skb,
+                                     enum htt_rx_mpdu_encrypt_type enctype)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+
+       if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) {
+               rx_status->flag &= ~(RX_FLAG_DECRYPTED |
+                                    RX_FLAG_IV_STRIPPED |
+                                    RX_FLAG_MMIC_STRIPPED);
+               return;
+       }
+
+       rx_status->flag |= RX_FLAG_DECRYPTED |
+                          RX_FLAG_IV_STRIPPED |
+                          RX_FLAG_MMIC_STRIPPED;
+       hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) &
+                                          ~IEEE80211_FCTL_PROTECTED);
+}
+
+static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
+                                   struct ieee80211_rx_status *status)
+{
+       struct ieee80211_channel *ch;
+
+       spin_lock_bh(&ar->data_lock);
+       ch = ar->scan_channel;
+       if (!ch)
+               ch = ar->rx_channel;
+       spin_unlock_bh(&ar->data_lock);
+
+       if (!ch)
+               return false;
+
+       status->band = ch->band;
+       status->freq = ch->center_freq;
+
+       return true;
+}
+
+static void ath10k_process_rx(struct ath10k *ar,
+                             struct ieee80211_rx_status *rx_status,
+                             struct sk_buff *skb)
+{
+       struct ieee80211_rx_status *status;
+
+       status = IEEE80211_SKB_RXCB(skb);
+       *status = *rx_status;
+
+       ath10k_dbg(ATH10K_DBG_DATA,
+                  "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
+                  skb,
+                  skb->len,
+                  status->flag == 0 ? "legacy" : "",
+                  status->flag & RX_FLAG_HT ? "ht" : "",
+                  status->flag & RX_FLAG_VHT ? "vht" : "",
+                  status->flag & RX_FLAG_40MHZ ? "40" : "",
+                  status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
+                  status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
+                  status->rate_idx,
+                  status->vht_nss,
+                  status->freq,
+                  status->band, status->flag,
+                  !!(status->flag & RX_FLAG_FAILED_FCS_CRC),
+                  !!(status->flag & RX_FLAG_MMIC_ERROR));
+       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
+                       skb->data, skb->len);
+
+       ieee80211_rx(ar->hw, skb);
+}
+
 static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
 {
        /* nwifi header is padded to 4 bytes. this fixes 4addr rx */
@@ -643,11 +831,12 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
 }
 
 static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
-                               struct htt_rx_info *info)
+                               struct ieee80211_rx_status *rx_status,
+                               struct sk_buff *skb_in)
 {
        struct htt_rx_desc *rxd;
+       struct sk_buff *skb = skb_in;
        struct sk_buff *first;
-       struct sk_buff *skb = info->skb;
        enum rx_msdu_decap_format fmt;
        enum htt_rx_mpdu_encrypt_type enctype;
        struct ieee80211_hdr *hdr;
@@ -728,24 +917,27 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                        break;
                }
 
-               info->skb = skb;
-               info->encrypt_type = enctype;
+               skb_in = skb;
+               ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype);
                skb = skb->next;
-               info->skb->next = NULL;
+               skb_in->next = NULL;
 
                if (skb)
-                       info->amsdu_more = true;
+                       rx_status->flag |= RX_FLAG_AMSDU_MORE;
+               else
+                       rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
 
-               ath10k_process_rx(htt->ar, info);
+               ath10k_process_rx(htt->ar, rx_status, skb_in);
        }
 
        /* FIXME: It might be nice to re-assemble the A-MSDU when there's a
         * monitor interface active for sniffing purposes. */
 }
 
-static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
+static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
+                              struct ieee80211_rx_status *rx_status,
+                              struct sk_buff *skb)
 {
-       struct sk_buff *skb = info->skb;
        struct htt_rx_desc *rxd;
        struct ieee80211_hdr *hdr;
        enum rx_msdu_decap_format fmt;
@@ -808,66 +1000,9 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
                break;
        }
 
-       info->skb = skb;
-       info->encrypt_type = enctype;
-
-       ath10k_process_rx(htt->ar, info);
-}
-
-static bool ath10k_htt_rx_has_decrypt_err(struct sk_buff *skb)
-{
-       struct htt_rx_desc *rxd;
-       u32 flags;
-
-       rxd = (void *)skb->data - sizeof(*rxd);
-       flags = __le32_to_cpu(rxd->attention.flags);
-
-       if (flags & RX_ATTENTION_FLAGS_DECRYPT_ERR)
-               return true;
-
-       return false;
-}
-
-static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb)
-{
-       struct htt_rx_desc *rxd;
-       u32 flags;
-
-       rxd = (void *)skb->data - sizeof(*rxd);
-       flags = __le32_to_cpu(rxd->attention.flags);
-
-       if (flags & RX_ATTENTION_FLAGS_FCS_ERR)
-               return true;
-
-       return false;
-}
-
-static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb)
-{
-       struct htt_rx_desc *rxd;
-       u32 flags;
-
-       rxd = (void *)skb->data - sizeof(*rxd);
-       flags = __le32_to_cpu(rxd->attention.flags);
-
-       if (flags & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
-               return true;
-
-       return false;
-}
-
-static bool ath10k_htt_rx_is_mgmt(struct sk_buff *skb)
-{
-       struct htt_rx_desc *rxd;
-       u32 flags;
-
-       rxd = (void *)skb->data - sizeof(*rxd);
-       flags = __le32_to_cpu(rxd->attention.flags);
-
-       if (flags & RX_ATTENTION_FLAGS_MGMT_TYPE)
-               return true;
+       ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype);
 
-       return false;
+       ath10k_process_rx(htt->ar, rx_status, skb);
 }
 
 static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
@@ -952,21 +1087,73 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
        return 0;
 }
 
+static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
+                                       struct sk_buff *head,
+                                       enum htt_rx_mpdu_status status,
+                                       bool channel_set,
+                                       u32 attention)
+{
+       if (head->len == 0) {
+               ath10k_dbg(ATH10K_DBG_HTT,
+                          "htt rx dropping due to zero-len\n");
+               return false;
+       }
+
+       if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
+               ath10k_dbg(ATH10K_DBG_HTT,
+                          "htt rx dropping due to decrypt-err\n");
+               return false;
+       }
+
+       if (!channel_set) {
+               ath10k_warn("no channel configured; ignoring frame!\n");
+               return false;
+       }
+
+       /* Skip mgmt frames while we handle this in WMI */
+       if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
+           attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
+               ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
+               return false;
+       }
+
+       if (status != HTT_RX_IND_MPDU_STATUS_OK &&
+           status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
+           status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
+           !htt->ar->monitor_started) {
+               ath10k_dbg(ATH10K_DBG_HTT,
+                          "htt rx ignoring frame w/ status %d\n",
+                          status);
+               return false;
+       }
+
+       if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
+               ath10k_dbg(ATH10K_DBG_HTT,
+                          "htt rx CAC running\n");
+               return false;
+       }
+
+       return true;
+}
+
 static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                  struct htt_rx_indication *rx)
 {
-       struct htt_rx_info info;
+       struct ieee80211_rx_status *rx_status = &htt->rx_status;
        struct htt_rx_indication_mpdu_range *mpdu_ranges;
+       struct htt_rx_desc *rxd;
+       enum htt_rx_mpdu_status status;
        struct ieee80211_hdr *hdr;
        int num_mpdu_ranges;
+       u32 attention;
        int fw_desc_len;
        u8 *fw_desc;
+       bool channel_set;
        int i, j;
+       int ret;
 
        lockdep_assert_held(&htt->rx_ring.lock);
 
-       memset(&info, 0, sizeof(info));
-
        fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);
        fw_desc = (u8 *)&rx->fw_desc;
 
@@ -974,106 +1161,90 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                             HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
        mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
 
+       /* Fill this once, while this is per-ppdu */
+       if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) {
+               memset(rx_status, 0, sizeof(*rx_status));
+               rx_status->signal  = ATH10K_DEFAULT_NOISE_FLOOR +
+                                    rx->ppdu.combined_rssi;
+       }
+
+       if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
+               /* TSF available only in 32-bit */
+               rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff;
+               rx_status->flag |= RX_FLAG_MACTIME_END;
+       }
+
+       channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status);
+
+       if (channel_set) {
+               ath10k_htt_rx_h_rates(htt->ar, rx_status->band,
+                                     rx->ppdu.info0,
+                                     __le32_to_cpu(rx->ppdu.info1),
+                                     __le32_to_cpu(rx->ppdu.info2),
+                                     rx_status);
+       }
+
        ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
                        rx, sizeof(*rx) +
                        (sizeof(struct htt_rx_indication_mpdu_range) *
                                num_mpdu_ranges));
 
        for (i = 0; i < num_mpdu_ranges; i++) {
-               info.status = mpdu_ranges[i].mpdu_range_status;
+               status = mpdu_ranges[i].mpdu_range_status;
 
                for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {
                        struct sk_buff *msdu_head, *msdu_tail;
-                       enum htt_rx_mpdu_status status;
-                       int msdu_chaining;
 
                        msdu_head = NULL;
                        msdu_tail = NULL;
-                       msdu_chaining = ath10k_htt_rx_amsdu_pop(htt,
-                                                        &fw_desc,
-                                                        &fw_desc_len,
-                                                        &msdu_head,
-                                                        &msdu_tail);
-
-                       if (!msdu_head) {
-                               ath10k_warn("htt rx no data!\n");
-                               continue;
-                       }
-
-                       if (msdu_head->len == 0) {
-                               ath10k_dbg(ATH10K_DBG_HTT,
-                                          "htt rx dropping due to zero-len\n");
-                               ath10k_htt_rx_free_msdu_chain(msdu_head);
-                               continue;
-                       }
-
-                       if (ath10k_htt_rx_has_decrypt_err(msdu_head)) {
-                               ath10k_dbg(ATH10K_DBG_HTT,
-                                          "htt rx dropping due to decrypt-err\n");
+                       ret = ath10k_htt_rx_amsdu_pop(htt,
+                                                     &fw_desc,
+                                                     &fw_desc_len,
+                                                     &msdu_head,
+                                                     &msdu_tail);
+
+                       if (ret < 0) {
+                               ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
+                                           ret);
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
 
-                       status = info.status;
-
-                       /* Skip mgmt frames while we handle this in WMI */
-                       if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
-                           ath10k_htt_rx_is_mgmt(msdu_head)) {
-                               ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
-                               ath10k_htt_rx_free_msdu_chain(msdu_head);
-                               continue;
-                       }
+                       rxd = container_of((void *)msdu_head->data,
+                                          struct htt_rx_desc,
+                                          msdu_payload);
+                       attention = __le32_to_cpu(rxd->attention.flags);
 
-                       if (status != HTT_RX_IND_MPDU_STATUS_OK &&
-                           status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
-                           status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
-                           !htt->ar->monitor_enabled) {
-                               ath10k_dbg(ATH10K_DBG_HTT,
-                                          "htt rx ignoring frame w/ status %d\n",
-                                          status);
+                       if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head,
+                                                        status,
+                                                        channel_set,
+                                                        attention)) {
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
 
-                       if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
-                               ath10k_dbg(ATH10K_DBG_HTT,
-                                          "htt rx CAC running\n");
+                       if (ret > 0 &&
+                           ath10k_unchain_msdu(msdu_head) < 0) {
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
 
-                       if (msdu_chaining &&
-                           (ath10k_unchain_msdu(msdu_head) < 0)) {
-                               ath10k_htt_rx_free_msdu_chain(msdu_head);
-                               continue;
-                       }
-
-                       info.skb     = msdu_head;
-                       info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
-                       info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
-
-                       if (info.fcs_err)
-                               ath10k_dbg(ATH10K_DBG_HTT,
-                                          "htt rx has FCS err\n");
-
-                       if (info.mic_err)
-                               ath10k_dbg(ATH10K_DBG_HTT,
-                                          "htt rx has MIC err\n");
-
-                       info.signal  = ATH10K_DEFAULT_NOISE_FLOOR;
-                       info.signal += rx->ppdu.combined_rssi;
+                       if (attention & RX_ATTENTION_FLAGS_FCS_ERR)
+                               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+                       else
+                               rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC;
 
-                       info.rate.info0 = rx->ppdu.info0;
-                       info.rate.info1 = __le32_to_cpu(rx->ppdu.info1);
-                       info.rate.info2 = __le32_to_cpu(rx->ppdu.info2);
-                       info.tsf = __le32_to_cpu(rx->ppdu.tsf);
+                       if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
+                               rx_status->flag |= RX_FLAG_MMIC_ERROR;
+                       else
+                               rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
 
                        hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);
 
                        if (ath10k_htt_rx_hdr_is_amsdu(hdr))
-                               ath10k_htt_rx_amsdu(htt, &info);
+                               ath10k_htt_rx_amsdu(htt, rx_status, msdu_head);
                        else
-                               ath10k_htt_rx_msdu(htt, &info);
+                               ath10k_htt_rx_msdu(htt, rx_status, msdu_head);
                }
        }
 
@@ -1084,11 +1255,12 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
                                struct htt_rx_fragment_indication *frag)
 {
        struct sk_buff *msdu_head, *msdu_tail;
+       enum htt_rx_mpdu_encrypt_type enctype;
        struct htt_rx_desc *rxd;
        enum rx_msdu_decap_format fmt;
-       struct htt_rx_info info = {};
+       struct ieee80211_rx_status *rx_status = &htt->rx_status;
        struct ieee80211_hdr *hdr;
-       int msdu_chaining;
+       int ret;
        bool tkip_mic_err;
        bool decrypt_err;
        u8 *fw_desc;
@@ -1102,19 +1274,15 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
        msdu_tail = NULL;
 
        spin_lock_bh(&htt->rx_ring.lock);
-       msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
-                                               &msdu_head, &msdu_tail);
+       ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
+                                     &msdu_head, &msdu_tail);
        spin_unlock_bh(&htt->rx_ring.lock);
 
        ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
 
-       if (!msdu_head) {
-               ath10k_warn("htt rx frag no data\n");
-               return;
-       }
-
-       if (msdu_chaining || msdu_head != msdu_tail) {
-               ath10k_warn("aggregation with fragmentation?!\n");
+       if (ret) {
+               ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
+                           ret);
                ath10k_htt_rx_free_msdu_chain(msdu_head);
                return;
        }
@@ -1136,57 +1304,54 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
                goto end;
        }
 
-       info.skb = msdu_head;
-       info.status = HTT_RX_IND_MPDU_STATUS_OK;
-       info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0),
-                               RX_MPDU_START_INFO0_ENCRYPT_TYPE);
-       info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb);
+       enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
+                    RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+       ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype);
+       msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
 
-       if (tkip_mic_err) {
+       if (tkip_mic_err)
                ath10k_warn("tkip mic error\n");
-               info.status = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR;
-       }
 
        if (decrypt_err) {
                ath10k_warn("decryption err in fragmented rx\n");
-               dev_kfree_skb_any(info.skb);
+               dev_kfree_skb_any(msdu_head);
                goto end;
        }
 
-       if (info.encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) {
+       if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
                hdrlen = ieee80211_hdrlen(hdr->frame_control);
-               paramlen = ath10k_htt_rx_crypto_param_len(info.encrypt_type);
+               paramlen = ath10k_htt_rx_crypto_param_len(enctype);
 
                /* It is more efficient to move the header than the payload */
-               memmove((void *)info.skb->data + paramlen,
-                       (void *)info.skb->data,
+               memmove((void *)msdu_head->data + paramlen,
+                       (void *)msdu_head->data,
                        hdrlen);
-               skb_pull(info.skb, paramlen);
-               hdr = (struct ieee80211_hdr *)info.skb->data;
+               skb_pull(msdu_head, paramlen);
+               hdr = (struct ieee80211_hdr *)msdu_head->data;
        }
 
        /* remove trailing FCS */
        trim  = 4;
 
        /* remove crypto trailer */
-       trim += ath10k_htt_rx_crypto_tail_len(info.encrypt_type);
+       trim += ath10k_htt_rx_crypto_tail_len(enctype);
 
        /* last fragment of TKIP frags has MIC */
        if (!ieee80211_has_morefrags(hdr->frame_control) &&
-           info.encrypt_type == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
+           enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
                trim += 8;
 
-       if (trim > info.skb->len) {
+       if (trim > msdu_head->len) {
                ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
-               dev_kfree_skb_any(info.skb);
+               dev_kfree_skb_any(msdu_head);
                goto end;
        }
 
-       skb_trim(info.skb, info.skb->len - trim);
+       skb_trim(msdu_head, msdu_head->len - trim);
 
        ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
-                       info.skb->data, info.skb->len);
-       ath10k_process_rx(htt->ar, &info);
+                       msdu_head->data, msdu_head->len);
+       ath10k_process_rx(htt->ar, rx_status, msdu_head);
 
 end:
        if (fw_desc_len > 0) {
index 35fc44e281f57968171283d7d336cce5b20eddac..007e855f4ba99f9067725a11b85fdeadb3412483 100644 (file)
@@ -28,6 +28,7 @@
 #define QCA988X_HW_2_0_CHIP_ID_REV     0x2
 #define QCA988X_HW_2_0_FW_DIR          "ath10k/QCA988X/hw2.0"
 #define QCA988X_HW_2_0_FW_FILE         "firmware.bin"
+#define QCA988X_HW_2_0_FW_2_FILE       "firmware-2.bin"
 #define QCA988X_HW_2_0_OTP_FILE                "otp.bin"
 #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
index 511a2f81e7afc190419623235cdbefe9a66e4039..0ac5437492fd5c100b95f7f576491d2d6d5d0025 100644 (file)
@@ -165,7 +165,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
                        first_errno = ret;
 
                if (ret)
-                       ath10k_warn("could not remove peer wep key %d (%d)\n",
+                       ath10k_warn("failed to remove peer wep key %d: %d\n",
                                    i, ret);
 
                peer->keys[i] = NULL;
@@ -213,7 +213,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
                        first_errno = ret;
 
                if (ret)
-                       ath10k_warn("could not remove key for %pM\n", addr);
+                       ath10k_warn("failed to remove key for %pM: %d\n",
+                                   addr, ret);
        }
 
        return first_errno;
@@ -323,14 +324,14 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 
        ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
        if (ret) {
-               ath10k_warn("Failed to create wmi peer %pM on vdev %i: %i\n",
+               ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
                            addr, vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
        if (ret) {
-               ath10k_warn("Failed to wait for created wmi peer %pM on vdev %i: %i\n",
+               ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
                            addr, vdev_id, ret);
                return ret;
        }
@@ -351,7 +352,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_pdev_set_param(ar, param,
                                        ATH10K_KICKOUT_THRESHOLD);
        if (ret) {
-               ath10k_warn("Failed to set kickout threshold on vdev %i: %d\n",
+               ath10k_warn("failed to set kickout threshold on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -360,7 +361,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
                                        ATH10K_KEEPALIVE_MIN_IDLE);
        if (ret) {
-               ath10k_warn("Failed to set keepalive minimum idle time on vdev %i : %d\n",
+               ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -369,7 +370,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
                                        ATH10K_KEEPALIVE_MAX_IDLE);
        if (ret) {
-               ath10k_warn("Failed to set keepalive maximum idle time on vdev %i: %d\n",
+               ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -378,7 +379,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
                                        ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
        if (ret) {
-               ath10k_warn("Failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+               ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -488,92 +489,20 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
        return 0;
 }
 
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static bool ath10k_monitor_is_enabled(struct ath10k *ar)
 {
-       struct ath10k *ar = arvif->ar;
-       struct cfg80211_chan_def *chandef = &ar->chandef;
-       struct wmi_vdev_start_request_arg arg = {};
-       int ret = 0;
-
        lockdep_assert_held(&ar->conf_mutex);
 
-       reinit_completion(&ar->vdev_setup_done);
-
-       arg.vdev_id = arvif->vdev_id;
-       arg.dtim_period = arvif->dtim_period;
-       arg.bcn_intval = arvif->beacon_interval;
-
-       arg.channel.freq = chandef->chan->center_freq;
-       arg.channel.band_center_freq1 = chandef->center_freq1;
-       arg.channel.mode = chan_to_phymode(chandef);
-
-       arg.channel.min_power = 0;
-       arg.channel.max_power = chandef->chan->max_power * 2;
-       arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
-       arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
-
-       if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
-               arg.ssid = arvif->u.ap.ssid;
-               arg.ssid_len = arvif->u.ap.ssid_len;
-               arg.hidden_ssid = arvif->u.ap.hidden_ssid;
-
-               /* For now allow DFS for AP mode */
-               arg.channel.chan_radar =
-                       !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
-       } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
-               arg.ssid = arvif->vif->bss_conf.ssid;
-               arg.ssid_len = arvif->vif->bss_conf.ssid_len;
-       }
-
        ath10k_dbg(ATH10K_DBG_MAC,
-                  "mac vdev %d start center_freq %d phymode %s\n",
-                  arg.vdev_id, arg.channel.freq,
-                  ath10k_wmi_phymode_str(arg.channel.mode));
-
-       ret = ath10k_wmi_vdev_start(ar, &arg);
-       if (ret) {
-               ath10k_warn("WMI vdev %i start failed: ret %d\n",
-                           arg.vdev_id, ret);
-               return ret;
-       }
-
-       ret = ath10k_vdev_setup_sync(ar);
-       if (ret) {
-               ath10k_warn("vdev %i setup failed %d\n",
-                           arg.vdev_id, ret);
-               return ret;
-       }
-
-       return ret;
-}
-
-static int ath10k_vdev_stop(struct ath10k_vif *arvif)
-{
-       struct ath10k *ar = arvif->ar;
-       int ret;
+                  "mac monitor refs: promisc %d monitor %d cac %d\n",
+                  ar->promisc, ar->monitor,
+                  test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
 
-       lockdep_assert_held(&ar->conf_mutex);
-
-       reinit_completion(&ar->vdev_setup_done);
-
-       ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
-       if (ret) {
-               ath10k_warn("WMI vdev %i stop failed: ret %d\n",
-                           arvif->vdev_id, ret);
-               return ret;
-       }
-
-       ret = ath10k_vdev_setup_sync(ar);
-       if (ret) {
-               ath10k_warn("vdev %i setup sync failed %d\n",
-                           arvif->vdev_id, ret);
-               return ret;
-       }
-
-       return ret;
+       return ar->promisc || ar->monitor ||
+              test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 }
 
-static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
+static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 {
        struct cfg80211_chan_def *chandef = &ar->chandef;
        struct ieee80211_channel *channel = chandef->chan;
@@ -582,11 +511,6 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (!ar->monitor_present) {
-               ath10k_warn("mac montor stop -- monitor is not present\n");
-               return -EINVAL;
-       }
-
        arg.vdev_id = vdev_id;
        arg.channel.freq = channel->center_freq;
        arg.channel.band_center_freq1 = chandef->center_freq1;
@@ -604,88 +528,75 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 
        ret = ath10k_wmi_vdev_start(ar, &arg);
        if (ret) {
-               ath10k_warn("Monitor vdev %i start failed: ret %d\n",
+               ath10k_warn("failed to request monitor vdev %i start: %d\n",
                            vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
-               ath10k_warn("Monitor vdev %i setup failed %d\n",
+               ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n",
                            vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
        if (ret) {
-               ath10k_warn("Monitor vdev %i up failed: %d\n",
+               ath10k_warn("failed to put up monitor vdev %i: %d\n",
                            vdev_id, ret);
                goto vdev_stop;
        }
 
        ar->monitor_vdev_id = vdev_id;
-       ar->monitor_enabled = true;
 
+       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
+                  ar->monitor_vdev_id);
        return 0;
 
 vdev_stop:
        ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
        if (ret)
-               ath10k_warn("Monitor vdev %i stop failed: %d\n",
+               ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n",
                            ar->monitor_vdev_id, ret);
 
        return ret;
 }
 
-static int ath10k_monitor_stop(struct ath10k *ar)
+static int ath10k_monitor_vdev_stop(struct ath10k *ar)
 {
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (!ar->monitor_present) {
-               ath10k_warn("mac montor stop -- monitor is not present\n");
-               return -EINVAL;
-       }
-
-       if (!ar->monitor_enabled) {
-               ath10k_warn("mac montor stop -- monitor is not enabled\n");
-               return -EINVAL;
-       }
-
        ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
        if (ret)
-               ath10k_warn("Monitor vdev %i down failed: %d\n",
+               ath10k_warn("failed to put down monitor vdev %i: %d\n",
                            ar->monitor_vdev_id, ret);
 
        ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
        if (ret)
-               ath10k_warn("Monitor vdev %i stop failed: %d\n",
+               ath10k_warn("failed to to request monitor vdev %i stop: %d\n",
                            ar->monitor_vdev_id, ret);
 
        ret = ath10k_vdev_setup_sync(ar);
        if (ret)
-               ath10k_warn("Monitor_down sync failed, vdev %i: %d\n",
+               ath10k_warn("failed to synchronise monitor vdev %i: %d\n",
                            ar->monitor_vdev_id, ret);
 
-       ar->monitor_enabled = false;
+       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
+                  ar->monitor_vdev_id);
        return ret;
 }
 
-static int ath10k_monitor_create(struct ath10k *ar)
+static int ath10k_monitor_vdev_create(struct ath10k *ar)
 {
        int bit, ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (ar->monitor_present) {
-               ath10k_warn("Monitor mode already enabled\n");
-               return 0;
-       }
-
        bit = ffs(ar->free_vdev_map);
        if (bit == 0) {
-               ath10k_warn("No free VDEV slots\n");
+               ath10k_warn("failed to find free vdev id for monitor vdev\n");
                return -ENOMEM;
        }
 
@@ -696,7 +607,7 @@ static int ath10k_monitor_create(struct ath10k *ar)
                                     WMI_VDEV_TYPE_MONITOR,
                                     0, ar->mac_addr);
        if (ret) {
-               ath10k_warn("WMI vdev %i monitor create failed: ret %d\n",
+               ath10k_warn("failed to request monitor vdev %i creation: %d\n",
                            ar->monitor_vdev_id, ret);
                goto vdev_fail;
        }
@@ -704,7 +615,6 @@ static int ath10k_monitor_create(struct ath10k *ar)
        ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
                   ar->monitor_vdev_id);
 
-       ar->monitor_present = true;
        return 0;
 
 vdev_fail:
@@ -715,48 +625,123 @@ vdev_fail:
        return ret;
 }
 
-static int ath10k_monitor_destroy(struct ath10k *ar)
+static int ath10k_monitor_vdev_delete(struct ath10k *ar)
 {
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (!ar->monitor_present)
-               return 0;
-
        ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
        if (ret) {
-               ath10k_warn("WMI vdev %i monitor delete failed: %d\n",
+               ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n",
                            ar->monitor_vdev_id, ret);
                return ret;
        }
 
        ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
-       ar->monitor_present = false;
 
        ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
                   ar->monitor_vdev_id);
        return ret;
 }
 
-static int ath10k_start_cac(struct ath10k *ar)
+static int ath10k_monitor_start(struct ath10k *ar)
 {
        int ret;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+       if (!ath10k_monitor_is_enabled(ar)) {
+               ath10k_warn("trying to start monitor with no references\n");
+               return 0;
+       }
+
+       if (ar->monitor_started) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n");
+               return 0;
+       }
 
-       ret = ath10k_monitor_create(ar);
+       ret = ath10k_monitor_vdev_create(ar);
        if (ret) {
-               clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+               ath10k_warn("failed to create monitor vdev: %d\n", ret);
                return ret;
        }
 
-       ret = ath10k_monitor_start(ar, ar->monitor_vdev_id);
+       ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
        if (ret) {
+               ath10k_warn("failed to start monitor vdev: %d\n", ret);
+               ath10k_monitor_vdev_delete(ar);
+               return ret;
+       }
+
+       ar->monitor_started = true;
+       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n");
+
+       return 0;
+}
+
+static void ath10k_monitor_stop(struct ath10k *ar)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (ath10k_monitor_is_enabled(ar)) {
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac monitor will be stopped later\n");
+               return;
+       }
+
+       if (!ar->monitor_started) {
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac monitor probably failed to start earlier\n");
+               return;
+       }
+
+       ret = ath10k_monitor_vdev_stop(ar);
+       if (ret)
+               ath10k_warn("failed to stop monitor vdev: %d\n", ret);
+
+       ret = ath10k_monitor_vdev_delete(ar);
+       if (ret)
+               ath10k_warn("failed to delete monitor vdev: %d\n", ret);
+
+       ar->monitor_started = false;
+       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n");
+}
+
+static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+       u32 vdev_param, rts_cts = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       vdev_param = ar->wmi.vdev_param->enable_rtscts;
+
+       if (arvif->use_cts_prot || arvif->num_legacy_stations > 0)
+               rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET);
+
+       if (arvif->num_legacy_stations > 0)
+               rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES,
+                             WMI_RTSCTS_PROFILE);
+
+       return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+                                        rts_cts);
+}
+
+static int ath10k_start_cac(struct ath10k *ar)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+       ret = ath10k_monitor_start(ar);
+       if (ret) {
+               ath10k_warn("failed to start monitor (cac): %d\n", ret);
                clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
-               ath10k_monitor_destroy(ar);
                return ret;
        }
 
@@ -774,58 +759,26 @@ static int ath10k_stop_cac(struct ath10k *ar)
        if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags))
                return 0;
 
-       ath10k_monitor_stop(ar);
-       ath10k_monitor_destroy(ar);
        clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+       ath10k_monitor_stop(ar);
 
        ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
 
        return 0;
 }
 
-static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state)
-{
-       switch (dfs_state) {
-       case NL80211_DFS_USABLE:
-               return "USABLE";
-       case NL80211_DFS_UNAVAILABLE:
-               return "UNAVAILABLE";
-       case NL80211_DFS_AVAILABLE:
-               return "AVAILABLE";
-       default:
-               WARN_ON(1);
-               return "bug";
-       }
-}
-
-static void ath10k_config_radar_detection(struct ath10k *ar)
+static void ath10k_recalc_radar_detection(struct ath10k *ar)
 {
-       struct ieee80211_channel *chan = ar->hw->conf.chandef.chan;
-       bool radar = ar->hw->conf.radar_enabled;
-       bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR);
-       enum nl80211_dfs_state dfs_state = chan->dfs_state;
        int ret;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       ath10k_dbg(ATH10K_DBG_MAC,
-                  "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n",
-                  chan->center_freq, radar, chan_radar,
-                  ath10k_dfs_state(dfs_state));
-
-       /*
-        * It's safe to call it even if CAC is not started.
-        * This call here guarantees changing channel, etc. will stop CAC.
-        */
        ath10k_stop_cac(ar);
 
-       if (!radar)
-               return;
-
-       if (!chan_radar)
+       if (!ar->radar_enabled)
                return;
 
-       if (dfs_state != NL80211_DFS_USABLE)
+       if (ar->num_started_vdevs > 0)
                return;
 
        ret = ath10k_start_cac(ar);
@@ -835,11 +788,106 @@ static void ath10k_config_radar_detection(struct ath10k *ar)
                 * radiation is not allowed, make this channel DFS_UNAVAILABLE
                 * by indicating that radar was detected.
                 */
-               ath10k_warn("failed to start CAC (%d)\n", ret);
+               ath10k_warn("failed to start CAC: %d\n", ret);
                ieee80211_radar_detected(ar->hw);
        }
 }
 
+static int ath10k_vdev_start(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+       struct cfg80211_chan_def *chandef = &ar->chandef;
+       struct wmi_vdev_start_request_arg arg = {};
+       int ret = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       reinit_completion(&ar->vdev_setup_done);
+
+       arg.vdev_id = arvif->vdev_id;
+       arg.dtim_period = arvif->dtim_period;
+       arg.bcn_intval = arvif->beacon_interval;
+
+       arg.channel.freq = chandef->chan->center_freq;
+       arg.channel.band_center_freq1 = chandef->center_freq1;
+       arg.channel.mode = chan_to_phymode(chandef);
+
+       arg.channel.min_power = 0;
+       arg.channel.max_power = chandef->chan->max_power * 2;
+       arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
+       arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
+
+       if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+               arg.ssid = arvif->u.ap.ssid;
+               arg.ssid_len = arvif->u.ap.ssid_len;
+               arg.hidden_ssid = arvif->u.ap.hidden_ssid;
+
+               /* For now allow DFS for AP mode */
+               arg.channel.chan_radar =
+                       !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
+       } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
+               arg.ssid = arvif->vif->bss_conf.ssid;
+               arg.ssid_len = arvif->vif->bss_conf.ssid_len;
+       }
+
+       ath10k_dbg(ATH10K_DBG_MAC,
+                  "mac vdev %d start center_freq %d phymode %s\n",
+                  arg.vdev_id, arg.channel.freq,
+                  ath10k_wmi_phymode_str(arg.channel.mode));
+
+       ret = ath10k_wmi_vdev_start(ar, &arg);
+       if (ret) {
+               ath10k_warn("failed to start WMI vdev %i: %d\n",
+                           arg.vdev_id, ret);
+               return ret;
+       }
+
+       ret = ath10k_vdev_setup_sync(ar);
+       if (ret) {
+               ath10k_warn("failed to synchronise setup for vdev %i: %d\n",
+                           arg.vdev_id, ret);
+               return ret;
+       }
+
+       ar->num_started_vdevs++;
+       ath10k_recalc_radar_detection(ar);
+
+       return ret;
+}
+
+static int ath10k_vdev_stop(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       reinit_completion(&ar->vdev_setup_done);
+
+       ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
+       if (ret) {
+               ath10k_warn("failed to stop WMI vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       ret = ath10k_vdev_setup_sync(ar);
+       if (ret) {
+               ath10k_warn("failed to syncronise setup for vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       WARN_ON(ar->num_started_vdevs == 0);
+
+       if (ar->num_started_vdevs != 0) {
+               ar->num_started_vdevs--;
+               ath10k_recalc_radar_detection(ar);
+       }
+
+       return ret;
+}
+
 static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                                struct ieee80211_bss_conf *info)
 {
@@ -880,7 +928,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
        ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
                                 arvif->bssid);
        if (ret) {
-               ath10k_warn("Failed to bring up vdev %d: %i\n",
+               ath10k_warn("failed to bring up vdev %d: %i\n",
                            arvif->vdev_id, ret);
                ath10k_vdev_stop(arvif);
                return;
@@ -904,7 +952,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
        if (!info->ibss_joined) {
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
                if (ret)
-                       ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
+                       ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",
                                    self_peer, arvif->vdev_id, ret);
 
                if (is_zero_ether_addr(arvif->bssid))
@@ -913,7 +961,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
                                         arvif->bssid);
                if (ret) {
-                       ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
+                       ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
                                    arvif->bssid, arvif->vdev_id, ret);
                        return;
                }
@@ -925,7 +973,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
 
        ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
        if (ret) {
-               ath10k_warn("Failed to create IBSS self peer:%pM for VDEV:%d ret:%d\n",
+               ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",
                            self_peer, arvif->vdev_id, ret);
                return;
        }
@@ -934,7 +982,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
        ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
                                        ATH10K_DEFAULT_ATIM);
        if (ret)
-               ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n",
+               ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",
                            arvif->vdev_id, ret);
 }
 
@@ -961,7 +1009,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
                                                  conf->dynamic_ps_timeout);
                if (ret) {
-                       ath10k_warn("Failed to set inactivity time for vdev %d: %i\n",
+                       ath10k_warn("failed to set inactivity time for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -974,8 +1022,8 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
 
        ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
        if (ret) {
-               ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n",
-                           psmode, arvif->vdev_id);
+               ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n",
+                           psmode, arvif->vdev_id, ret);
                return ret;
        }
 
@@ -1429,7 +1477,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
        if (!ap_sta) {
-               ath10k_warn("Failed to find station entry for %pM, vdev %i\n",
+               ath10k_warn("failed to find station entry for bss %pM vdev %i\n",
                            bss_conf->bssid, arvif->vdev_id);
                rcu_read_unlock();
                return;
@@ -1442,7 +1490,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
        ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
                                        bss_conf, &peer_arg);
        if (ret) {
-               ath10k_warn("Peer assoc prepare failed for %pM vdev %i\n: %d",
+               ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n",
                            bss_conf->bssid, arvif->vdev_id, ret);
                rcu_read_unlock();
                return;
@@ -1452,7 +1500,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
        if (ret) {
-               ath10k_warn("Peer assoc failed for %pM vdev %i\n: %d",
+               ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n",
                            bss_conf->bssid, arvif->vdev_id, ret);
                return;
        }
@@ -1473,7 +1521,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
        if (ret) {
-               ath10k_warn("VDEV: %d up failed: ret %d\n",
+               ath10k_warn("failed to set vdev %d up: %d\n",
                            arvif->vdev_id, ret);
                return;
        }
@@ -1524,7 +1572,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
 }
 
 static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
-                               struct ieee80211_sta *sta)
+                               struct ieee80211_sta *sta, bool reassoc)
 {
        struct wmi_peer_assoc_complete_arg peer_arg;
        int ret = 0;
@@ -1533,34 +1581,46 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
 
        ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
        if (ret) {
-               ath10k_warn("WMI peer assoc prepare failed for %pM vdev %i: %i\n",
+               ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
                            sta->addr, arvif->vdev_id, ret);
                return ret;
        }
 
+       peer_arg.peer_reassoc = reassoc;
        ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
        if (ret) {
-               ath10k_warn("Peer assoc failed for STA %pM vdev %i: %d\n",
+               ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n",
                            sta->addr, arvif->vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
        if (ret) {
-               ath10k_warn("failed to setup peer SMPS for vdev: %d\n", ret);
+               ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n",
+                           arvif->vdev_id, ret);
                return ret;
        }
 
+       if (!sta->wme) {
+               arvif->num_legacy_stations++;
+               ret  = ath10k_recalc_rtscts_prot(arvif);
+               if (ret) {
+                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
+       }
+
        ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
        if (ret) {
-               ath10k_warn("could not install peer wep keys for vdev %i: %d\n",
+               ath10k_warn("failed to install peer wep keys for vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
        if (ret) {
-               ath10k_warn("could not set qos params for STA %pM for vdev %i: %d\n",
+               ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n",
                            sta->addr, arvif->vdev_id, ret);
                return ret;
        }
@@ -1575,9 +1635,19 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       if (!sta->wme) {
+               arvif->num_legacy_stations--;
+               ret = ath10k_recalc_rtscts_prot(arvif);
+               if (ret) {
+                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
+       }
+
        ret = ath10k_clear_peer_keys(arvif, sta->addr);
        if (ret) {
-               ath10k_warn("could not clear all peer wep keys for vdev %i: %d\n",
+               ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -1685,19 +1755,44 @@ static int ath10k_update_channel_list(struct ath10k *ar)
        return ret;
 }
 
+static enum wmi_dfs_region
+ath10k_mac_get_dfs_region(enum nl80211_dfs_regions dfs_region)
+{
+       switch (dfs_region) {
+       case NL80211_DFS_UNSET:
+               return WMI_UNINIT_DFS_DOMAIN;
+       case NL80211_DFS_FCC:
+               return WMI_FCC_DFS_DOMAIN;
+       case NL80211_DFS_ETSI:
+               return WMI_ETSI_DFS_DOMAIN;
+       case NL80211_DFS_JP:
+               return WMI_MKK4_DFS_DOMAIN;
+       }
+       return WMI_UNINIT_DFS_DOMAIN;
+}
+
 static void ath10k_regd_update(struct ath10k *ar)
 {
        struct reg_dmn_pair_mapping *regpair;
        int ret;
+       enum wmi_dfs_region wmi_dfs_reg;
+       enum nl80211_dfs_regions nl_dfs_reg;
 
        lockdep_assert_held(&ar->conf_mutex);
 
        ret = ath10k_update_channel_list(ar);
        if (ret)
-               ath10k_warn("could not update channel list (%d)\n", ret);
+               ath10k_warn("failed to update channel list: %d\n", ret);
 
        regpair = ar->ath_common.regulatory.regpair;
 
+       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+               nl_dfs_reg = ar->dfs_detector->region;
+               wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg);
+       } else {
+               wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN;
+       }
+
        /* Target allows setting up per-band regdomain but ath_common provides
         * a combined one only */
        ret = ath10k_wmi_pdev_set_regdomain(ar,
@@ -1705,9 +1800,10 @@ static void ath10k_regd_update(struct ath10k *ar)
                                            regpair->reg_domain, /* 2ghz */
                                            regpair->reg_domain, /* 5ghz */
                                            regpair->reg_2ghz_ctl,
-                                           regpair->reg_5ghz_ctl);
+                                           regpair->reg_5ghz_ctl,
+                                           wmi_dfs_reg);
        if (ret)
-               ath10k_warn("could not set pdev regdomain (%d)\n", ret);
+               ath10k_warn("failed to set pdev regdomain: %d\n", ret);
 }
 
 static void ath10k_reg_notifier(struct wiphy *wiphy,
@@ -1725,7 +1821,7 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
                result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
                                                          request->dfs_region);
                if (!result)
-                       ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n",
+                       ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n",
                                    request->dfs_region);
        }
 
@@ -1759,10 +1855,10 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
        if (info->control.vif)
                return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
 
-       if (ar->monitor_enabled)
+       if (ar->monitor_started)
                return ar->monitor_vdev_id;
 
-       ath10k_warn("could not resolve vdev id\n");
+       ath10k_warn("failed to resolve vdev id\n");
        return 0;
 }
 
@@ -1803,7 +1899,9 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
                                        arvif->ar->wmi.vdev_param->def_keyid,
                                        keyidx);
        if (ret) {
-               ath10k_warn("could not update wep keyidx (%d)\n", ret);
+               ath10k_warn("failed to update wep key index for vdev %d: %d\n",
+                           arvif->vdev_id,
+                           ret);
                return;
        }
 
@@ -1879,7 +1977,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
                             ar->fw_features)) {
                        if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
                            ATH10K_MAX_NUM_MGMT_PENDING) {
-                               ath10k_warn("wmi mgmt_tx queue limit reached\n");
+                               ath10k_warn("reached WMI management tranmist queue limit\n");
                                ret = -EBUSY;
                                goto exit;
                        }
@@ -1903,7 +2001,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
 
 exit:
        if (ret) {
-               ath10k_warn("tx failed (%d). dropping packet.\n", ret);
+               ath10k_warn("failed to transmit packet, dropping: %d\n", ret);
                ieee80211_free_txskb(ar->hw, skb);
        }
 }
@@ -1964,7 +2062,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
                if (!peer) {
                        ret = ath10k_peer_create(ar, vdev_id, peer_addr);
                        if (ret)
-                               ath10k_warn("peer %pM on vdev %d not created (%d)\n",
+                               ath10k_warn("failed to create peer %pM on vdev %d: %d\n",
                                            peer_addr, vdev_id, ret);
                }
 
@@ -1984,7 +2082,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
                if (!peer) {
                        ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
                        if (ret)
-                               ath10k_warn("peer %pM on vdev %d not deleted (%d)\n",
+                               ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",
                                            peer_addr, vdev_id, ret);
                }
 
@@ -2018,7 +2116,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
 
                ret = ath10k_wmi_mgmt_tx(ar, skb);
                if (ret) {
-                       ath10k_warn("wmi mgmt_tx failed (%d)\n", ret);
+                       ath10k_warn("failed to transmit management frame via WMI: %d\n",
+                                   ret);
                        ieee80211_free_txskb(ar->hw, skb);
                }
        }
@@ -2043,7 +2142,7 @@ void ath10k_reset_scan(unsigned long ptr)
                return;
        }
 
-       ath10k_warn("scan timeout. resetting. fw issue?\n");
+       ath10k_warn("scan timed out, firmware problem?\n");
 
        if (ar->scan.is_roc)
                ieee80211_remain_on_channel_expired(ar->hw);
@@ -2079,7 +2178,7 @@ static int ath10k_abort_scan(struct ath10k *ar)
 
        ret = ath10k_wmi_stop_scan(ar, &arg);
        if (ret) {
-               ath10k_warn("could not submit wmi stop scan (%d)\n", ret);
+               ath10k_warn("failed to stop wmi scan: %d\n", ret);
                spin_lock_bh(&ar->data_lock);
                ar->scan.in_progress = false;
                ath10k_offchan_tx_purge(ar);
@@ -2099,7 +2198,7 @@ static int ath10k_abort_scan(struct ath10k *ar)
 
        spin_lock_bh(&ar->data_lock);
        if (ar->scan.in_progress) {
-               ath10k_warn("could not stop scan. its still in progress\n");
+               ath10k_warn("failed to stop scan, it's still in progress\n");
                ar->scan.in_progress = false;
                ath10k_offchan_tx_purge(ar);
                ret = -ETIMEDOUT;
@@ -2194,7 +2293,13 @@ void ath10k_halt(struct ath10k *ar)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
-       ath10k_stop_cac(ar);
+       if (ath10k_monitor_is_enabled(ar)) {
+               clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+               ar->promisc = false;
+               ar->monitor = false;
+               ath10k_monitor_stop(ar);
+       }
+
        del_timer_sync(&ar->scan.timeout);
        ath10k_offchan_tx_purge(ar);
        ath10k_mgmt_over_wmi_tx_purge(ar);
@@ -2226,14 +2331,14 @@ static int ath10k_start(struct ieee80211_hw *hw)
 
        ret = ath10k_hif_power_up(ar);
        if (ret) {
-               ath10k_err("could not init hif (%d)\n", ret);
+               ath10k_err("Could not init hif: %d\n", ret);
                ar->state = ATH10K_STATE_OFF;
                goto exit;
        }
 
        ret = ath10k_core_start(ar);
        if (ret) {
-               ath10k_err("could not init core (%d)\n", ret);
+               ath10k_err("Could not init core: %d\n", ret);
                ath10k_hif_power_down(ar);
                ar->state = ATH10K_STATE_OFF;
                goto exit;
@@ -2246,13 +2351,11 @@ static int ath10k_start(struct ieee80211_hw *hw)
 
        ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
        if (ret)
-               ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
-                           ret);
+               ath10k_warn("failed to enable PMF QOS: %d\n", ret);
 
        ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
        if (ret)
-               ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
-                           ret);
+               ath10k_warn("failed to enable dynamic BW: %d\n", ret);
 
        /*
         * By default FW set ARP frames ac to voice (6). In that case ARP
@@ -2266,11 +2369,12 @@ static int ath10k_start(struct ieee80211_hw *hw)
        ret = ath10k_wmi_pdev_set_param(ar,
                                        ar->wmi.pdev_param->arp_ac_override, 0);
        if (ret) {
-               ath10k_warn("could not set arp ac override parameter: %d\n",
+               ath10k_warn("failed to set arp ac override parameter: %d\n",
                            ret);
                goto exit;
        }
 
+       ar->num_started_vdevs = 0;
        ath10k_regd_update(ar);
        ret = 0;
 
@@ -2309,7 +2413,7 @@ static int ath10k_config_ps(struct ath10k *ar)
        list_for_each_entry(arvif, &ar->arvifs, list) {
                ret = ath10k_mac_vif_setup_ps(arvif);
                if (ret) {
-                       ath10k_warn("could not setup powersave (%d)\n", ret);
+                       ath10k_warn("failed to setup powersave: %d\n", ret);
                        break;
                }
        }
@@ -2343,7 +2447,6 @@ static const char *chandef_get_width(enum nl80211_chan_width width)
 static void ath10k_config_chan(struct ath10k *ar)
 {
        struct ath10k_vif *arvif;
-       bool monitor_was_enabled;
        int ret;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -2357,10 +2460,8 @@ static void ath10k_config_chan(struct ath10k *ar)
 
        /* First stop monitor interface. Some FW versions crash if there's a
         * lone monitor interface. */
-       monitor_was_enabled = ar->monitor_enabled;
-
-       if (ar->monitor_enabled)
-               ath10k_monitor_stop(ar);
+       if (ar->monitor_started)
+               ath10k_monitor_vdev_stop(ar);
 
        list_for_each_entry(arvif, &ar->arvifs, list) {
                if (!arvif->is_started)
@@ -2371,7 +2472,7 @@ static void ath10k_config_chan(struct ath10k *ar)
 
                ret = ath10k_vdev_stop(arvif);
                if (ret) {
-                       ath10k_warn("could not stop vdev %d (%d)\n",
+                       ath10k_warn("failed to stop vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        continue;
                }
@@ -2388,7 +2489,7 @@ static void ath10k_config_chan(struct ath10k *ar)
 
                ret = ath10k_vdev_start(arvif);
                if (ret) {
-                       ath10k_warn("could not start vdev %d (%d)\n",
+                       ath10k_warn("failed to start vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        continue;
                }
@@ -2399,14 +2500,14 @@ static void ath10k_config_chan(struct ath10k *ar)
                ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
                                         arvif->bssid);
                if (ret) {
-                       ath10k_warn("could not bring vdev up %d (%d)\n",
+                       ath10k_warn("failed to bring vdev up %d: %d\n",
                                    arvif->vdev_id, ret);
                        continue;
                }
        }
 
-       if (monitor_was_enabled)
-               ath10k_monitor_start(ar, ar->monitor_vdev_id);
+       if (ath10k_monitor_is_enabled(ar))
+               ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
 }
 
 static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2420,15 +2521,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                ath10k_dbg(ATH10K_DBG_MAC,
-                          "mac config channel %d mhz flags 0x%x\n",
+                          "mac config channel %dMHz flags 0x%x radar %d\n",
                           conf->chandef.chan->center_freq,
-                          conf->chandef.chan->flags);
+                          conf->chandef.chan->flags,
+                          conf->radar_enabled);
 
                spin_lock_bh(&ar->data_lock);
                ar->rx_channel = conf->chandef.chan;
                spin_unlock_bh(&ar->data_lock);
 
-               ath10k_config_radar_detection(ar);
+               ar->radar_enabled = conf->radar_enabled;
+               ath10k_recalc_radar_detection(ar);
 
                if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
                        ar->chandef = conf->chandef;
@@ -2444,14 +2547,14 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                ret = ath10k_wmi_pdev_set_param(ar, param,
                                                hw->conf.power_level * 2);
                if (ret)
-                       ath10k_warn("mac failed to set 2g txpower %d (%d)\n",
+                       ath10k_warn("failed to set 2g txpower %d: %d\n",
                                    hw->conf.power_level, ret);
 
                param = ar->wmi.pdev_param->txpower_limit5g;
                ret = ath10k_wmi_pdev_set_param(ar, param,
                                                hw->conf.power_level * 2);
                if (ret)
-                       ath10k_warn("mac failed to set 5g txpower %d (%d)\n",
+                       ath10k_warn("failed to set 5g txpower %d: %d\n",
                                    hw->conf.power_level, ret);
        }
 
@@ -2459,10 +2562,19 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                ath10k_config_ps(ar);
 
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-               if (conf->flags & IEEE80211_CONF_MONITOR)
-                       ret = ath10k_monitor_create(ar);
-               else
-                       ret = ath10k_monitor_destroy(ar);
+               if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) {
+                       ar->monitor = true;
+                       ret = ath10k_monitor_start(ar);
+                       if (ret) {
+                               ath10k_warn("failed to start monitor (config): %d\n",
+                                           ret);
+                               ar->monitor = false;
+                       }
+               } else if (!(conf->flags & IEEE80211_CONF_MONITOR) &&
+                          ar->monitor) {
+                       ar->monitor = false;
+                       ath10k_monitor_stop(ar);
+               }
        }
 
        mutex_unlock(&ar->conf_mutex);
@@ -2497,12 +2609,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
        INIT_LIST_HEAD(&arvif->list);
 
-       if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) {
-               ath10k_warn("Only one monitor interface allowed\n");
-               ret = -EBUSY;
-               goto err;
-       }
-
        bit = ffs(ar->free_vdev_map);
        if (bit == 0) {
                ret = -EBUSY;
@@ -2545,7 +2651,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
                                     arvif->vdev_subtype, vif->addr);
        if (ret) {
-               ath10k_warn("WMI vdev %i create failed: ret %d\n",
+               ath10k_warn("failed to create WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
                goto err;
        }
@@ -2557,7 +2663,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
                                        arvif->def_wep_key_idx);
        if (ret) {
-               ath10k_warn("Failed to set vdev %i default keyid: %d\n",
+               ath10k_warn("failed to set vdev %i default key id: %d\n",
                            arvif->vdev_id, ret);
                goto err_vdev_delete;
        }
@@ -2567,7 +2673,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                                        ATH10K_HW_TXRX_NATIVE_WIFI);
        /* 10.X firmware does not support this VDEV parameter. Do not warn */
        if (ret && ret != -EOPNOTSUPP) {
-               ath10k_warn("Failed to set vdev %i TX encap: %d\n",
+               ath10k_warn("failed to set vdev %i TX encapsulation: %d\n",
                            arvif->vdev_id, ret);
                goto err_vdev_delete;
        }
@@ -2575,14 +2681,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
                ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
                if (ret) {
-                       ath10k_warn("Failed to create vdev %i peer for AP: %d\n",
+                       ath10k_warn("failed to create vdev %i peer for AP: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_vdev_delete;
                }
 
                ret = ath10k_mac_set_kickout(arvif);
                if (ret) {
-                       ath10k_warn("Failed to set vdev %i kickout parameters: %d\n",
+                       ath10k_warn("failed to set vdev %i kickout parameters: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2594,7 +2700,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
                                                  param, value);
                if (ret) {
-                       ath10k_warn("Failed to set vdev %i RX wake policy: %d\n",
+                       ath10k_warn("failed to set vdev %i RX wake policy: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2604,7 +2710,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
                                                  param, value);
                if (ret) {
-                       ath10k_warn("Failed to set vdev %i TX wake thresh: %d\n",
+                       ath10k_warn("failed to set vdev %i TX wake thresh: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2614,7 +2720,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
                                                  param, value);
                if (ret) {
-                       ath10k_warn("Failed to set vdev %i PSPOLL count: %d\n",
+                       ath10k_warn("failed to set vdev %i PSPOLL count: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2622,21 +2728,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 
        ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
        if (ret) {
-               ath10k_warn("failed to set rts threshold for vdev %d (%d)\n",
+               ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
                            arvif->vdev_id, ret);
                goto err_peer_delete;
        }
 
        ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
        if (ret) {
-               ath10k_warn("failed to set frag threshold for vdev %d (%d)\n",
+               ath10k_warn("failed to set frag threshold for vdev %d: %d\n",
                            arvif->vdev_id, ret);
                goto err_peer_delete;
        }
 
-       if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
-               ar->monitor_present = true;
-
        mutex_unlock(&ar->conf_mutex);
        return 0;
 
@@ -2679,7 +2782,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
                if (ret)
-                       ath10k_warn("Failed to remove peer for AP vdev %i: %d\n",
+                       ath10k_warn("failed to remove peer for AP vdev %i: %d\n",
                                    arvif->vdev_id, ret);
 
                kfree(arvif->u.ap.noa_data);
@@ -2690,12 +2793,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 
        ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
        if (ret)
-               ath10k_warn("WMI vdev %i delete failed: %d\n",
+               ath10k_warn("failed to delete WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
 
-       if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
-               ar->monitor_present = false;
-
        ath10k_peer_cleanup(ar, arvif->vdev_id);
 
        mutex_unlock(&ar->conf_mutex);
@@ -2728,28 +2828,17 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
        *total_flags &= SUPPORTED_FILTERS;
        ar->filter_flags = *total_flags;
 
-       /* Monitor must not be started if it wasn't created first.
-        * Promiscuous mode may be started on a non-monitor interface - in
-        * such case the monitor vdev is not created so starting the
-        * monitor makes no sense. Since ath10k uses no special RX filters
-        * (only BSS filter in STA mode) there's no need for any special
-        * action here. */
-       if ((ar->filter_flags & FIF_PROMISC_IN_BSS) &&
-           !ar->monitor_enabled && ar->monitor_present) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n",
-                          ar->monitor_vdev_id);
-
-               ret = ath10k_monitor_start(ar, ar->monitor_vdev_id);
-               if (ret)
-                       ath10k_warn("Unable to start monitor mode\n");
-       } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) &&
-                  ar->monitor_enabled && ar->monitor_present) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n",
-                          ar->monitor_vdev_id);
-
-               ret = ath10k_monitor_stop(ar);
-               if (ret)
-                       ath10k_warn("Unable to stop monitor mode\n");
+       if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) {
+               ar->promisc = true;
+               ret = ath10k_monitor_start(ar);
+               if (ret) {
+                       ath10k_warn("failed to start monitor (promisc): %d\n",
+                                   ret);
+                       ar->promisc = false;
+               }
+       } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) {
+               ar->promisc = false;
+               ath10k_monitor_stop(ar);
        }
 
        mutex_unlock(&ar->conf_mutex);
@@ -2780,7 +2869,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                           arvif->vdev_id, arvif->beacon_interval);
 
                if (ret)
-                       ath10k_warn("Failed to set beacon interval for vdev %d: %i\n",
+                       ath10k_warn("failed to set beacon interval for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -2793,7 +2882,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
                                                WMI_BEACON_STAGGERED_MODE);
                if (ret)
-                       ath10k_warn("Failed to set beacon mode for vdev %d: %i\n",
+                       ath10k_warn("failed to set beacon mode for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -2808,7 +2897,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                arvif->dtim_period);
                if (ret)
-                       ath10k_warn("Failed to set dtim period for vdev %d: %i\n",
+                       ath10k_warn("failed to set dtim period for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -2829,7 +2918,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                        ret = ath10k_peer_create(ar, arvif->vdev_id,
                                                 info->bssid);
                        if (ret)
-                               ath10k_warn("Failed to add peer %pM for vdev %d when changing bssid: %i\n",
+                               ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n",
                                            info->bssid, arvif->vdev_id, ret);
 
                        if (vif->type == NL80211_IFTYPE_STATION) {
@@ -2868,20 +2957,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ath10k_control_beaconing(arvif, info);
 
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
-               u32 cts_prot;
-               if (info->use_cts_prot)
-                       cts_prot = 1;
-               else
-                       cts_prot = 0;
-
+               arvif->use_cts_prot = info->use_cts_prot;
                ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
-                          arvif->vdev_id, cts_prot);
+                          arvif->vdev_id, info->use_cts_prot);
 
-               vdev_param = ar->wmi.vdev_param->enable_rtscts;
-               ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
-                                               cts_prot);
+               ret = ath10k_recalc_rtscts_prot(arvif);
                if (ret)
-                       ath10k_warn("Failed to set CTS prot for vdev %d: %d\n",
+                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -2900,7 +2982,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                slottime);
                if (ret)
-                       ath10k_warn("Failed to set erp slot for vdev %d: %i\n",
+                       ath10k_warn("failed to set erp slot for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -2919,7 +3001,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                preamble);
                if (ret)
-                       ath10k_warn("Failed to set preamble for vdev %d: %i\n",
+                       ath10k_warn("failed to set preamble for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -2990,7 +3072,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
 
        ret = ath10k_start_scan(ar, &arg);
        if (ret) {
-               ath10k_warn("could not start hw scan (%d)\n", ret);
+               ath10k_warn("failed to start hw scan: %d\n", ret);
                spin_lock_bh(&ar->data_lock);
                ar->scan.in_progress = false;
                spin_unlock_bh(&ar->data_lock);
@@ -3010,8 +3092,7 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,
        mutex_lock(&ar->conf_mutex);
        ret = ath10k_abort_scan(ar);
        if (ret) {
-               ath10k_warn("couldn't abort scan (%d). forcefully sending scan completion to mac80211\n",
-                           ret);
+               ath10k_warn("failed to abort scan: %d\n", ret);
                ieee80211_scan_completed(hw, 1 /* aborted */);
        }
        mutex_unlock(&ar->conf_mutex);
@@ -3089,7 +3170,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        if (!peer) {
                if (cmd == SET_KEY) {
-                       ath10k_warn("cannot install key for non-existent peer %pM\n",
+                       ath10k_warn("failed to install key for non-existent peer %pM\n",
                                    peer_addr);
                        ret = -EOPNOTSUPP;
                        goto exit;
@@ -3112,7 +3193,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        ret = ath10k_install_key(arvif, key, cmd, peer_addr);
        if (ret) {
-               ath10k_warn("key installation failed for vdev %i peer %pM: %d\n",
+               ath10k_warn("failed to install key for vdev %i peer %pM: %d\n",
                            arvif->vdev_id, peer_addr, ret);
                goto exit;
        }
@@ -3127,7 +3208,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                peer->keys[key->keyidx] = NULL;
        else if (peer == NULL)
                /* impossible unless FW goes crazy */
-               ath10k_warn("peer %pM disappeared!\n", peer_addr);
+               ath10k_warn("Peer %pM disappeared!\n", peer_addr);
        spin_unlock_bh(&ar->data_lock);
 
 exit:
@@ -3195,6 +3276,16 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
                                    sta->addr, smps, err);
        }
 
+       if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
+                          sta->addr);
+
+               err = ath10k_station_assoc(ar, arvif, sta, true);
+               if (err)
+                       ath10k_warn("failed to reassociate station: %pM\n",
+                                   sta->addr);
+       }
+
        mutex_unlock(&ar->conf_mutex);
 }
 
@@ -3236,7 +3327,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                        max_num_peers = TARGET_NUM_PEERS;
 
                if (ar->num_peers >= max_num_peers) {
-                       ath10k_warn("Number of peers exceeded: peers number %d (max peers %d)\n",
+                       ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n",
                                    ar->num_peers, max_num_peers);
                        ret = -ENOBUFS;
                        goto exit;
@@ -3248,7 +3339,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
                ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
                if (ret)
-                       ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
+                       ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
        } else if ((old_state == IEEE80211_STA_NONE &&
                    new_state == IEEE80211_STA_NOTEXIST)) {
@@ -3260,7 +3351,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                           arvif->vdev_id, sta->addr);
                ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
                if (ret)
-                       ath10k_warn("Failed to delete peer %pM for vdev %d: %i\n",
+                       ath10k_warn("failed to delete peer %pM for vdev %d: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
 
                if (vif->type == NL80211_IFTYPE_STATION)
@@ -3275,9 +3366,9 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
                           sta->addr);
 
-               ret = ath10k_station_assoc(ar, arvif, sta);
+               ret = ath10k_station_assoc(ar, arvif, sta, false);
                if (ret)
-                       ath10k_warn("Failed to associate station %pM for vdev %i: %i\n",
+                       ath10k_warn("failed to associate station %pM for vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH &&
@@ -3291,7 +3382,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
                ret = ath10k_station_disassoc(ar, arvif, sta);
                if (ret)
-                       ath10k_warn("Failed to disassociate station: %pM vdev %i ret %i\n",
+                       ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
        }
 exit:
@@ -3339,7 +3430,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
                                          WMI_STA_PS_PARAM_UAPSD,
                                          arvif->u.sta.uapsd);
        if (ret) {
-               ath10k_warn("could not set uapsd params %d\n", ret);
+               ath10k_warn("failed to set uapsd params: %d\n", ret);
                goto exit;
        }
 
@@ -3352,7 +3443,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
                                          WMI_STA_PS_PARAM_RX_WAKE_POLICY,
                                          value);
        if (ret)
-               ath10k_warn("could not set rx wake param %d\n", ret);
+               ath10k_warn("failed to set rx wake param: %d\n", ret);
 
 exit:
        return ret;
@@ -3402,13 +3493,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
        /* FIXME: FW accepts wmm params per hw, not per vif */
        ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
        if (ret) {
-               ath10k_warn("could not set wmm params %d\n", ret);
+               ath10k_warn("failed to set wmm params: %d\n", ret);
                goto exit;
        }
 
        ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
        if (ret)
-               ath10k_warn("could not set sta uapsd %d\n", ret);
+               ath10k_warn("failed to set sta uapsd: %d\n", ret);
 
 exit:
        mutex_unlock(&ar->conf_mutex);
@@ -3461,7 +3552,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
 
        ret = ath10k_start_scan(ar, &arg);
        if (ret) {
-               ath10k_warn("could not start roc scan (%d)\n", ret);
+               ath10k_warn("failed to start roc scan: %d\n", ret);
                spin_lock_bh(&ar->data_lock);
                ar->scan.in_progress = false;
                spin_unlock_bh(&ar->data_lock);
@@ -3470,7 +3561,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
 
        ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
        if (ret == 0) {
-               ath10k_warn("could not switch to channel for roc scan\n");
+               ath10k_warn("failed to switch to channel for roc scan\n");
                ath10k_abort_scan(ar);
                ret = -ETIMEDOUT;
                goto exit;
@@ -3511,7 +3602,7 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 
                ret = ath10k_mac_set_rts(arvif, value);
                if (ret) {
-                       ath10k_warn("could not set rts threshold for vdev %d (%d)\n",
+                       ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        break;
                }
@@ -3534,7 +3625,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
 
                ret = ath10k_mac_set_rts(arvif, value);
                if (ret) {
-                       ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n",
+                       ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        break;
                }
@@ -3544,7 +3635,8 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
        return ret;
 }
 
-static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                        u32 queues, bool drop)
 {
        struct ath10k *ar = hw->priv;
        bool skip;
@@ -3573,7 +3665,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
                }), ATH10K_FLUSH_TIMEOUT_HZ);
 
        if (ret <= 0 || skip)
-               ath10k_warn("tx not flushed (skip %i ar-state %i): %i\n",
+               ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
                            skip, ar->state, ret);
 
 skip:
@@ -3608,7 +3700,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
 
        ret = ath10k_hif_suspend(ar);
        if (ret) {
-               ath10k_warn("could not suspend hif (%d)\n", ret);
+               ath10k_warn("failed to suspend hif: %d\n", ret);
                goto resume;
        }
 
@@ -3617,7 +3709,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
 resume:
        ret = ath10k_wmi_pdev_resume_target(ar);
        if (ret)
-               ath10k_warn("could not resume target (%d)\n", ret);
+               ath10k_warn("failed to resume target: %d\n", ret);
 
        ret = 1;
 exit:
@@ -3634,14 +3726,14 @@ static int ath10k_resume(struct ieee80211_hw *hw)
 
        ret = ath10k_hif_resume(ar);
        if (ret) {
-               ath10k_warn("could not resume hif (%d)\n", ret);
+               ath10k_warn("failed to resume hif: %d\n", ret);
                ret = 1;
                goto exit;
        }
 
        ret = ath10k_wmi_pdev_resume_target(ar);
        if (ret) {
-               ath10k_warn("could not resume target (%d)\n", ret);
+               ath10k_warn("failed to resume target: %d\n", ret);
                ret = 1;
                goto exit;
        }
@@ -3964,7 +4056,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                        vdev_param, fixed_rate);
        if (ret) {
-               ath10k_warn("Could not set fixed_rate param 0x%02x: %d\n",
+               ath10k_warn("failed to set fixed rate param 0x%02x: %d\n",
                            fixed_rate, ret);
                ret = -EINVAL;
                goto exit;
@@ -3977,7 +4069,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
                                        vdev_param, fixed_nss);
 
        if (ret) {
-               ath10k_warn("Could not set fixed_nss param %d: %d\n",
+               ath10k_warn("failed to set fixed nss param %d: %d\n",
                            fixed_nss, ret);
                ret = -EINVAL;
                goto exit;
@@ -3990,7 +4082,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
                                        force_sgi);
 
        if (ret) {
-               ath10k_warn("Could not set sgi param %d: %d\n",
+               ath10k_warn("failed to set sgi param %d: %d\n",
                            force_sgi, ret);
                ret = -EINVAL;
                goto exit;
@@ -4026,7 +4118,7 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
        }
 
        if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
-               ath10k_warn("Could not force SGI usage for default rate settings\n");
+               ath10k_warn("failed to force SGI usage for default rate settings\n");
                return -EINVAL;
        }
 
@@ -4072,8 +4164,8 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
                        bw = WMI_PEER_CHWIDTH_80MHZ;
                        break;
                case IEEE80211_STA_RX_BW_160:
-                       ath10k_warn("mac sta rc update for %pM: invalid bw %d\n",
-                                   sta->addr, sta->bandwidth);
+                       ath10k_warn("Invalid bandwith %d in rc update for %pM\n",
+                                   sta->bandwidth, sta->addr);
                        bw = WMI_PEER_CHWIDTH_20MHZ;
                        break;
                }
@@ -4099,8 +4191,8 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
                        smps = WMI_PEER_SMPS_DYNAMIC;
                        break;
                case IEEE80211_SMPS_NUM_MODES:
-                       ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n",
-                                   sta->addr, sta->smps_mode);
+                       ath10k_warn("Invalid smps %d in sta rc update for %pM\n",
+                                   sta->smps_mode, sta->addr);
                        smps = WMI_PEER_SMPS_PS_NONE;
                        break;
                }
@@ -4108,15 +4200,6 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
                arsta->smps = smps;
        }
 
-       if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
-               /* FIXME: Not implemented. Probably the only way to do it would
-                * be to re-assoc the peer. */
-               changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED;
-               ath10k_dbg(ATH10K_DBG_MAC,
-                          "mac sta rc update for %pM: changing supported rates not implemented\n",
-                          sta->addr);
-       }
-
        arsta->changed |= changed;
 
        spin_unlock_bh(&ar->data_lock);
@@ -4516,7 +4599,6 @@ int ath10k_mac_register(struct ath10k *ar)
                        IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                        IEEE80211_HW_HAS_RATE_CONTROL |
                        IEEE80211_HW_SUPPORTS_STATIC_SMPS |
-                       IEEE80211_HW_WANT_MONITOR_VIF |
                        IEEE80211_HW_AP_LINK_PS |
                        IEEE80211_HW_SPECTRUM_MGMT;
 
@@ -4570,19 +4652,19 @@ int ath10k_mac_register(struct ath10k *ar)
                                                             NL80211_DFS_UNSET);
 
                if (!ar->dfs_detector)
-                       ath10k_warn("dfs pattern detector init failed\n");
+                       ath10k_warn("failed to initialise DFS pattern detector\n");
        }
 
        ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
                            ath10k_reg_notifier);
        if (ret) {
-               ath10k_err("Regulatory initialization failed: %i\n", ret);
+               ath10k_err("failed to initialise regulatory: %i\n", ret);
                goto err_free;
        }
 
        ret = ieee80211_register_hw(ar->hw);
        if (ret) {
-               ath10k_err("ieee80211 registration failed: %d\n", ret);
+               ath10k_err("failed to register ieee80211: %d\n", ret);
                goto err_free;
        }
 
index 9d242d801d9d354f772b74257826427f0a598180..bf1083d52e61d5f4c29bc6e649f357bf74c7ad51 100644 (file)
@@ -39,15 +39,27 @@ enum ath10k_pci_irq_mode {
        ATH10K_PCI_IRQ_MSI = 2,
 };
 
-static unsigned int ath10k_target_ps;
+enum ath10k_pci_reset_mode {
+       ATH10K_PCI_RESET_AUTO = 0,
+       ATH10K_PCI_RESET_WARM_ONLY = 1,
+};
+
+static unsigned int ath10k_pci_target_ps;
 static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
+static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
 
-module_param(ath10k_target_ps, uint, 0644);
-MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
+module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
+MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
 
 module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
 MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
 
+module_param_named(reset_mode, ath10k_pci_reset_mode, uint, 0644);
+MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
+
+/* how long wait to wait for target to initialise, in ms */
+#define ATH10K_PCI_TARGET_WAIT 3000
+
 #define QCA988X_2_0_DEVICE_ID  (0x003c)
 
 static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
@@ -346,9 +358,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
         *   2) Buffer in DMA-able space
         */
        orig_nbytes = nbytes;
-       data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev,
-                                                        orig_nbytes,
-                                                        &ce_data_base);
+       data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
+                                                      orig_nbytes,
+                                                      &ce_data_base,
+                                                      GFP_ATOMIC);
 
        if (!data_buf) {
                ret = -ENOMEM;
@@ -442,12 +455,12 @@ done:
                                __le32_to_cpu(((__le32 *)data_buf)[i]);
                }
        } else
-               ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n",
-                          __func__, address);
+               ath10k_warn("failed to read diag value at 0x%x: %d\n",
+                           address, ret);
 
        if (data_buf)
-               pci_free_consistent(ar_pci->pdev, orig_nbytes,
-                                   data_buf, ce_data_base);
+               dma_free_coherent(ar->dev, orig_nbytes, data_buf,
+                                 ce_data_base);
 
        return ret;
 }
@@ -490,9 +503,10 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
         *   2) Buffer in DMA-able space
         */
        orig_nbytes = nbytes;
-       data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev,
-                                                        orig_nbytes,
-                                                        &ce_data_base);
+       data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
+                                                      orig_nbytes,
+                                                      &ce_data_base,
+                                                      GFP_ATOMIC);
        if (!data_buf) {
                ret = -ENOMEM;
                goto done;
@@ -588,13 +602,13 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 
 done:
        if (data_buf) {
-               pci_free_consistent(ar_pci->pdev, orig_nbytes, data_buf,
-                                   ce_data_base);
+               dma_free_coherent(ar->dev, orig_nbytes, data_buf,
+                                 ce_data_base);
        }
 
        if (ret != 0)
-               ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", __func__,
-                          address);
+               ath10k_warn("failed to write diag value at 0x%x: %d\n",
+                           address, ret);
 
        return ret;
 }
@@ -803,6 +817,9 @@ unlock:
 static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
+
        return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
 }
 
@@ -854,6 +871,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
 static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
                                               int force)
 {
+       ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
+
        if (!force) {
                int resources;
                /*
@@ -880,7 +899,7 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
+       ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
 
        memcpy(&ar_pci->msg_callbacks_current, callbacks,
               sizeof(ar_pci->msg_callbacks_current));
@@ -938,6 +957,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
 {
        int ret = 0;
 
+       ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
+
        /* polling for received messages not supported */
        *dl_is_polled = 0;
 
@@ -997,6 +1018,8 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
 {
        int ul_is_polled, dl_is_polled;
 
+       ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
+
        (void)ath10k_pci_hif_map_service_to_pipe(ar,
                                                 ATH10K_HTC_SVC_ID_RSVD_CTRL,
                                                 ul_pipe,
@@ -1098,6 +1121,8 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret, ret_early;
 
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
+
        ath10k_pci_free_early_irq(ar);
        ath10k_pci_kill_tasklet(ar);
 
@@ -1233,18 +1258,10 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
 
 static void ath10k_pci_ce_deinit(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_pci_pipe *pipe_info;
-       int pipe_num;
+       int i;
 
-       for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
-               pipe_info = &ar_pci->pipe_info[pipe_num];
-               if (pipe_info->ce_hdl) {
-                       ath10k_ce_deinit(pipe_info->ce_hdl);
-                       pipe_info->ce_hdl = NULL;
-                       pipe_info->buf_sz = 0;
-               }
-       }
+       for (i = 0; i < CE_COUNT; i++)
+               ath10k_ce_deinit_pipe(ar, i);
 }
 
 static void ath10k_pci_hif_stop(struct ath10k *ar)
@@ -1252,7 +1269,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
 
        ret = ath10k_ce_disable_interrupts(ar);
        if (ret)
@@ -1697,30 +1714,49 @@ static int ath10k_pci_init_config(struct ath10k *ar)
        return 0;
 }
 
+static int ath10k_pci_alloc_ce(struct ath10k *ar)
+{
+       int i, ret;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
+               if (ret) {
+                       ath10k_err("failed to allocate copy engine pipe %d: %d\n",
+                                  i, ret);
+                       return ret;
+               }
+       }
 
+       return 0;
+}
+
+static void ath10k_pci_free_ce(struct ath10k *ar)
+{
+       int i;
+
+       for (i = 0; i < CE_COUNT; i++)
+               ath10k_ce_free_pipe(ar, i);
+}
 
 static int ath10k_pci_ce_init(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_pci_pipe *pipe_info;
        const struct ce_attr *attr;
-       int pipe_num;
+       int pipe_num, ret;
 
        for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
                pipe_info = &ar_pci->pipe_info[pipe_num];
+               pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];
                pipe_info->pipe_num = pipe_num;
                pipe_info->hif_ce_state = ar;
                attr = &host_ce_config_wlan[pipe_num];
 
-               pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr);
-               if (pipe_info->ce_hdl == NULL) {
-                       ath10k_err("failed to initialize CE for pipe: %d\n",
-                                  pipe_num);
-
-                       /* It is safe to call it here. It checks if ce_hdl is
-                        * valid for each pipe */
-                       ath10k_pci_ce_deinit(ar);
-                       return -1;
+               ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
+               if (ret) {
+                       ath10k_err("failed to initialize copy engine pipe %d: %d\n",
+                                  pipe_num, ret);
+                       return ret;
                }
 
                if (pipe_num == CE_COUNT - 1) {
@@ -1741,16 +1777,15 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       u32 fw_indicator_address, fw_indicator;
+       u32 fw_indicator;
 
        ath10k_pci_wake(ar);
 
-       fw_indicator_address = ar_pci->fw_indicator_address;
-       fw_indicator = ath10k_pci_read32(ar, fw_indicator_address);
+       fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
 
        if (fw_indicator & FW_IND_EVENT_PENDING) {
                /* ACK: clear Target-side pending event */
-               ath10k_pci_write32(ar, fw_indicator_address,
+               ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
                                   fw_indicator & ~FW_IND_EVENT_PENDING);
 
                if (ar_pci->started) {
@@ -1769,11 +1804,10 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
 
 static int ath10k_pci_warm_reset(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret = 0;
        u32 val;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n");
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
 
        ret = ath10k_do_pci_wake(ar);
        if (ret) {
@@ -1801,7 +1835,7 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
        msleep(100);
 
        /* clear fw indicator */
-       ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0);
+       ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0);
 
        /* clear target LF timer interrupts */
        val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
@@ -1934,7 +1968,9 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
                irq_mode = "legacy";
 
        if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
-               ath10k_info("pci irq %s\n", irq_mode);
+               ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
+                           irq_mode, ath10k_pci_irq_mode,
+                           ath10k_pci_reset_mode);
 
        return 0;
 
@@ -1956,6 +1992,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
+
        /*
         * Hardware CUS232 version 2 has some issues with cold reset and the
         * preferred (and safer) way to perform a device reset is through a
@@ -1966,9 +2004,14 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
         */
        ret = __ath10k_pci_hif_power_up(ar, false);
        if (ret) {
-               ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n",
+               ath10k_warn("failed to power up target using warm reset: %d\n",
                            ret);
 
+               if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
+                       return ret;
+
+               ath10k_warn("trying cold reset\n");
+
                ret = __ath10k_pci_hif_power_up(ar, true);
                if (ret) {
                        ath10k_err("failed to power up target using cold reset too (%d)\n",
@@ -1984,12 +2027,14 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
+
        ath10k_pci_free_early_irq(ar);
        ath10k_pci_kill_tasklet(ar);
        ath10k_pci_deinit_irq(ar);
+       ath10k_pci_ce_deinit(ar);
        ath10k_pci_warm_reset(ar);
 
-       ath10k_pci_ce_deinit(ar);
        if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
                ath10k_do_pci_sleep(ar);
 }
@@ -2137,7 +2182,6 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 static void ath10k_pci_early_irq_tasklet(unsigned long data)
 {
        struct ath10k *ar = (struct ath10k *)data;
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        u32 fw_ind;
        int ret;
 
@@ -2148,9 +2192,9 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data)
                return;
        }
 
-       fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address);
+       fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
        if (fw_ind & FW_IND_EVENT_PENDING) {
-               ath10k_pci_write32(ar, ar_pci->fw_indicator_address,
+               ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
                                   fw_ind & ~FW_IND_EVENT_PENDING);
 
                /* Some structures are unavailable during early boot or at
@@ -2385,33 +2429,50 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int wait_limit = 300; /* 3 sec */
+       unsigned long timeout;
        int ret;
+       u32 val;
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
 
        ret = ath10k_pci_wake(ar);
        if (ret) {
-               ath10k_err("failed to wake up target: %d\n", ret);
+               ath10k_err("failed to wake up target for init: %d\n", ret);
                return ret;
        }
 
-       while (wait_limit-- &&
-              !(ioread32(ar_pci->mem + FW_INDICATOR_ADDRESS) &
-                FW_IND_INITIALIZED)) {
+       timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
+
+       do {
+               val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+
+               ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
+
+               /* target should never return this */
+               if (val == 0xffffffff)
+                       continue;
+
+               if (val & FW_IND_INITIALIZED)
+                       break;
+
                if (ar_pci->num_msi_intrs == 0)
                        /* Fix potential race by repeating CORE_BASE writes */
-                       iowrite32(PCIE_INTR_FIRMWARE_MASK |
-                                 PCIE_INTR_CE_MASK_ALL,
-                                 ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-                                                PCIE_INTR_ENABLE_ADDRESS));
+                       ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
+                                              PCIE_INTR_FIRMWARE_MASK |
+                                              PCIE_INTR_CE_MASK_ALL);
+
                mdelay(10);
-       }
+       } while (time_before(jiffies, timeout));
 
-       if (wait_limit < 0) {
-               ath10k_err("target stalled\n");
-               ret = -EIO;
+       if (val == 0xffffffff || !(val & FW_IND_INITIALIZED)) {
+               ath10k_err("failed to receive initialized event from target: %08x\n",
+                          val);
+               ret = -ETIMEDOUT;
                goto out;
        }
 
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
+
 out:
        ath10k_pci_sleep(ar);
        return ret;
@@ -2422,6 +2483,8 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
        int i, ret;
        u32 val;
 
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
+
        ret = ath10k_do_pci_wake(ar);
        if (ret) {
                ath10k_err("failed to wake up target: %d\n",
@@ -2453,6 +2516,9 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
        }
 
        ath10k_do_pci_sleep(ar);
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
+
        return 0;
 }
 
@@ -2484,7 +2550,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        struct ath10k_pci *ar_pci;
        u32 lcr_val, chip_id;
 
-       ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
+       ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
 
        ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
        if (ar_pci == NULL)
@@ -2503,7 +2569,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_ar_pci;
        }
 
-       if (ath10k_target_ps)
+       if (ath10k_pci_target_ps)
                set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
 
        ath10k_pci_dump_features(ar_pci);
@@ -2516,7 +2582,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        }
 
        ar_pci->ar = ar;
-       ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS;
        atomic_set(&ar_pci->keep_awake_count, 0);
 
        pci_set_drvdata(pdev, ar);
@@ -2594,16 +2659,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 
        ath10k_do_pci_sleep(ar);
 
+       ret = ath10k_pci_alloc_ce(ar);
+       if (ret) {
+               ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
+               goto err_iomap;
+       }
+
        ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
 
        ret = ath10k_core_register(ar, chip_id);
        if (ret) {
                ath10k_err("failed to register driver core: %d\n", ret);
-               goto err_iomap;
+               goto err_free_ce;
        }
 
        return 0;
 
+err_free_ce:
+       ath10k_pci_free_ce(ar);
 err_iomap:
        pci_iounmap(pdev, mem);
 err_master:
@@ -2626,7 +2699,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
        struct ath10k *ar = pci_get_drvdata(pdev);
        struct ath10k_pci *ar_pci;
 
-       ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
+       ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
 
        if (!ar)
                return;
@@ -2639,6 +2712,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
        tasklet_kill(&ar_pci->msi_fw_err);
 
        ath10k_core_unregister(ar);
+       ath10k_pci_free_ce(ar);
 
        pci_iounmap(pdev, ar_pci->mem);
        pci_release_region(pdev, BAR_NUM);
@@ -2680,6 +2754,5 @@ module_exit(ath10k_pci_exit);
 MODULE_AUTHOR("Qualcomm Atheros");
 MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_OTP_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
index b43fdb4f731973544e1a55f700c779e4191d76bb..dfdebb4157aa177acde13ea1149b5a7490c5593e 100644 (file)
@@ -189,9 +189,6 @@ struct ath10k_pci {
 
        struct ath10k_hif_cb msg_callbacks_current;
 
-       /* Target address used to signal a pending firmware event */
-       u32 fw_indicator_address;
-
        /* Copy Engine used for Diagnostic Accesses */
        struct ath10k_ce_pipe *ce_diag;
 
index 0541dd939ce9d8be7dc7e195ef952526abab0255..82669a77e553b8f6902c7dc03f99e24b42a3dea6 100644 (file)
@@ -100,189 +100,6 @@ exit:
                wake_up(&htt->empty_tx_wq);
 }
 
-static const u8 rx_legacy_rate_idx[] = {
-       3,      /* 0x00  - 11Mbps  */
-       2,      /* 0x01  - 5.5Mbps */
-       1,      /* 0x02  - 2Mbps   */
-       0,      /* 0x03  - 1Mbps   */
-       3,      /* 0x04  - 11Mbps  */
-       2,      /* 0x05  - 5.5Mbps */
-       1,      /* 0x06  - 2Mbps   */
-       0,      /* 0x07  - 1Mbps   */
-       10,     /* 0x08  - 48Mbps  */
-       8,      /* 0x09  - 24Mbps  */
-       6,      /* 0x0A  - 12Mbps  */
-       4,      /* 0x0B  - 6Mbps   */
-       11,     /* 0x0C  - 54Mbps  */
-       9,      /* 0x0D  - 36Mbps  */
-       7,      /* 0x0E  - 18Mbps  */
-       5,      /* 0x0F  - 9Mbps   */
-};
-
-static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info,
-                            enum ieee80211_band band,
-                            struct ieee80211_rx_status *status)
-{
-       u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
-       u8 info0 = info->rate.info0;
-       u32 info1 = info->rate.info1;
-       u32 info2 = info->rate.info2;
-       u8 preamble = 0;
-
-       /* Check if valid fields */
-       if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
-               return;
-
-       preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
-
-       switch (preamble) {
-       case HTT_RX_LEGACY:
-               cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
-               rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
-               rate_idx = 0;
-
-               if (rate < 0x08 || rate > 0x0F)
-                       break;
-
-               switch (band) {
-               case IEEE80211_BAND_2GHZ:
-                       if (cck)
-                               rate &= ~BIT(3);
-                       rate_idx = rx_legacy_rate_idx[rate];
-                       break;
-               case IEEE80211_BAND_5GHZ:
-                       rate_idx = rx_legacy_rate_idx[rate];
-                       /* We are using same rate table registering
-                          HW - ath10k_rates[]. In case of 5GHz skip
-                          CCK rates, so -4 here */
-                       rate_idx -= 4;
-                       break;
-               default:
-                       break;
-               }
-
-               status->rate_idx = rate_idx;
-               break;
-       case HTT_RX_HT:
-       case HTT_RX_HT_WITH_TXBF:
-               /* HT-SIG - Table 20-11 in info1 and info2 */
-               mcs = info1 & 0x1F;
-               nss = mcs >> 3;
-               bw = (info1 >> 7) & 1;
-               sgi = (info2 >> 7) & 1;
-
-               status->rate_idx = mcs;
-               status->flag |= RX_FLAG_HT;
-               if (sgi)
-                       status->flag |= RX_FLAG_SHORT_GI;
-               if (bw)
-                       status->flag |= RX_FLAG_40MHZ;
-               break;
-       case HTT_RX_VHT:
-       case HTT_RX_VHT_WITH_TXBF:
-               /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
-                  TODO check this */
-               mcs = (info2 >> 4) & 0x0F;
-               nss = ((info1 >> 10) & 0x07) + 1;
-               bw = info1 & 3;
-               sgi = info2 & 1;
-
-               status->rate_idx = mcs;
-               status->vht_nss = nss;
-
-               if (sgi)
-                       status->flag |= RX_FLAG_SHORT_GI;
-
-               switch (bw) {
-               /* 20MHZ */
-               case 0:
-                       break;
-               /* 40MHZ */
-               case 1:
-                       status->flag |= RX_FLAG_40MHZ;
-                       break;
-               /* 80MHZ */
-               case 2:
-                       status->vht_flag |= RX_VHT_FLAG_80MHZ;
-               }
-
-               status->flag |= RX_FLAG_VHT;
-               break;
-       default:
-               break;
-       }
-}
-
-void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
-{
-       struct ieee80211_rx_status *status;
-       struct ieee80211_channel *ch;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)info->skb->data;
-
-       status = IEEE80211_SKB_RXCB(info->skb);
-       memset(status, 0, sizeof(*status));
-
-       if (info->encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) {
-               status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
-                               RX_FLAG_MMIC_STRIPPED;
-               hdr->frame_control = __cpu_to_le16(
-                               __le16_to_cpu(hdr->frame_control) &
-                               ~IEEE80211_FCTL_PROTECTED);
-       }
-
-       if (info->mic_err)
-               status->flag |= RX_FLAG_MMIC_ERROR;
-
-       if (info->fcs_err)
-               status->flag |= RX_FLAG_FAILED_FCS_CRC;
-
-       if (info->amsdu_more)
-               status->flag |= RX_FLAG_AMSDU_MORE;
-
-       status->signal = info->signal;
-
-       spin_lock_bh(&ar->data_lock);
-       ch = ar->scan_channel;
-       if (!ch)
-               ch = ar->rx_channel;
-       spin_unlock_bh(&ar->data_lock);
-
-       if (!ch) {
-               ath10k_warn("no channel configured; ignoring frame!\n");
-               dev_kfree_skb_any(info->skb);
-               return;
-       }
-
-       process_rx_rates(ar, info, ch->band, status);
-       status->band = ch->band;
-       status->freq = ch->center_freq;
-
-       if (info->rate.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
-               /* TSF available only in 32-bit */
-               status->mactime = info->tsf & 0xffffffff;
-               status->flag |= RX_FLAG_MACTIME_END;
-       }
-
-       ath10k_dbg(ATH10K_DBG_DATA,
-                  "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n",
-                  info->skb,
-                  info->skb->len,
-                  status->flag == 0 ? "legacy" : "",
-                  status->flag & RX_FLAG_HT ? "ht" : "",
-                  status->flag & RX_FLAG_VHT ? "vht" : "",
-                  status->flag & RX_FLAG_40MHZ ? "40" : "",
-                  status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
-                  status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
-                  status->rate_idx,
-                  status->vht_nss,
-                  status->freq,
-                  status->band, status->flag, info->fcs_err);
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
-                       info->skb->data, info->skb->len);
-
-       ieee80211_rx(ar->hw, info->skb);
-}
-
 struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
                                     const u8 *addr)
 {
index 356dc9c04c9e3981feaeb04d8df4e8f45fc36f7f..aee3e20058f814f2e7a774005d84d77c684442f4 100644 (file)
@@ -21,7 +21,6 @@
 
 void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
                          const struct htt_tx_done *tx_done);
-void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info);
 
 struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
                                     const u8 *addr);
index cb1f7b5bcf4cdefa774411e09fa39b80728d82e4..fe4d5f1c672f56b621db21370fa79a70214584bb 100644 (file)
@@ -1362,13 +1362,10 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
        struct sk_buff *bcn;
        int ret, vdev_id = 0;
 
-       ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n");
-
        ev = (struct wmi_host_swba_event *)skb->data;
        map = __le32_to_cpu(ev->vdev_map);
 
-       ath10k_dbg(ATH10K_DBG_MGMT, "host swba:\n"
-                  "-vdev map 0x%x\n",
+       ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
                   ev->vdev_map);
 
        for (; map; map >>= 1, vdev_id++) {
@@ -1385,12 +1382,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                bcn_info = &ev->bcn_info[i];
 
                ath10k_dbg(ATH10K_DBG_MGMT,
-                          "-bcn_info[%d]:\n"
-                          "--tim_len %d\n"
-                          "--tim_mcast %d\n"
-                          "--tim_changed %d\n"
-                          "--tim_num_ps_pending %d\n"
-                          "--tim_bitmap 0x%08x%08x%08x%08x\n",
+                          "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
                           i,
                           __le32_to_cpu(bcn_info->tim_info.tim_len),
                           __le32_to_cpu(bcn_info->tim_info.tim_mcast),
@@ -2393,8 +2385,9 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)
        return 0;
 }
 
-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
-                                 u16 rd5g, u16 ctl2g, u16 ctl5g)
+static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
+                                             u16 rd2g, u16 rd5g, u16 ctl2g,
+                                             u16 ctl5g)
 {
        struct wmi_pdev_set_regdomain_cmd *cmd;
        struct sk_buff *skb;
@@ -2418,6 +2411,46 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
                                   ar->wmi.cmd->pdev_set_regdomain_cmdid);
 }
 
+static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
+                                            u16 rd2g, u16 rd5g,
+                                            u16 ctl2g, u16 ctl5g,
+                                            enum wmi_dfs_region dfs_reg)
+{
+       struct wmi_pdev_set_regdomain_cmd_10x *cmd;
+       struct sk_buff *skb;
+
+       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data;
+       cmd->reg_domain = __cpu_to_le32(rd);
+       cmd->reg_domain_2G = __cpu_to_le32(rd2g);
+       cmd->reg_domain_5G = __cpu_to_le32(rd5g);
+       cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
+       cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
+       cmd->dfs_domain = __cpu_to_le32(dfs_reg);
+
+       ath10k_dbg(ATH10K_DBG_WMI,
+                  "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
+                  rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
+
+       return ath10k_wmi_cmd_send(ar, skb,
+                                  ar->wmi.cmd->pdev_set_regdomain_cmdid);
+}
+
+int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
+                                 u16 rd5g, u16 ctl2g, u16 ctl5g,
+                                 enum wmi_dfs_region dfs_reg)
+{
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+               return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g,
+                                                       ctl2g, ctl5g, dfs_reg);
+       else
+               return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g,
+                                                        ctl2g, ctl5g);
+}
+
 int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
                                const struct wmi_channel_arg *arg)
 {
@@ -3456,8 +3489,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
                __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
 
        ath10k_dbg(ATH10K_DBG_WMI,
-                  "wmi peer assoc vdev %d addr %pM\n",
-                  arg->vdev_id, arg->addr);
+                  "wmi peer assoc vdev %d addr %pM (%s)\n",
+                  arg->vdev_id, arg->addr,
+                  arg->peer_reassoc ? "reassociate" : "new");
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
 }
 
index 4fcc96aa9513b89a45e11fd9c2d8da79414204c9..ae838221af65d46efd817f18f5bb872034e1c5c5 100644 (file)
@@ -198,16 +198,6 @@ struct wmi_mac_addr {
        } __packed;
 } __packed;
 
-/* macro to convert MAC address from WMI word format to char array */
-#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr, c_macaddr) do { \
-       (c_macaddr)[0] =  ((pwmi_mac_addr)->word0) & 0xff; \
-       (c_macaddr)[1] = (((pwmi_mac_addr)->word0) >> 8) & 0xff; \
-       (c_macaddr)[2] = (((pwmi_mac_addr)->word0) >> 16) & 0xff; \
-       (c_macaddr)[3] = (((pwmi_mac_addr)->word0) >> 24) & 0xff; \
-       (c_macaddr)[4] =  ((pwmi_mac_addr)->word1) & 0xff; \
-       (c_macaddr)[5] = (((pwmi_mac_addr)->word1) >> 8) & 0xff; \
-       } while (0)
-
 struct wmi_cmd_map {
        u32 init_cmdid;
        u32 start_scan_cmdid;
@@ -2185,6 +2175,31 @@ struct wmi_pdev_set_regdomain_cmd {
        __le32 conformance_test_limit_5G;
 } __packed;
 
+enum wmi_dfs_region {
+       /* Uninitialized dfs domain */
+       WMI_UNINIT_DFS_DOMAIN = 0,
+
+       /* FCC3 dfs domain */
+       WMI_FCC_DFS_DOMAIN = 1,
+
+       /* ETSI dfs domain */
+       WMI_ETSI_DFS_DOMAIN = 2,
+
+       /*Japan dfs domain */
+       WMI_MKK4_DFS_DOMAIN = 3,
+};
+
+struct wmi_pdev_set_regdomain_cmd_10x {
+       __le32 reg_domain;
+       __le32 reg_domain_2G;
+       __le32 reg_domain_5G;
+       __le32 conformance_test_limit_2G;
+       __le32 conformance_test_limit_5G;
+
+       /* dfs domain from wmi_dfs_region */
+       __le32 dfs_domain;
+} __packed;
+
 /* Command to set/unset chip in quiet mode */
 struct wmi_pdev_set_quiet_cmd {
        /* period in TUs */
@@ -2210,6 +2225,19 @@ enum ath10k_protmode {
        ATH10K_PROT_RTSCTS   = 2,    /* RTS-CTS */
 };
 
+enum wmi_rtscts_profile {
+       WMI_RTSCTS_FOR_NO_RATESERIES = 0,
+       WMI_RTSCTS_FOR_SECOND_RATESERIES,
+       WMI_RTSCTS_ACROSS_SW_RETRIES
+};
+
+#define WMI_RTSCTS_ENABLED             1
+#define WMI_RTSCTS_SET_MASK            0x0f
+#define WMI_RTSCTS_SET_LSB             0
+
+#define WMI_RTSCTS_PROFILE_MASK                0xf0
+#define WMI_RTSCTS_PROFILE_LSB         4
+
 enum wmi_beacon_gen_mode {
        WMI_BEACON_STAGGERED_MODE = 0,
        WMI_BEACON_BURST_MODE = 1
@@ -2682,6 +2710,9 @@ struct wal_dbg_tx_stats {
        /* wal pdev resets  */
        __le32 pdev_resets;
 
+       /* frames dropped due to non-availability of stateless TIDs */
+       __le32 stateless_tid_alloc_failure;
+
        __le32 phy_underrun;
 
        /* MPDU is more than txop limit */
@@ -2738,13 +2769,21 @@ enum wmi_stats_id {
        WMI_REQUEST_AP_STAT     = 0x02
 };
 
+struct wlan_inst_rssi_args {
+       __le16 cfg_retry_count;
+       __le16 retry_count;
+};
+
 struct wmi_request_stats_cmd {
        __le32 stats_id;
 
-       /*
-        * Space to add parameters like
-        * peer mac addr
-        */
+       __le32 vdev_id;
+
+       /* peer MAC address */
+       struct wmi_mac_addr peer_macaddr;
+
+       /* Instantaneous RSSI arguments */
+       struct wlan_inst_rssi_args inst_rssi_args;
 } __packed;
 
 /* Suspend option */
@@ -2795,7 +2834,7 @@ struct wmi_stats_event {
  * PDEV statistics
  * TODO: add all PDEV stats here
  */
-struct wmi_pdev_stats {
+struct wmi_pdev_stats_old {
        __le32 chan_nf;        /* Channel noise floor */
        __le32 tx_frame_count; /* TX frame count */
        __le32 rx_frame_count; /* RX frame count */
@@ -2806,6 +2845,23 @@ struct wmi_pdev_stats {
        struct wal_dbg_stats wal; /* WAL dbg stats */
 } __packed;
 
+struct wmi_pdev_stats_10x {
+       __le32 chan_nf;        /* Channel noise floor */
+       __le32 tx_frame_count; /* TX frame count */
+       __le32 rx_frame_count; /* RX frame count */
+       __le32 rx_clear_count; /* rx clear count */
+       __le32 cycle_count;    /* cycle count */
+       __le32 phy_err_count;  /* Phy error count */
+       __le32 chan_tx_pwr;    /* channel tx power */
+       struct wal_dbg_stats wal; /* WAL dbg stats */
+       __le32 ack_rx_bad;
+       __le32 rts_bad;
+       __le32 rts_good;
+       __le32 fcs_bad;
+       __le32 no_beacons;
+       __le32 mib_int_count;
+} __packed;
+
 /*
  * VDEV statistics
  * TODO: add all VDEV stats here
@@ -2818,10 +2874,17 @@ struct wmi_vdev_stats {
  * peer statistics.
  * TODO: add more stats
  */
-struct wmi_peer_stats {
+struct wmi_peer_stats_old {
+       struct wmi_mac_addr peer_macaddr;
+       __le32 peer_rssi;
+       __le32 peer_tx_rate;
+} __packed;
+
+struct wmi_peer_stats_10x {
        struct wmi_mac_addr peer_macaddr;
        __le32 peer_rssi;
        __le32 peer_tx_rate;
+       __le32 peer_rx_rate;
 } __packed;
 
 struct wmi_vdev_create_cmd {
@@ -4202,7 +4265,8 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
 int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
 int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
 int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
-                                 u16 rd5g, u16 ctl2g, u16 ctl5g);
+                                 u16 rd5g, u16 ctl2g, u16 ctl5g,
+                                 enum wmi_dfs_region dfs_reg);
 int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value);
 int ath10k_wmi_cmd_init(struct ath10k *ar);
 int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *);
index 1a2973b7acf2500f5c97c992315793d0b4b9a9a7..0fce1c76638e9c9ae103e01ac6752dced8b1670d 100644 (file)
@@ -3709,8 +3709,8 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                        AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
                        AR5K_TPC);
        } else {
-               ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
-                       AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+               ath5k_hw_reg_write(ah, AR5K_TUNE_MAX_TXPOWER,
+                       AR5K_PHY_TXPOWER_RATE_MAX);
        }
 
        return 0;
index e39e5860a2e9347a2d44318e69b07410c4bd2dc5..9c125ff083f73de2c766bd5ccd6f3dc16aad7ae2 100644 (file)
@@ -1,11 +1,19 @@
 config ATH6KL
        tristate "Atheros mobile chipsets support"
+       depends on CFG80211
+        ---help---
+         This module adds core support for wireless adapters based on
+         Atheros AR6003 and AR6004 chipsets. You still need separate
+         bus drivers for USB and SDIO to be able to use real devices.
+
+         If you choose to build it as a module, it will be called
+         ath6kl_core. Please note that AR6002 and AR6001 are not
+         supported by this driver.
 
 config ATH6KL_SDIO
        tristate "Atheros ath6kl SDIO support"
        depends on ATH6KL
        depends on MMC
-       depends on CFG80211
        ---help---
          This module adds support for wireless adapters based on
          Atheros AR6003 and AR6004 chipsets running over SDIO. If you
@@ -17,25 +25,31 @@ config ATH6KL_USB
        tristate "Atheros ath6kl USB support"
        depends on ATH6KL
        depends on USB
-       depends on CFG80211
        ---help---
          This module adds support for wireless adapters based on
-         Atheros AR6004 chipset running over USB. This is still under
-         implementation and it isn't functional. If you choose to
-         build it as a module, it will be called ath6kl_usb.
+         Atheros AR6004 chipset and chipsets based on it running over
+         USB. If you choose to build it as a module, it will be
+         called ath6kl_usb.
 
 config ATH6KL_DEBUG
        bool "Atheros ath6kl debugging"
        depends on ATH6KL
        ---help---
-         Enables debug support
+         Enables ath6kl debug support, including debug messages
+         enabled with debug_mask module parameter and debugfs
+         interface.
+
+         If unsure, say Y to make it easier to debug problems.
 
 config ATH6KL_TRACING
        bool "Atheros ath6kl tracing support"
        depends on ATH6KL
        depends on EVENT_TRACING
        ---help---
-         Select this to ath6kl use tracing infrastructure.
+         Select this to ath6kl use tracing infrastructure which, for
+         example, can be enabled with help of trace-cmd. All debug
+         messages and commands are delivered to using individually
+         enablable trace points.
 
          If unsure, say Y to make it easier to debug problems.
 
@@ -47,3 +61,5 @@ config ATH6KL_REGDOMAIN
          Enabling this makes it possible to change the regdomain in
          the firmware. This can be only enabled if regulatory requirements
          are taken into account.
+
+         If unsure, say N.
index c2c6f460495859ae3517c4f20daa2c15caebdde0..09285084bcd3d0a17ab6c518b1d2ea4f616ffe26 100644 (file)
@@ -724,8 +724,9 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
                        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                                   "added bss %pM to cfg80211\n", bssid);
                kfree(ie);
-       } else
+       } else {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
+       }
 
        return bss;
 }
@@ -970,7 +971,6 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar,
                                          ssid_list[i].flag,
                                          ssid_list[i].ssid.ssid_len,
                                          ssid_list[i].ssid.ssid);
-
        }
 
        /* Make sure no old entries are left behind */
@@ -1897,7 +1897,6 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
 
        /* Configure the patterns that we received from the user. */
        for (i = 0; i < wow->n_patterns; i++) {
-
                /*
                 * Convert given nl80211 specific mask value to equivalent
                 * driver specific mask value and send it to the chip along
@@ -2850,8 +2849,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        if (p.prwise_crypto_type == 0) {
                p.prwise_crypto_type = NONE_CRYPT;
                ath6kl_set_cipher(vif, 0, true);
-       } else if (info->crypto.n_ciphers_pairwise == 1)
+       } else if (info->crypto.n_ciphers_pairwise == 1) {
                ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
+       }
 
        switch (info->crypto.cipher_group) {
        case WLAN_CIPHER_SUITE_WEP40:
@@ -2897,7 +2897,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        }
 
        if (info->inactivity_timeout) {
-
                inactivity_timeout = info->inactivity_timeout;
 
                if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS)
index 4b46adbe8c923b7dd410c919dc3cbc289541ea4f..b0b6520427600a05687e299318f78f873e3fd948 100644 (file)
@@ -45,9 +45,9 @@ module_param(testmode, uint, 0644);
 module_param(recovery_enable, uint, 0644);
 module_param(heart_beat_poll, uint, 0644);
 MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error");
-MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic"   \
-                "polling. This also specifies the polling interval in"  \
-                "msecs. Set reocvery_enable for this to be effective");
+MODULE_PARM_DESC(heart_beat_poll,
+                "Enable fw error detection periodic polling in msecs - Also set recovery_enable for this to be effective");
+
 
 void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
 {
index dbfd17d0a5faa33fa390b150d8d39e03a42d3746..55c4064dd5067f26b8dfaf54689f85c9eb67a88e 100644 (file)
@@ -172,7 +172,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
                           struct ath6kl_irq_proc_registers *irq_proc_reg,
                           struct ath6kl_irq_enable_reg *irq_enable_reg)
 {
-
        ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
 
        if (irq_proc_reg != NULL) {
@@ -219,7 +218,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
                                   "GMBOX lookahead alias 1:   0x%x\n",
                                   irq_proc_reg->rx_gmbox_lkahd_alias[1]);
                }
-
        }
 
        if (irq_enable_reg != NULL) {
@@ -1396,7 +1394,6 @@ static ssize_t ath6kl_create_qos_write(struct file *file,
                                                const char __user *user_buf,
                                                size_t count, loff_t *ppos)
 {
-
        struct ath6kl *ar = file->private_data;
        struct ath6kl_vif *vif;
        char buf[200];
@@ -1575,7 +1572,6 @@ static ssize_t ath6kl_delete_qos_write(struct file *file,
                                const char __user *user_buf,
                                size_t count, loff_t *ppos)
 {
-
        struct ath6kl *ar = file->private_data;
        struct ath6kl_vif *vif;
        char buf[100];
index ca9ba005f2871f3e42bbc914bb5ca90f6e8b90e9..e194c10d9f0071725c1c5eba917347ae8209b0a0 100644 (file)
@@ -97,8 +97,8 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev,
                struct ath6kl_irq_proc_registers *irq_proc_reg,
                struct ath6kl_irq_enable_reg *irq_en_reg)
 {
-
 }
+
 static inline void dump_cred_dist_stats(struct htc_target *target)
 {
 }
index fea7709b5dda59aa26fa0fbc5eb70caccea77918..18c070850a09b870900624a83ee5576551281cdb 100644 (file)
@@ -37,7 +37,6 @@ static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req,
        buf = req->virt_dma_buf;
 
        for (i = 0; i < req->scat_entries; i++) {
-
                if (from_dma)
                        memcpy(req->scat_list[i].buf, buf,
                               req->scat_list[i].len);
@@ -116,7 +115,6 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
                            le32_to_cpu(regdump_val[i + 2]),
                            le32_to_cpu(regdump_val[i + 3]));
        }
-
 }
 
 static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
@@ -701,5 +699,4 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
 
 fail_setup:
        return status;
-
 }
index 61f6b21fb0aeeaa4e6ef20dfca3baddf6ad638cd..dc6bd8cd9b837d85155d494a0afd2b32b7775240 100644 (file)
@@ -197,9 +197,9 @@ struct hif_scatter_req {
        /* bounce buffer for upper layers to copy to/from */
        u8 *virt_dma_buf;
 
-       struct hif_scatter_item scat_list[1];
-
        u32 scat_q_depth;
+
+       struct hif_scatter_item scat_list[0];
 };
 
 struct ath6kl_irq_proc_registers {
index 65e5b719093d47943b3135e902cf68001eefd988..e481f14b98787e88354278d26e3c59615ff2851c 100644 (file)
@@ -112,9 +112,9 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
                if (cur_ep_dist->endpoint == ENDPOINT_0)
                        continue;
 
-               if (cur_ep_dist->svc_id == WMI_CONTROL_SVC)
+               if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) {
                        cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg;
-               else {
+               else {
                        /*
                         * For the remaining data endpoints, we assume that
                         * each cred_per_msg are the same. We use a simple
@@ -129,7 +129,6 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
                        count = (count * 3) >> 2;
                        count = max(count, cur_ep_dist->cred_per_msg);
                        cur_ep_dist->cred_norm = count;
-
                }
 
                ath6kl_dbg(ATH6KL_DBG_CREDIT,
@@ -549,7 +548,6 @@ static int htc_check_credits(struct htc_target *target,
                             enum htc_endpoint_id eid, unsigned int len,
                             int *req_cred)
 {
-
        *req_cred = (len > target->tgt_cred_sz) ?
                     DIV_ROUND_UP(len, target->tgt_cred_sz) : 1;
 
@@ -608,7 +606,6 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
        unsigned int len;
 
        while (true) {
-
                flags = 0;
 
                if (list_empty(&endpoint->txq))
@@ -889,7 +886,6 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
                ac = target->dev->ar->ep2ac_map[endpoint->eid];
 
        while (true) {
-
                if (list_empty(&endpoint->txq))
                        break;
 
@@ -1190,7 +1186,6 @@ static void ath6kl_htc_mbox_flush_txep(struct htc_target *target,
                list_add_tail(&packet->list, &container);
                htc_tx_complete(endpoint, &container);
        }
-
 }
 
 static void ath6kl_htc_flush_txep_all(struct htc_target *target)
@@ -1394,7 +1389,6 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,
 
        ep_cb = ep->ep_cb;
        for (j = 0; j < n_msg; j++) {
-
                /*
                 * Reset flag, any packets allocated using the
                 * rx_alloc() API cannot be recycled on
@@ -1424,9 +1418,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,
                                }
                        }
 
-                       if (list_empty(&ep->rx_bufq))
+                       if (list_empty(&ep->rx_bufq)) {
                                packet = NULL;
-                       else {
+                       else {
                                packet = list_first_entry(&ep->rx_bufq,
                                                struct htc_packet, list);
                                list_del(&packet->list);
@@ -1487,7 +1481,6 @@ static int ath6kl_htc_rx_alloc(struct htc_target *target,
        spin_lock_bh(&target->rx_lock);
 
        for (i = 0; i < msg; i++) {
-
                htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i];
 
                if (htc_hdr->eid >= ENDPOINT_MAX) {
@@ -1708,7 +1701,6 @@ static int htc_parse_trailer(struct htc_target *target,
                lk_ahd = (struct htc_lookahead_report *) record_buf;
                if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) &&
                    next_lk_ahds) {
-
                        ath6kl_dbg(ATH6KL_DBG_HTC,
                                   "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n",
                                   lk_ahd->pre_valid, lk_ahd->post_valid);
@@ -1755,7 +1747,6 @@ static int htc_parse_trailer(struct htc_target *target,
        }
 
        return 0;
-
 }
 
 static int htc_proc_trailer(struct htc_target *target,
@@ -1776,7 +1767,6 @@ static int htc_proc_trailer(struct htc_target *target,
        status = 0;
 
        while (len > 0) {
-
                if (len < sizeof(struct htc_record_hdr)) {
                        status = -ENOMEM;
                        break;
@@ -2098,7 +2088,6 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target,
                }
 
                if (!fetched_pkts) {
-
                        packet = list_first_entry(rx_pktq, struct htc_packet,
                                                   list);
 
@@ -2173,7 +2162,6 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
        look_aheads[0] = msg_look_ahead;
 
        while (true) {
-
                /*
                 * First lookahead sets the expected endpoint IDs for all
                 * packets in a bundle.
@@ -2825,8 +2813,9 @@ static int ath6kl_htc_reset(struct htc_target *target)
                        packet->buf = packet->buf_start;
                        packet->endpoint = ENDPOINT_0;
                        list_add_tail(&packet->list, &target->free_ctrl_rxbuf);
-               } else
+               } else {
                        list_add_tail(&packet->list, &target->free_ctrl_txbuf);
+               }
        }
 
        return 0;
index 67aa924ed8b317f9d5240ad1560a820553790c24..756fe52a12c8ad5a3496de58bbfec01d0ad9820b 100644 (file)
@@ -137,7 +137,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,
                        credits_required = 0;
 
                } else {
-
                        if (ep->cred_dist.credits < credits_required)
                                break;
 
@@ -169,7 +168,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,
                /* queue this packet into the caller's queue */
                list_add_tail(&packet->list, queue);
        }
-
 }
 
 static void get_htc_packet(struct htc_target *target,
@@ -279,7 +277,6 @@ static int htc_issue_packets(struct htc_target *target,
                        list_add(&packet->list, pkt_queue);
                        break;
                }
-
        }
 
        if (status != 0) {
@@ -385,7 +382,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
                         */
                        list_for_each_entry_safe(packet, tmp_pkt,
                                                 txq, list) {
-
                                ath6kl_dbg(ATH6KL_DBG_HTC,
                                           "%s: Indicat overflowed TX pkts: %p\n",
                                           __func__, packet);
@@ -403,7 +399,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
                                        list_move_tail(&packet->list,
                                                       &send_queue);
                                }
-
                        }
 
                        if (list_empty(&send_queue)) {
@@ -454,7 +449,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
         * enough transmit resources.
         */
        while (true) {
-
                if (get_queue_depth(&ep->txq) == 0)
                        break;
 
@@ -495,8 +489,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
                }
 
                spin_lock_bh(&target->tx_lock);
-
        }
+
        /* done with this endpoint, we can clear the count */
        ep->tx_proc_cnt = 0;
        spin_unlock_bh(&target->tx_lock);
@@ -1106,7 +1100,6 @@ free_skb:
        dev_kfree_skb(skb);
 
        return status;
-
 }
 
 static void htc_flush_rx_queue(struct htc_target *target,
@@ -1258,7 +1251,6 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
                tx_alloc = 0;
 
        } else {
-
                tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id);
                if (tx_alloc == 0) {
                        status = -ENOMEM;
index 4f316bdcbab58da3911c6a2365da1989ba412744..d5ef211f261c2c19e6e8deeef985dc2b83130794 100644 (file)
@@ -1192,7 +1192,6 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
 
        if (board_ext_address &&
            ar->fw_board_len == (board_data_size + board_ext_data_size)) {
-
                /* write extended board data */
                ath6kl_dbg(ATH6KL_DBG_BOOT,
                           "writing extended board data to 0x%x (%d B)\n",
index 5839fc23bdc789d5013f1c89e48f0f65eff37efe..d56554674da47924477c02423ad08c50caef2918 100644 (file)
@@ -571,7 +571,6 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
 
 static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
 {
-
        struct ath6kl *ar = vif->ar;
 
        vif->profile.ch = cpu_to_le16(channel);
@@ -600,7 +599,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
 
 static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
 {
-
        struct ath6kl_vif *vif;
        int res = 0;
 
@@ -692,9 +690,9 @@ void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast)
                cfg80211_michael_mic_failure(vif->ndev, sta->mac,
                                             NL80211_KEYTYPE_PAIRWISE, keyid,
                                             tsc, GFP_KERNEL);
-       } else
+       } else {
                ath6kl_cfg80211_tkip_micerr_event(vif, keyid, ismcast);
-
+       }
 }
 
 static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
@@ -1093,8 +1091,9 @@ static int ath6kl_open(struct net_device *dev)
        if (test_bit(CONNECTED, &vif->flags)) {
                netif_carrier_on(dev);
                netif_wake_queue(dev);
-       } else
+       } else {
                netif_carrier_off(dev);
+       }
 
        return 0;
 }
@@ -1146,7 +1145,6 @@ static int ath6kl_set_features(struct net_device *dev,
                        dev->features = features | NETIF_F_RXCSUM;
                        return err;
                }
-
        }
 
        return err;
index 7126bdd4236c2b1e78dd3a9d2c600dbadbb53f0e..339d89f14d32b1991c3d3d646f460b90f41411bb 100644 (file)
@@ -348,7 +348,7 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
        int i, scat_req_sz, scat_list_sz, size;
        u8 *virt_buf;
 
-       scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
+       scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item);
        scat_req_sz = sizeof(*s_req) + scat_list_sz;
 
        if (!virt_scat)
@@ -425,8 +425,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
                        memcpy(tbuf, buf, len);
 
                bounced = true;
-       } else
+       } else {
                tbuf = buf;
+       }
 
        ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len);
        if ((request & HIF_READ) && bounced)
@@ -441,9 +442,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
 static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,
                                      struct bus_request *req)
 {
-       if (req->scat_req)
+       if (req->scat_req) {
                ath6kl_sdio_scat_rw(ar_sdio, req);
-       else {
+       else {
                void *context;
                int status;
 
@@ -656,7 +657,6 @@ static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,
        list_add_tail(&s_req->list, &ar_sdio->scat_req);
 
        spin_unlock_bh(&ar_sdio->scat_lock);
-
 }
 
 /* scatter gather read write request */
@@ -674,9 +674,9 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
                   "hif-scatter: total len: %d scatter entries: %d\n",
                   scat_req->len, scat_req->scat_entries);
 
-       if (request & HIF_SYNCHRONOUS)
+       if (request & HIF_SYNCHRONOUS) {
                status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
-       else {
+       else {
                spin_lock_bh(&ar_sdio->wr_async_lock);
                list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq);
                spin_unlock_bh(&ar_sdio->wr_async_lock);
@@ -856,7 +856,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 
        if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
            (!ar->suspend_mode && wow)) {
-
                ret = ath6kl_set_sdio_pm_caps(ar);
                if (ret)
                        goto cut_pwr;
@@ -878,7 +877,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 
        if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
            !ar->suspend_mode || try_deepsleep) {
-
                flags = sdio_get_host_pm_caps(func);
                if (!(flags & MMC_PM_KEEP_POWER))
                        goto cut_pwr;
@@ -1061,7 +1059,6 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
 
        timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
        while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
-
                /*
                 * Hit the credit counter with a 4-byte access, the first byte
                 * read will hit the counter and cause a decrement, while the
index a580a629a0da6ba24b251dab8147e7de74c34f7c..d5eeeae7711b253c7dcddbf4214613cd5aff86f7 100644 (file)
@@ -289,7 +289,7 @@ struct host_interest {
        u32 hi_hp_rx_traffic_ratio;                    /* 0xd8 */
 
        /* test applications flags */
-       u32 hi_test_apps_related    ;                  /* 0xdc */
+       u32 hi_test_apps_related;                      /* 0xdc */
        /* location of test script */
        u32 hi_ota_testscript;                         /* 0xe0 */
        /* location of CAL data */
index ebb24045a8ae6cbcac844a239d11a05ee6f86e14..40432fe7a5d2cc112a4ce6d68bb8fd43a115e01f 100644 (file)
@@ -125,8 +125,9 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,
                *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
                spin_unlock_bh(&conn->psq_lock);
                return false;
-       } else if (!conn->apsd_info)
+       } else if (!conn->apsd_info) {
                return false;
+       }
 
        if (test_bit(WMM_ENABLED, &vif->flags)) {
                ether_type = be16_to_cpu(datap->h_proto);
@@ -316,8 +317,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
                cookie = NULL;
                ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n",
                           skb, skb->len);
-       } else
+       } else {
                cookie = ath6kl_alloc_cookie(ar);
+       }
 
        if (cookie == NULL) {
                spin_unlock_bh(&ar->lock);
@@ -359,7 +361,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
        struct ath6kl_vif *vif = netdev_priv(dev);
        u32 map_no = 0;
        u16 htc_tag = ATH6KL_DATA_PKT_TAG;
-       u8 ac = 99 ; /* initialize to unmapped ac */
+       u8 ac = 99; /* initialize to unmapped ac */
        bool chk_adhoc_ps_mapping = false;
        int ret;
        struct wmi_tx_meta_v2 meta_v2;
@@ -449,8 +451,9 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
                        if (ret)
                                goto fail_tx;
                }
-       } else
+       } else {
                goto fail_tx;
+       }
 
        spin_lock_bh(&ar->lock);
 
@@ -702,7 +705,6 @@ void ath6kl_tx_complete(struct htc_target *target,
 
        /* reap completed packets */
        while (!list_empty(packet_queue)) {
-
                packet = list_first_entry(packet_queue, struct htc_packet,
                                          list);
                list_del(&packet->list);
@@ -1089,8 +1091,9 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
                        else
                                skb_queue_tail(&rxtid->q, node->skb);
                        node->skb = NULL;
-               } else
+               } else {
                        stats->num_hole++;
+               }
 
                rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next);
                idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
@@ -1211,7 +1214,7 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
                return is_queued;
 
        spin_lock_bh(&rxtid->lock);
-       for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+       for (idx = 0; idx < rxtid->hold_q_sz; idx++) {
                if (rxtid->hold_q[idx].skb) {
                        /*
                         * There is a frame in the queue and no
@@ -1265,7 +1268,6 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,
        is_apsdq_empty_at_start = is_apsdq_empty;
 
        while ((!is_apsdq_empty) && (num_frames_to_deliver)) {
-
                spin_lock_bh(&conn->psq_lock);
                skb = skb_dequeue(&conn->apsdq);
                is_apsdq_empty = skb_queue_empty(&conn->apsdq);
@@ -1606,16 +1608,18 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                        if (!conn)
                                return;
                        aggr_conn = conn->aggr_conn;
-               } else
+               } else {
                        aggr_conn = vif->aggr_cntxt->aggr_conn;
+               }
 
                if (aggr_process_recv_frm(aggr_conn, tid, seq_no,
                                          is_amsdu, skb)) {
                        /* aggregation code will handle the skb */
                        return;
                }
-       } else if (!is_broadcast_ether_addr(datap->h_dest))
+       } else if (!is_broadcast_ether_addr(datap->h_dest)) {
                vif->net_stats.multicast++;
+       }
 
        ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);
 }
@@ -1710,8 +1714,9 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
                sta = ath6kl_find_sta_by_aid(vif->ar, aid);
                if (sta)
                        aggr_conn = sta->aggr_conn;
-       } else
+       } else {
                aggr_conn = vif->aggr_cntxt->aggr_conn;
+       }
 
        if (!aggr_conn)
                return;
@@ -1766,7 +1771,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
                skb_queue_head_init(&rxtid->q);
                spin_lock_init(&rxtid->lock);
        }
-
 }
 
 struct aggr_info *aggr_init(struct ath6kl_vif *vif)
@@ -1806,8 +1810,9 @@ void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux)
                sta = ath6kl_find_sta_by_aid(vif->ar, aid);
                if (sta)
                        aggr_conn = sta->aggr_conn;
-       } else
+       } else {
                aggr_conn = vif->aggr_cntxt->aggr_conn;
+       }
 
        if (!aggr_conn)
                return;
index 56c3fd5cef65a07e915d63d8c0dc24727a87406b..3afc5a463d06f822f339250deecfb1cefadea592 100644 (file)
@@ -236,7 +236,6 @@ static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe)
                        break;
                kfree(urb_context);
        }
-
 }
 
 static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb)
@@ -245,7 +244,6 @@ static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb)
 
        for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++)
                ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]);
-
 }
 
 static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb,
index 8b4ce28e3ce8f51f7cda070364394a117d5aef66..0c0e1e36e40fe7359e7190f2abc2015ab79578bb 100644 (file)
@@ -289,8 +289,9 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
                           ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
                                        sizeof(struct ath6kl_llc_snap_hdr),
                                        layer2_priority);
-               } else
+               } else {
                        usr_pri = layer2_priority & 0x7;
+               }
 
                /*
                 * Queue the EAPOL frames in the same WMM_AC_VO queue
@@ -359,8 +360,9 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
                hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
                                   sizeof(u32));
                skb_pull(skb, hdr_size);
-       } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA))
+       } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) {
                skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
+       }
 
        datap = skb->data;
        llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
@@ -936,7 +938,6 @@ ath6kl_regd_find_country_by_rd(u16 regdmn)
 
 static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
 {
-
        struct ath6kl_wmi_regdomain *ev;
        struct country_code_to_enum_rd *country = NULL;
        struct reg_dmn_pair_mapping *regpair = NULL;
@@ -946,10 +947,9 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
        ev = (struct ath6kl_wmi_regdomain *) datap;
        reg_code = le32_to_cpu(ev->reg_code);
 
-       if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG)
+       if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) {
                country = ath6kl_regd_find_country((u16) reg_code);
-       else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {
-
+       } else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {
                regpair = ath6kl_get_regpair((u16) reg_code);
                country = ath6kl_regd_find_country_by_rd((u16) reg_code);
                if (regpair)
@@ -1499,7 +1499,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
 
        if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
            (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
-
                ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
                tsinfo = le16_to_cpu(ts->tsinfo);
                tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
@@ -1530,7 +1529,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
         * for delete qos stream from AP
         */
        else if (reply->cac_indication == CAC_INDICATION_DELETE) {
-
                ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
                tsinfo = le16_to_cpu(ts->tsinfo);
                ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
@@ -2479,7 +2477,6 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
                goto free_data_skb;
 
        for (index = 0; index < num_pri_streams; index++) {
-
                if (WARN_ON(!data_sync_bufs[index].skb))
                        goto free_data_skb;
 
@@ -2704,7 +2701,6 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
 
        for (i = 0; i < WMM_NUM_AC; i++) {
                if (stream_exist & (1 << i)) {
-
                        /*
                         * FIXME: Is this lock & unlock inside
                         * for loop correct? may need rework.
@@ -2870,8 +2866,9 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
        if (host_mode == ATH6KL_HOST_MODE_ASLEEP) {
                ath6kl_wmi_relinquish_implicit_pstream_credits(wmi);
                cmd->asleep = cpu_to_le32(1);
-       } else
+       } else {
                cmd->awake = cpu_to_le32(1);
+       }
 
        ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
                                  WMI_SET_HOST_SLEEP_MODE_CMDID,
index b5f226503baf7e37ea15c7953878f7a05185375f..1f05ecd97c912b1efdfdea3910abd3aca71be38a 100644 (file)
@@ -898,7 +898,6 @@ struct wmi_start_scan_cmd {
  *  flags here
  */
 enum wmi_scan_ctrl_flags_bits {
-
        /* set if can scan in the connect cmd */
        CONNECT_SCAN_CTRL_FLAGS = 0x01,
 
index a0398fe3eb284f94e650f4541e18bfcd6713e5ef..be3eb2a8d602ee9096cf2f7b798d4ea5807dba82 100644 (file)
@@ -86,7 +86,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
        int irq;
        int ret = 0;
        struct ath_hw *ah;
-       struct ath_common *common;
        char hw_name[64];
 
        if (!dev_get_platdata(&pdev->dev)) {
@@ -146,9 +145,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
        wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
                   hw_name, (unsigned long)mem, irq);
 
-       common = ath9k_hw_common(sc->sc_ah);
-       /* Will be cleared in ath9k_start() */
-       set_bit(ATH_OP_INVALID, &common->op_flags);
        return 0;
 
  err_irq:
index 6d47783f2e5b7ecfd4343c29c8ad4bcbff7252aa..ba502a2d199bc2c85e00718d7f1cda1f71e90e43 100644 (file)
@@ -155,6 +155,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
                ATH9K_ANI_RSSI_THR_LOW,
                ATH9K_ANI_RSSI_THR_HIGH);
 
+       if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_OFDM_DEF_LEVEL)
+               immunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
+
        if (!scan)
                aniState->ofdmNoiseImmunityLevel = immunityLevel;
 
@@ -235,6 +238,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
                BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
                ATH9K_ANI_RSSI_THR_HIGH);
 
+       if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_CCK_DEF_LEVEL)
+               immunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+
        if (ah->opmode == NL80211_IFTYPE_STATION &&
            BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
            immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
index 0a6163e9248c0fdefa0f0e78a695201fb8a7d0f2..c38399bc9aa96e84fce4929319599e1d4db694c7 100644 (file)
@@ -410,7 +410,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
        {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
+       {0x00009e40, 0x0d261800},
        {0x00009e4c, 0x00001004},
        {0x00009e50, 0x00ff03f1},
        {0x00009e54, 0x00000000},
index f76139bbb74f0fcf144e22dd382be140c48cf08b..2c42ff05efa38f507cdd0f54905d8b79c0c77d32 100644 (file)
@@ -592,7 +592,7 @@ static const u32 ar9331_1p1_baseband_core[][2] = {
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
        {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
+       {0x00009e40, 0x0d261800},
        {0x00009e4c, 0x00001004},
        {0x00009e50, 0x00ff03f1},
        {0x00009fc0, 0x803e4788},
index 0ac8be96097f2e70f436f75aadb4be1b2d2bc44b..2154efcd3900514af944619a174db08d2514a140 100644 (file)
@@ -231,7 +231,7 @@ static const u32 ar9331_1p2_baseband_core[][2] = {
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
        {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
+       {0x00009e40, 0x0d261800},
        {0x00009e4c, 0x00001004},
        {0x00009e50, 0x00ff03f1},
        {0x00009fc0, 0x803e4788},
index a01f0edb65182a16b95181038786c9d8073a1cab..b995ffe88b33bb8af6ca6a7aaa47e23adee34857 100644 (file)
@@ -318,7 +318,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
        {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
+       {0x00009e40, 0x0d261800},
        {0x00009e4c, 0x00001004},
        {0x00009e50, 0x00ff03f1},
        {0x00009e54, 0x00000000},
@@ -348,9 +348,9 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a370, 0x00000000},
        {0x0000a390, 0x00000001},
        {0x0000a394, 0x00000444},
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x210d0401},
-       {0x0000a3a0, 0xab9a7144},
+       {0x0000a398, 0x001f0e0f},
+       {0x0000a39c, 0x0075393f},
+       {0x0000a3a0, 0xb79f6427},
        {0x0000a3a4, 0x00000000},
        {0x0000a3a8, 0xaaaaaaaa},
        {0x0000a3ac, 0x3c466478},
index 3c9113d9b1bc3cfe3aa7e9e07be8efa1a2df4d14..8e5c3b9786e3ac3fab8cf42e0d80bf84f268d4d2 100644 (file)
@@ -257,9 +257,9 @@ static const u32 qca953x_1p0_baseband_core[][2] = {
        {0x0000a370, 0x00000000},
        {0x0000a390, 0x00000001},
        {0x0000a394, 0x00000444},
-       {0x0000a398, 0x1f020503},
-       {0x0000a39c, 0x29180c03},
-       {0x0000a3a0, 0x9a8b6844},
+       {0x0000a398, 0x001f0e0f},
+       {0x0000a39c, 0x0075393f},
+       {0x0000a3a0, 0xb79f6427},
        {0x0000a3a4, 0x000000ff},
        {0x0000a3a8, 0x6a6a6a6a},
        {0x0000a3ac, 0x6a6a6a6a},
index e6aec2c0207ff43754a79a236a769a33bacf401e..a5ca65240af30b8980b5732a610d73ef155063c9 100644 (file)
@@ -90,7 +90,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
        {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
+       {0x00009e40, 0x0d261800},
        {0x00009e4c, 0x00001004},
        {0x00009e50, 0x00ff03f1},
        {0x00009e54, 0x00000000},
index 44d74495c4de1465dbf42cba08b6bff03090023a..33a2ae77b59514b66269cfbc7c42512611d7c8a6 100644 (file)
@@ -114,6 +114,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 #define ATH_TXFIFO_DEPTH           8
 #define ATH_TX_ERROR               0x01
 
+/* Stop tx traffic 1ms before the GO goes away */
+#define ATH_P2P_PS_STOP_TIME       1000
+
 #define IEEE80211_SEQ_SEQ_SHIFT    4
 #define IEEE80211_SEQ_MAX          4096
 #define IEEE80211_WEP_IVLEN        3
@@ -251,7 +254,6 @@ struct ath_atx_tid {
 
        s8 bar_index;
        bool sched;
-       bool paused;
        bool active;
 };
 
@@ -367,11 +369,15 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
 /********/
 
 struct ath_vif {
+       struct ieee80211_vif *vif;
        struct ath_node mcast_node;
        int av_bslot;
        bool primary_sta_vif;
        __le64 tsf_adjust; /* TSF adjustment for staggered beacons */
        struct ath_buf *av_bcbuf;
+
+       /* P2P Client */
+       struct ieee80211_noa_data noa;
 };
 
 struct ath9k_vif_iter_data {
@@ -464,6 +470,8 @@ int ath_update_survey_stats(struct ath_softc *sc);
 void ath_update_survey_nf(struct ath_softc *sc, int channel);
 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
 void ath_ps_full_sleep(unsigned long data);
+void ath9k_p2p_ps_timer(void *priv);
+void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
 
 /**********/
 /* BTCOEX */
@@ -714,6 +722,9 @@ struct ath_softc {
        struct completion paprd_complete;
        wait_queue_head_t tx_wait;
 
+       struct ath_gen_timer *p2p_ps_timer;
+       struct ath_vif *p2p_ps_vif;
+
        unsigned long driver_data;
 
        u8 gtt_cnt;
index d76e6e0120d2c28236163f56de4471c46f397c60..ffca918ff16aff4be941d572ac19d4f152e5b2c2 100644 (file)
@@ -72,7 +72,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf,
                ath_txq_lock(sc, txq);
                if (tid->active) {
                        len += scnprintf(buf + len, size - len,
-                                        "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n",
+                                        "%3d%11d%10d%10d%10d%10d%9d%6d\n",
                                         tid->tidno,
                                         tid->seq_start,
                                         tid->seq_next,
@@ -80,8 +80,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf,
                                         tid->baw_head,
                                         tid->baw_tail,
                                         tid->bar_index,
-                                        tid->sched,
-                                        tid->paused);
+                                        tid->sched);
                }
                ath_txq_unlock(sc, txq);
        }
index cbbb02a6b13b463c9bfdf8b1bad21f45cde0b4cd..4243509616bd75e58e2d1af4e8ec375ccd021281 100644 (file)
@@ -589,6 +589,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        if (ret)
                goto err_btcoex;
 
+       sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
+               NULL, sc, AR_FIRST_NDP_TIMER);
+
        ath9k_cmn_init_crypto(sc->sc_ah);
        ath9k_init_misc(sc);
        ath_fill_led_pin(sc);
@@ -644,13 +647,13 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)
 
 static const struct ieee80211_iface_limit if_limits[] = {
        { .max = 2048,  .types = BIT(NL80211_IFTYPE_STATION) |
-                                BIT(NL80211_IFTYPE_P2P_CLIENT) |
                                 BIT(NL80211_IFTYPE_WDS) },
        { .max = 8,     .types =
 #ifdef CONFIG_MAC80211_MESH
                                 BIT(NL80211_IFTYPE_MESH_POINT) |
 #endif
-                                BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_AP) },
+       { .max = 1,     .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
                                 BIT(NL80211_IFTYPE_P2P_GO) },
 };
 
@@ -783,6 +786,9 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
        common = ath9k_hw_common(ah);
        ath9k_set_hw_capab(sc, hw);
 
+       /* Will be cleared in ath9k_start() */
+       set_bit(ATH_OP_INVALID, &common->op_flags);
+
        /* Initialize regulatory */
        error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
                              ath9k_reg_notifier);
@@ -852,6 +858,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 {
        int i = 0;
 
+       if (sc->p2p_ps_timer)
+               ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
+
        ath9k_deinit_btcoex(sc);
 
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
index d69853b848ce1f10167275c4e85d6026ee41c5f1..8d7b9b66fefa592e5cee77b55e84c49b14ea2de0 100644 (file)
@@ -261,6 +261,8 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        sc->gtt_cnt = 0;
        ieee80211_wake_queues(sc->hw);
 
+       ath9k_p2p_ps_timer(sc);
+
        return true;
 }
 
@@ -1119,6 +1121,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        if (ath9k_uses_beacons(vif->type))
                ath9k_beacon_assign_slot(sc, vif);
 
+       avp->vif = vif;
+
        an->sc = sc;
        an->sta = NULL;
        an->vif = vif;
@@ -1163,6 +1167,29 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
        return 0;
 }
 
+static void
+ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       s32 tsf, target_tsf;
+
+       if (!avp || !avp->noa.has_next_tsf)
+               return;
+
+       ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
+
+       tsf = ath9k_hw_gettsf32(sc->sc_ah);
+
+       target_tsf = avp->noa.next_tsf;
+       if (!avp->noa.absent)
+               target_tsf -= ATH_P2P_PS_STOP_TIME;
+
+       if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
+               target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
+
+       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+}
+
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
 {
@@ -1174,6 +1201,13 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&sc->mutex);
 
+       spin_lock_bh(&sc->sc_pcu_lock);
+       if (avp == sc->p2p_ps_vif) {
+               sc->p2p_ps_vif = NULL;
+               ath9k_update_p2p_ps_timer(sc, NULL);
+       }
+       spin_unlock_bh(&sc->sc_pcu_lock);
+
        sc->nvifs--;
        sc->tx99_vif = NULL;
 
@@ -1636,6 +1670,72 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
                ath9k_set_assoc_state(sc, vif);
 }
 
+void ath9k_p2p_ps_timer(void *priv)
+{
+       struct ath_softc *sc = priv;
+       struct ath_vif *avp = sc->p2p_ps_vif;
+       struct ieee80211_vif *vif;
+       struct ieee80211_sta *sta;
+       struct ath_node *an;
+       u32 tsf;
+
+       if (!avp)
+               return;
+
+       tsf = ath9k_hw_gettsf32(sc->sc_ah);
+       if (!avp->noa.absent)
+               tsf += ATH_P2P_PS_STOP_TIME;
+
+       if (!avp->noa.has_next_tsf ||
+           avp->noa.next_tsf - tsf > BIT(31))
+               ieee80211_update_p2p_noa(&avp->noa, tsf);
+
+       ath9k_update_p2p_ps_timer(sc, avp);
+
+       rcu_read_lock();
+
+       vif = avp->vif;
+       sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+       if (!sta)
+               goto out;
+
+       an = (void *) sta->drv_priv;
+       if (an->sleeping == !!avp->noa.absent)
+               goto out;
+
+       an->sleeping = avp->noa.absent;
+       if (an->sleeping)
+               ath_tx_aggr_sleep(sta, sc, an);
+       else
+               ath_tx_aggr_wakeup(sc, an);
+
+out:
+       rcu_read_unlock();
+}
+
+void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+       struct ath_vif *avp = (void *)vif->drv_priv;
+       unsigned long flags;
+       u32 tsf;
+
+       if (!sc->p2p_ps_timer)
+               return;
+
+       if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
+               return;
+
+       sc->p2p_ps_vif = avp;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (!(sc->ps_flags & PS_BEACON_SYNC)) {
+               tsf = ath9k_hw_gettsf32(sc->sc_ah);
+               ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+               ath9k_update_p2p_ps_timer(sc, avp);
+       }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
 static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
                                   struct ieee80211_bss_conf *bss_conf,
@@ -1710,6 +1810,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if (changed & BSS_CHANGED_P2P_PS) {
+               spin_lock_bh(&sc->sc_pcu_lock);
+               ath9k_update_p2p_ps(sc, vif);
+               spin_unlock_bh(&sc->sc_pcu_lock);
+       }
+
        if (changed & CHECK_ANI)
                ath_check_ani(sc);
 
@@ -1883,7 +1989,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc)
        return !!npend;
 }
 
-static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       u32 queues, bool drop)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
index 25304adece571d9d4e498df9398103a49ad08a7e..914dbc6b17208df991e92d3c3539508ea31f57ad 100644 (file)
@@ -784,7 +784,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct ath_softc *sc;
        struct ieee80211_hw *hw;
-       struct ath_common *common;
        u8 csz;
        u32 val;
        int ret = 0;
@@ -877,10 +876,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
                   hw_name, (unsigned long)sc->mem, pdev->irq);
 
-       /* Will be cleared in ath9k_start() */
-       common = ath9k_hw_common(sc->sc_ah);
-       set_bit(ATH_OP_INVALID, &common->op_flags);
-
        return 0;
 
 err_init:
index 6c9accdb52e4140076d7378f530e975c34f68433..441c71448e4ce7ff77c36ac943edf16d383b1ec0 100644 (file)
@@ -539,6 +539,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                ath_dbg(common, PS,
                        "Reconfigure beacon timers based on synchronized timestamp\n");
                ath9k_set_beacon(sc);
+
+               if (sc->p2p_ps_vif)
+                       ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
        }
 
        if (ath_beacon_dtim_pending_cab(skb)) {
@@ -975,6 +978,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
        u64 tsf = 0;
        unsigned long flags;
        dma_addr_t new_buf_addr;
+       unsigned int budget = 512;
 
        if (edma)
                dma_type = DMA_BIDIRECTIONAL;
@@ -1113,15 +1117,17 @@ requeue_drop_frag:
                }
 requeue:
                list_add_tail(&bf->list, &sc->rx.rxbuf);
-               if (flush)
-                       continue;
 
                if (edma) {
                        ath_rx_edma_buf_link(sc, qtype);
                } else {
                        ath_rx_buf_relink(sc, bf);
-                       ath9k_hw_rxena(ah);
+                       if (!flush)
+                               ath9k_hw_rxena(ah);
                }
+
+               if (!budget--)
+                       break;
        } while (1);
 
        if (!(ah->imask & ATH9K_INT_RXEOL)) {
index 87cbec47fb48371403daaa70b32c1b9bc40ce1ec..66acb2cbd9df3cc45c307bb6b38118436da3d01a 100644 (file)
@@ -107,9 +107,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
 {
        struct ath_atx_ac *ac = tid->ac;
 
-       if (tid->paused)
-               return;
-
        if (tid->sched)
                return;
 
@@ -1407,7 +1404,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
        ath_tx_tid_change_state(sc, txtid);
 
        txtid->active = true;
-       txtid->paused = true;
        *ssn = txtid->seq_start = txtid->seq_next;
        txtid->bar_index = -1;
 
@@ -1427,7 +1423,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 
        ath_txq_lock(sc, txq);
        txtid->active = false;
-       txtid->paused = false;
        ath_tx_flush_tid(sc, txtid);
        ath_tx_tid_change_state(sc, txtid);
        ath_txq_unlock_complete(sc, txq);
@@ -1487,7 +1482,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
                ath_txq_lock(sc, txq);
                ac->clear_ps_filter = true;
 
-               if (!tid->paused && ath_tid_has_buffered(tid)) {
+               if (ath_tid_has_buffered(tid)) {
                        ath_tx_queue_tid(txq, tid);
                        ath_txq_schedule(sc, txq);
                }
@@ -1510,7 +1505,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
        ath_txq_lock(sc, txq);
 
        tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-       tid->paused = false;
 
        if (ath_tid_has_buffered(tid)) {
                ath_tx_queue_tid(txq, tid);
@@ -1544,8 +1538,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
                        continue;
 
                tid = ATH_AN_2_TID(an, i);
-               if (tid->paused)
-                       continue;
 
                ath_txq_lock(sc, tid->ac->txq);
                while (nframes > 0) {
@@ -1844,9 +1836,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
                        list_del(&tid->list);
                        tid->sched = false;
 
-                       if (tid->paused)
-                               continue;
-
                        if (ath_tx_sched_aggr(sc, txq, tid, &stop))
                                sent = true;
 
@@ -2698,7 +2687,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
                tid->baw_size  = WME_MAX_BA;
                tid->baw_head  = tid->baw_tail = 0;
                tid->sched     = false;
-               tid->paused    = false;
                tid->active        = false;
                __skb_queue_head_init(&tid->buf_q);
                __skb_queue_head_init(&tid->retry_q);
index 4c8cdb097b6599c08816a4e184537d764bc9ef43..f8ded84b7be8c5e3b6038910a8829364a5e5ba1e 100644 (file)
@@ -1707,7 +1707,9 @@ found:
        return 0;
 }
 
-static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void carl9170_op_flush(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             u32 queues, bool drop)
 {
        struct ar9170 *ar = hw->priv;
        unsigned int vid;
index 5824cd41e4bac6d387087ab84739df3225b8f799..73593aa3cd9813e2bd6849b969427f83f1a9a578 100644 (file)
@@ -338,7 +338,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
        }
 
        if (isr)
-               wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
+               wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
 
        wil->isr_misc = 0;
 
index 95f4efe9ef37c652722a5ca381af4529a6ea65e9..1b265fd19de26060329ffb3c7b2818feeb2fcc68 100644 (file)
@@ -363,8 +363,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
                wil_err(wil, "Firmware not ready\n");
                return -ETIME;
        } else {
-               wil_dbg_misc(wil, "FW ready after %d ms\n",
-                            jiffies_to_msecs(to-left));
+               wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
+                        jiffies_to_msecs(to-left), wil->hw_version);
        }
        return 0;
 }
index f1e1bb338d681e71c96b130363bf04387c3ffa85..0660884183070d7d46876e0a07effb2c1650e005 100644 (file)
@@ -74,8 +74,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
        if (rc)
                goto release_irq;
 
-       wil_info(wil, "HW version: 0x%08x\n", wil->hw_version);
-
        return 0;
 
  release_irq:
index d04629fe053f5e2f864bc1342ebdadf144d17008..ec29954bd44dd1d8de1cf46ce736cc4f8157127e 100644 (file)
@@ -91,6 +91,22 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 
        spin_lock(&r->reorder_lock);
 
+       /** Due to the race between WMI events, where BACK establishment
+        * reported, and data Rx, few packets may be pass up before reorder
+        * buffer get allocated. Catch up by pretending SSN is what we
+        * see in the 1-st Rx packet
+        */
+       if (r->first_time) {
+               r->first_time = false;
+               if (seq != r->head_seq_num) {
+                       wil_err(wil, "Error: 1-st frame with wrong sequence"
+                               " %d, should be %d. Fixing...\n", seq,
+                               r->head_seq_num);
+                       r->head_seq_num = seq;
+                       r->ssn = seq;
+               }
+       }
+
        /* frame with out of date sequence number */
        if (seq_less(seq, r->head_seq_num)) {
                dev_kfree_skb(skb);
@@ -162,6 +178,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
        r->head_seq_num = ssn;
        r->buf_size = size;
        r->stored_mpdu_num = 0;
+       r->first_time = true;
        return r;
 }
 
index 2a2dec75f02606c9ea71ecd95d846287520157d5..d3b8659ca32e17853602a8a21525f345abaf92a2 100644 (file)
@@ -35,7 +35,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 #define WIL6210_MEM_SIZE (2*1024*1024UL)
 
 #define WIL6210_RX_RING_SIZE   (128)
-#define WIL6210_TX_RING_SIZE   (128)
+#define WIL6210_TX_RING_SIZE   (512)
 #define WIL6210_MAX_TX_RINGS   (24) /* HW limit */
 #define WIL6210_MAX_CID                (8) /* HW limit */
 #define WIL6210_NAPI_BUDGET    (16) /* arbitrary */
@@ -301,6 +301,7 @@ struct wil_tid_ampdu_rx {
        u16 buf_size;
        u16 timeout;
        u8 dialog_token;
+       bool first_time; /* is it 1-st time this buffer used? */
 };
 
 struct wil6210_stats {
index 2ba56eef0c457d4397c27fa84a1291b011d3884f..e9a11cb3428ad1c44d4f33b18aeab3198a937120 100644 (file)
@@ -192,7 +192,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
        might_sleep();
 
        if (!test_bit(wil_status_fwready, &wil->status)) {
-               wil_err(wil, "FW not ready\n");
+               wil_err(wil, "WMI: cannot send command while FW not ready\n");
                return -EAGAIN;
        }
 
@@ -276,8 +276,8 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
        wil->fw_version = le32_to_cpu(evt->sw_version);
        wil->n_mids = evt->numof_additional_mids;
 
-       wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
-                   evt->mac, wil->n_mids);
+       wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
+                evt->mac, wil->n_mids);
 
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
@@ -290,7 +290,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
 static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
                             int len)
 {
-       wil_dbg_wmi(wil, "WMI: FW ready\n");
+       wil_dbg_wmi(wil, "WMI: got FW ready event\n");
 
        set_bit(wil_status_fwready, &wil->status);
        /* reuse wmi_ready for the firmware ready indication */
@@ -348,7 +348,7 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
 {
        if (wil->scan_request) {
                struct wmi_scan_complete_event *data = d;
-               bool aborted = (data->status != 0);
+               bool aborted = (data->status != WMI_SCAN_SUCCESS);
 
                wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
                cfg80211_scan_done(wil->scan_request, aborted);
@@ -802,6 +802,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
                .network_type = wmi_nettype,
                .disable_sec_offload = 1,
                .channel = chan - 1,
+               .pcp_max_assoc_sta = WIL6210_MAX_CID,
        };
        struct {
                struct wil6210_mbox_hdr_wmi wmi;
index 50b8528394f4050b8098098e9bbdd0520ae1bf2a..17334c852866c3cc8a061eecb829052ebd9415cf 100644 (file)
@@ -28,7 +28,7 @@
 #define __WILOCITY_WMI_H__
 
 /* General */
-
+#define WILOCITY_MAX_ASSOC_STA (8)
 #define WMI_MAC_LEN            (6)
 #define WMI_PROX_RANGE_NUM     (3)
 
@@ -219,15 +219,6 @@ struct wmi_disconnect_sta_cmd {
        __le16 disconnect_reason;
 } __packed;
 
-/*
- * WMI_RECONNECT_CMDID
- */
-struct wmi_reconnect_cmd {
-       u8 channel;                     /* hint */
-       u8 reserved;
-       u8 bssid[WMI_MAC_LEN];          /* mandatory if set */
-} __packed;
-
 
 /*
  * WMI_SET_PMK_CMDID
@@ -296,11 +287,13 @@ enum wmi_scan_type {
        WMI_LONG_SCAN           = 0,
        WMI_SHORT_SCAN          = 1,
        WMI_PBC_SCAN            = 2,
+       WMI_ACTIVE_SCAN         = 3,
+       WMI_DIRECT_SCAN         = 4,
 };
 
 struct wmi_start_scan_cmd {
-       u8 reserved[8];
-
+       u8 direct_scan_mac_addr[6];
+       u8 reserved[2];
        __le32 home_dwell_time; /* Max duration in the home channel(ms) */
        __le32 force_scan_interval;     /* Time interval between scans (ms)*/
        u8 scan_type;           /* wmi_scan_type */
@@ -332,6 +325,7 @@ struct wmi_probed_ssid_cmd {
        u8 ssid[WMI_MAX_SSID_LEN];
 } __packed;
 
+
 /*
  * WMI_SET_APPIE_CMDID
  * Add Application specified IE to a management frame
@@ -427,7 +421,7 @@ struct wmi_bcon_ctrl_cmd {
        __le16 frag_num;
        __le64 ss_mask;
        u8 network_type;
-       u8 reserved;
+       u8 pcp_max_assoc_sta;
        u8 disable_sec_offload;
        u8 disable_sec;
 } __packed;
@@ -450,7 +444,7 @@ enum wmi_port_role {
 struct wmi_port_allocate_cmd {
        u8 mac[WMI_MAC_LEN];
        u8 port_role;
-       u8 midid;
+       u8 mid;
 } __packed;
 
 /*
@@ -467,6 +461,7 @@ struct wmi_delete_port_cmd {
 enum wmi_discovery_mode {
        WMI_DISCOVERY_MODE_NON_OFFLOAD  = 0,
        WMI_DISCOVERY_MODE_OFFLOAD      = 1,
+       WMI_DISCOVERY_MODE_PEER2PEER    = 2,
 };
 
 struct wmi_p2p_cfg_cmd {
@@ -493,7 +488,8 @@ struct wmi_power_mgmt_cfg_cmd {
  */
 struct wmi_pcp_start_cmd {
        __le16 bcon_interval;
-       u8 reserved0[10];
+       u8 pcp_max_assoc_sta;
+       u8 reserved0[9];
        u8 network_type;
        u8 channel;
        u8 disable_sec_offload;
@@ -857,6 +853,7 @@ enum wmi_event_id {
        WMI_RF_MGMT_STATUS_EVENTID              = 0x1853,
        WMI_BF_SM_MGMT_DONE_EVENTID             = 0x1838,
        WMI_RX_MGMT_PACKET_EVENTID              = 0x1840,
+       WMI_TX_MGMT_PACKET_EVENTID              = 0x1841,
 
        /* Performance monitoring events */
        WMI_DATA_PORT_OPEN_EVENTID              = 0x1860,
@@ -1040,16 +1037,23 @@ enum wmi_disconnect_reason {
 struct wmi_disconnect_event {
        __le16 protocol_reason_status;  /* reason code, see 802.11 spec. */
        u8 bssid[WMI_MAC_LEN];          /* set if known */
-       u8 disconnect_reason;           /* see wmi_disconnect_reason_e */
-       u8 assoc_resp_len;
-       u8 assoc_info[0];
+       u8 disconnect_reason;           /* see wmi_disconnect_reason */
+       u8 assoc_resp_len;              /* not in use */
+       u8 assoc_info[0];               /* not in use */
 } __packed;
 
 /*
  * WMI_SCAN_COMPLETE_EVENTID
  */
+enum scan_status {
+       WMI_SCAN_SUCCESS        = 0,
+       WMI_SCAN_FAILED         = 1,
+       WMI_SCAN_ABORTED        = 2,
+       WMI_SCAN_REJECTED       = 3,
+};
+
 struct wmi_scan_complete_event {
-       __le32 status;
+       __le32 status;  /* scan_status */
 } __packed;
 
 /*
@@ -1256,6 +1260,14 @@ struct wmi_rx_mgmt_info {
        u8 channel;     /* From Radio MNGR */
 } __packed;
 
+
+/*
+ * WMI_TX_MGMT_PACKET_EVENTID
+ */
+struct wmi_tx_mgmt_packet_event {
+       u8 payload[0];
+} __packed;
+
 struct wmi_rx_mgmt_packet_event {
        struct wmi_rx_mgmt_info info;
        u8 payload[0];
index 54376fddfaf9f11fef6e4a7a0ae5554d5e427f4c..4113b69347640359aa22020eb0dcfd7efe0b7c14 100644 (file)
@@ -915,10 +915,6 @@ struct b43_wl {
        char rng_name[30 + 1];
 #endif /* CONFIG_B43_HWRNG */
 
-       /* List of all wireless devices on this chip */
-       struct list_head devlist;
-       u8 nr_devs;
-
        bool radiotap_enabled;
        bool radio_enabled;
 
index 69fc3d65531a7eeb88c4901f804ab197dbbb939e..32e08d35c06e131118e761a7df207a59b7e0043d 100644 (file)
@@ -1195,8 +1195,13 @@ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
                  B43_BCMA_CLKCTLST_PHY_PLL_REQ;
        u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST |
                     B43_BCMA_CLKCTLST_PHY_PLL_ST;
+       u32 flags;
+
+       flags = B43_BCMA_IOCTL_PHY_CLKEN;
+       if (gmode)
+               flags |= B43_BCMA_IOCTL_GMODE;
+       b43_device_enable(dev, flags);
 
-       b43_device_enable(dev, B43_BCMA_IOCTL_PHY_CLKEN);
        bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
        b43_bcma_phy_reset(dev);
        bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
@@ -3735,40 +3740,35 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
 {
        struct b43_wldev *up_dev = NULL;
        struct b43_wldev *down_dev;
-       struct b43_wldev *d;
        int err;
        bool uninitialized_var(gmode);
        int prev_status;
 
        /* Find a device and PHY which supports the band. */
-       list_for_each_entry(d, &wl->devlist, list) {
-               switch (chan->band) {
-               case IEEE80211_BAND_5GHZ:
-                       if (d->phy.supports_5ghz) {
-                               up_dev = d;
-                               gmode = false;
-                       }
-                       break;
-               case IEEE80211_BAND_2GHZ:
-                       if (d->phy.supports_2ghz) {
-                               up_dev = d;
-                               gmode = true;
-                       }
-                       break;
-               default:
-                       B43_WARN_ON(1);
-                       return -EINVAL;
+       switch (chan->band) {
+       case IEEE80211_BAND_5GHZ:
+               if (wl->current_dev->phy.supports_5ghz) {
+                       up_dev = wl->current_dev;
+                       gmode = false;
                }
-               if (up_dev)
-                       break;
+               break;
+       case IEEE80211_BAND_2GHZ:
+               if (wl->current_dev->phy.supports_2ghz) {
+                       up_dev = wl->current_dev;
+                       gmode = true;
+               }
+               break;
+       default:
+               B43_WARN_ON(1);
+               return -EINVAL;
        }
+
        if (!up_dev) {
                b43err(wl, "Could not find a device for %s-GHz band operation\n",
                       band_to_string(chan->band));
                return -ENODEV;
        }
-       if ((up_dev == wl->current_dev) &&
-           (!!wl->current_dev->phy.gmode == !!gmode)) {
+       if (!!wl->current_dev->phy.gmode == !!gmode) {
                /* This device is already running. */
                return 0;
        }
@@ -5178,7 +5178,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        }
 
        dev->phy.gmode = have_2ghz_phy;
-       dev->phy.radio_on = true;
        b43_wireless_core_reset(dev, dev->phy.gmode);
 
        err = b43_phy_versioning(dev);
@@ -5270,7 +5269,6 @@ static void b43_one_core_detach(struct b43_bus_dev *dev)
        b43_debugfs_remove_device(wldev);
        b43_wireless_core_detach(wldev);
        list_del(&wldev->list);
-       wl->nr_devs--;
        b43_bus_set_wldev(dev, NULL);
        kfree(wldev);
 }
@@ -5295,8 +5293,6 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
        if (err)
                goto err_kfree_wldev;
 
-       list_add(&wldev->list, &wl->devlist);
-       wl->nr_devs++;
        b43_bus_set_wldev(dev, wldev);
        b43_debugfs_add_device(wldev);
 
@@ -5386,7 +5382,6 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
        wl->hw = hw;
        mutex_init(&wl->mutex);
        spin_lock_init(&wl->hardirq_lock);
-       INIT_LIST_HEAD(&wl->devlist);
        INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
        INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
        INIT_WORK(&wl->tx_work, b43_tx_work);
@@ -5486,39 +5481,42 @@ int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
        struct b43_bus_dev *dev;
        struct b43_wl *wl;
        int err;
-       int first = 0;
 
        dev = b43_bus_dev_ssb_init(sdev);
        if (!dev)
                return -ENOMEM;
 
        wl = ssb_get_devtypedata(sdev);
-       if (!wl) {
-               /* Probing the first core. Must setup common struct b43_wl */
-               first = 1;
-               b43_sprom_fixup(sdev->bus);
-               wl = b43_wireless_init(dev);
-               if (IS_ERR(wl)) {
-                       err = PTR_ERR(wl);
-                       goto out;
-               }
-               ssb_set_devtypedata(sdev, wl);
-               B43_WARN_ON(ssb_get_devtypedata(sdev) != wl);
+       if (wl) {
+               b43err(NULL, "Dual-core devices are not supported\n");
+               err = -ENOTSUPP;
+               goto err_ssb_kfree_dev;
+       }
+
+       b43_sprom_fixup(sdev->bus);
+
+       wl = b43_wireless_init(dev);
+       if (IS_ERR(wl)) {
+               err = PTR_ERR(wl);
+               goto err_ssb_kfree_dev;
        }
+       ssb_set_devtypedata(sdev, wl);
+       B43_WARN_ON(ssb_get_devtypedata(sdev) != wl);
+
        err = b43_one_core_attach(dev, wl);
        if (err)
-               goto err_wireless_exit;
+               goto err_ssb_wireless_exit;
 
        /* setup and start work to load firmware */
        INIT_WORK(&wl->firmware_load, b43_request_firmware);
        schedule_work(&wl->firmware_load);
 
-      out:
        return err;
 
-      err_wireless_exit:
-       if (first)
-               b43_wireless_exit(dev, wl);
+err_ssb_wireless_exit:
+       b43_wireless_exit(dev, wl);
+err_ssb_kfree_dev:
+       kfree(dev);
        return err;
 }
 
@@ -5546,13 +5544,8 @@ static void b43_ssb_remove(struct ssb_device *sdev)
        /* Unregister HW RNG driver */
        b43_rng_exit(wl);
 
-       if (list_empty(&wl->devlist)) {
-               b43_leds_unregister(wl);
-               /* Last core on the chip unregistered.
-                * We can destroy common struct b43_wl.
-                */
-               b43_wireless_exit(dev, wl);
-       }
+       b43_leds_unregister(wl);
+       b43_wireless_exit(dev, wl);
 }
 
 static struct ssb_driver b43_ssb_driver = {
index dbaa51890198945b7552ed506bc3c8bfe4ba2359..3e45989f418d00876d00590094c6e9a1db1a4c56 100644 (file)
@@ -96,7 +96,7 @@ int b43_phy_init(struct b43_wldev *dev)
 
        phy->channel = ops->get_default_chan(dev);
 
-       ops->software_rfkill(dev, false);
+       b43_software_rfkill(dev, false);
        err = ops->init(dev);
        if (err) {
                b43err(dev->wl, "PHY init failed\n");
@@ -116,7 +116,7 @@ err_phy_exit:
        if (ops->exit)
                ops->exit(dev);
 err_block_rf:
-       ops->software_rfkill(dev, true);
+       b43_software_rfkill(dev, true);
 
        return err;
 }
@@ -125,7 +125,7 @@ void b43_phy_exit(struct b43_wldev *dev)
 {
        const struct b43_phy_operations *ops = dev->phy.ops;
 
-       ops->software_rfkill(dev, true);
+       b43_software_rfkill(dev, true);
        if (ops->exit)
                ops->exit(dev);
 }
index 12f467b8d564f1c5cdca06acbdf65ca8f80b48c8..8f5c14bc10e6fedcab2d7b88a0009470772dad8a 100644 (file)
@@ -1587,6 +1587,7 @@ static void b43_phy_initb5(struct b43_wldev *dev)
        b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */
 static void b43_phy_initb6(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
@@ -1670,7 +1671,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x50, 0x20);
        }
        if (phy->radio_rev <= 2) {
-               b43_radio_write16(dev, 0x7C, 0x20);
+               b43_radio_write16(dev, 0x50, 0x20);
                b43_radio_write16(dev, 0x5A, 0x70);
                b43_radio_write16(dev, 0x5B, 0x7B);
                b43_radio_write16(dev, 0x5C, 0xB0);
@@ -1686,9 +1687,8 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_phy_write(dev, 0x2A, 0x8AC0);
        b43_phy_write(dev, 0x0038, 0x0668);
        b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
-       if (phy->radio_rev <= 5) {
+       if (phy->radio_rev == 4 || phy->radio_rev == 5)
                b43_phy_maskset(dev, 0x5D, 0xFF80, 0x0003);
-       }
        if (phy->radio_rev <= 2)
                b43_radio_write16(dev, 0x005D, 0x000D);
 
index 24ccbe96e0c8a0723bb165b0f32677ab6ba7ded5..41dab89a2942dddbc80388079e5812382f3f6a43 100644 (file)
@@ -257,6 +257,72 @@ static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field,
        }
 }
 
+static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev,
+                                              enum n_intc_override intc_override,
+                                              u16 value, u8 core_sel)
+{
+       u16 reg, tmp, tmp2, val;
+       int core;
+
+       for (core = 0; core < 2; core++) {
+               if ((core_sel == 1 && core != 0) ||
+                   (core_sel == 2 && core != 1))
+                       continue;
+
+               reg = (core == 0) ? B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2;
+
+               switch (intc_override) {
+               case N_INTC_OVERRIDE_OFF:
+                       b43_phy_write(dev, reg, 0);
+                       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+                       break;
+               case N_INTC_OVERRIDE_TRSW:
+                       b43_phy_maskset(dev, reg, ~0xC0, value << 6);
+                       b43_phy_set(dev, reg, 0x400);
+
+                       b43_phy_mask(dev, 0x2ff, ~0xC000 & 0xFFFF);
+                       b43_phy_set(dev, 0x2ff, 0x2000);
+                       b43_phy_set(dev, 0x2ff, 0x0001);
+                       break;
+               case N_INTC_OVERRIDE_PA:
+                       tmp = 0x0030;
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+                               val = value << 5;
+                       else
+                               val = value << 4;
+                       b43_phy_maskset(dev, reg, ~tmp, val);
+                       b43_phy_set(dev, reg, 0x1000);
+                       break;
+               case N_INTC_OVERRIDE_EXT_LNA_PU:
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                               tmp = 0x0001;
+                               tmp2 = 0x0004;
+                               val = value;
+                       } else {
+                               tmp = 0x0004;
+                               tmp2 = 0x0001;
+                               val = value << 2;
+                       }
+                       b43_phy_maskset(dev, reg, ~tmp, val);
+                       b43_phy_mask(dev, reg, ~tmp2);
+                       break;
+               case N_INTC_OVERRIDE_EXT_LNA_GAIN:
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                               tmp = 0x0002;
+                               tmp2 = 0x0008;
+                               val = value << 1;
+                       } else {
+                               tmp = 0x0008;
+                               tmp2 = 0x0002;
+                               val = value << 3;
+                       }
+                       b43_phy_maskset(dev, reg, ~tmp, val);
+                       b43_phy_mask(dev, reg, ~tmp2);
+                       break;
+               }
+       }
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
 static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev,
                                          enum n_intc_override intc_override,
@@ -265,6 +331,12 @@ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev,
        u8 i, j;
        u16 reg, tmp, val;
 
+       if (dev->phy.rev >= 7) {
+               b43_nphy_rf_ctl_intc_override_rev7(dev, intc_override, value,
+                                                  core);
+               return;
+       }
+
        B43_WARN_ON(dev->phy.rev < 3);
 
        for (i = 0; i < 2; i++) {
@@ -419,7 +491,8 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
                static const u16 clip[] = { 0xFFFF, 0xFFFF };
                if (nphy->deaf_count++ == 0) {
                        nphy->classifier_state = b43_nphy_classifier(dev, 0, 0);
-                       b43_nphy_classifier(dev, 0x7, 0);
+                       b43_nphy_classifier(dev, 0x7,
+                                           B43_NPHY_CLASSCTL_WAITEDEN);
                        b43_nphy_read_clip_detection(dev, nphy->clip_state);
                        b43_nphy_write_clip_detection(dev, clip);
                }
@@ -734,9 +807,16 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
        u16 bias, cbias;
        u16 pag_boost, padg_boost, pgag_boost, mixg_boost;
        u16 paa_boost, pada_boost, pgaa_boost, mixa_boost;
+       bool is_pkg_fab_smic;
 
        B43_WARN_ON(dev->phy.rev < 3);
 
+       is_pkg_fab_smic =
+               ((dev->dev->chip_id == BCMA_CHIP_ID_BCM43224 ||
+                 dev->dev->chip_id == BCMA_CHIP_ID_BCM43225 ||
+                 dev->dev->chip_id == BCMA_CHIP_ID_BCM43421) &&
+                dev->dev->chip_pkg == BCMA_PKG_ID_BCM43224_FAB_SMIC);
+
        b43_chantab_radio_2056_upload(dev, e);
        b2056_upload_syn_pll_cp2(dev, band == IEEE80211_BAND_5GHZ);
 
@@ -744,7 +824,8 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
            b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
                b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
                b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
-               if (dev->dev->chip_id == 0x4716) {
+               if (dev->dev->chip_id == BCMA_CHIP_ID_BCM4716 ||
+                   dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) {
                        b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x14);
                        b43_radio_write(dev, B2056_SYN_PLL_CP2, 0);
                } else {
@@ -752,6 +833,13 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
                        b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x14);
                }
        }
+       if (sprom->boardflags2_hi & B43_BFH2_GPLL_WAR2 &&
+           b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1f);
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1f);
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x0b);
+               b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x20);
+       }
        if (sprom->boardflags2_lo & B43_BFL2_APLL_WAR &&
            b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
                b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
@@ -767,7 +855,8 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
                                b43_radio_write(dev,
                                        offset | B2056_TX_PADG_IDAC, 0xcc);
 
-                               if (dev->dev->chip_id == 0x4716) {
+                               if (dev->dev->chip_id == BCMA_CHIP_ID_BCM4716 ||
+                                   dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) {
                                        bias = 0x40;
                                        cbias = 0x45;
                                        pag_boost = 0x5;
@@ -776,6 +865,10 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
                                } else {
                                        bias = 0x25;
                                        cbias = 0x20;
+                                       if (is_pkg_fab_smic) {
+                                               bias = 0x2a;
+                                               cbias = 0x38;
+                                       }
                                        pag_boost = 0x4;
                                        pgag_boost = 0x03;
                                        mixg_boost = 0x65;
@@ -844,6 +937,8 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
                        mixa_boost = 0xF;
                }
 
+               cbias = is_pkg_fab_smic ? 0x35 : 0x30;
+
                for (i = 0; i < 2; i++) {
                        offset = i ? B2056_TX1 : B2056_TX0;
 
@@ -862,11 +957,11 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
                        b43_radio_write(dev,
                                offset | B2056_TX_PADA_CASCBIAS, 0x03);
                        b43_radio_write(dev,
-                               offset | B2056_TX_INTPAA_IAUX_STAT, 0x50);
+                               offset | B2056_TX_INTPAA_IAUX_STAT, 0x30);
                        b43_radio_write(dev,
-                               offset | B2056_TX_INTPAA_IMAIN_STAT, 0x50);
+                               offset | B2056_TX_INTPAA_IMAIN_STAT, 0x30);
                        b43_radio_write(dev,
-                               offset | B2056_TX_INTPAA_CASCBIAS, 0x30);
+                               offset | B2056_TX_INTPAA_CASCBIAS, cbias);
                }
        }
 
@@ -1164,23 +1259,20 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
        u16 seq_mode;
        u32 tmp;
 
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, true);
+       b43_nphy_stay_in_carrier_search(dev, true);
 
        if ((nphy->bb_mult_save & 0x80000000) == 0) {
                tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
                nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
        }
 
+       /* TODO: add modify_bbmult argument */
        if (!dev->phy.is_40mhz)
                tmp = 0x6464;
        else
                tmp = 0x4747;
        b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
 
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, false);
-
        b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
 
        if (loops != 0xFFFF)
@@ -1213,6 +1305,8 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
                b43err(dev->wl, "run samples timeout\n");
 
        b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+
+       b43_nphy_stay_in_carrier_search(dev, false);
 }
 
 /**************************************************
@@ -1588,8 +1682,8 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
        struct b43_phy_n *nphy = dev->phy.n;
 
        u16 saved_regs_phy_rfctl[2];
-       u16 saved_regs_phy[13];
-       u16 regs_to_store[] = {
+       u16 saved_regs_phy[22];
+       u16 regs_to_store_rev3[] = {
                B43_NPHY_AFECTL_OVER1, B43_NPHY_AFECTL_OVER,
                B43_NPHY_AFECTL_C1, B43_NPHY_AFECTL_C2,
                B43_NPHY_TXF_40CO_B1S1, B43_NPHY_RFCTL_OVER,
@@ -1598,6 +1692,20 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
                B43_NPHY_RFCTL_LUT_TRSW_UP1, B43_NPHY_RFCTL_LUT_TRSW_UP2,
                B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2
        };
+       u16 regs_to_store_rev7[] = {
+               B43_NPHY_AFECTL_OVER1, B43_NPHY_AFECTL_OVER,
+               B43_NPHY_AFECTL_C1, B43_NPHY_AFECTL_C2,
+               B43_NPHY_TXF_40CO_B1S1, B43_NPHY_RFCTL_OVER,
+               0x342, 0x343, 0x346, 0x347,
+               0x2ff,
+               B43_NPHY_TXF_40CO_B1S0, B43_NPHY_TXF_40CO_B32S1,
+               B43_NPHY_RFCTL_CMD,
+               B43_NPHY_RFCTL_LUT_TRSW_UP1, B43_NPHY_RFCTL_LUT_TRSW_UP2,
+               0x340, 0x341, 0x344, 0x345,
+               B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2
+       };
+       u16 *regs_to_store;
+       int regs_amount;
 
        u16 class;
 
@@ -1617,6 +1725,15 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
        u8 rx_core_state;
        int core, i, j, vcm;
 
+       if (dev->phy.rev >= 7) {
+               regs_to_store = regs_to_store_rev7;
+               regs_amount = ARRAY_SIZE(regs_to_store_rev7);
+       } else {
+               regs_to_store = regs_to_store_rev3;
+               regs_amount = ARRAY_SIZE(regs_to_store_rev3);
+       }
+       BUG_ON(regs_amount > ARRAY_SIZE(saved_regs_phy));
+
        class = b43_nphy_classifier(dev, 0, 0);
        b43_nphy_classifier(dev, 7, 4);
        b43_nphy_read_clip_detection(dev, clip_state);
@@ -1624,22 +1741,29 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
 
        saved_regs_phy_rfctl[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
        saved_regs_phy_rfctl[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
-       for (i = 0; i < ARRAY_SIZE(regs_to_store); i++)
+       for (i = 0; i < regs_amount; i++)
                saved_regs_phy[i] = b43_phy_read(dev, regs_to_store[i]);
 
        b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_OFF, 0, 7);
        b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 1, 7);
-       b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false);
-       b43_nphy_rf_ctl_override(dev, 0x2, 1, 0, false);
-       b43_nphy_rf_ctl_override(dev, 0x80, 1, 0, false);
-       b43_nphy_rf_ctl_override(dev, 0x40, 1, 0, false);
-
-       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
-               b43_nphy_rf_ctl_override(dev, 0x20, 0, 0, false);
-               b43_nphy_rf_ctl_override(dev, 0x10, 1, 0, false);
+
+       if (dev->phy.rev >= 7) {
+               /* TODO */
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+               } else {
+               }
        } else {
-               b43_nphy_rf_ctl_override(dev, 0x10, 0, 0, false);
-               b43_nphy_rf_ctl_override(dev, 0x20, 1, 0, false);
+               b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false);
+               b43_nphy_rf_ctl_override(dev, 0x2, 1, 0, false);
+               b43_nphy_rf_ctl_override(dev, 0x80, 1, 0, false);
+               b43_nphy_rf_ctl_override(dev, 0x40, 1, 0, false);
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                       b43_nphy_rf_ctl_override(dev, 0x20, 0, 0, false);
+                       b43_nphy_rf_ctl_override(dev, 0x10, 1, 0, false);
+               } else {
+                       b43_nphy_rf_ctl_override(dev, 0x10, 0, 0, false);
+                       b43_nphy_rf_ctl_override(dev, 0x20, 1, 0, false);
+               }
        }
 
        rx_core_state = b43_nphy_get_rx_core_state(dev);
@@ -1654,8 +1778,11 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
 
                /* Grab RSSI results for every possible VCM */
                for (vcm = 0; vcm < 8; vcm++) {
-                       b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3,
-                                       vcm << 2);
+                       if (dev->phy.rev >= 7)
+                               ;
+                       else
+                               b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC,
+                                                 0xE3, vcm << 2);
                        b43_nphy_poll_rssi(dev, N_RSSI_NB, results[vcm], 8);
                }
 
@@ -1682,8 +1809,11 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
                }
 
                /* Select the best VCM */
-               b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3,
-                                 vcm_final << 2);
+               if (dev->phy.rev >= 7)
+                       ;
+               else
+                       b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC,
+                                         0xE3, vcm_final << 2);
 
                for (i = 0; i < 4; i++) {
                        if (core != i / 2)
@@ -1736,9 +1866,9 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
 
        b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
        b43_phy_set(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_RXTX);
-       b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1, ~0x1);
+       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
 
-       for (i = 0; i < ARRAY_SIZE(regs_to_store); i++)
+       for (i = 0; i < regs_amount; i++)
                b43_phy_write(dev, regs_to_store[i], saved_regs_phy[i]);
 
        /* Store for future configuration */
@@ -2494,8 +2624,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        struct ssb_sprom *sprom = dev->dev->bus_sprom;
 
        /* TX to RX */
-       u8 tx2rx_events[8] = { 0x4, 0x3, 0x6, 0x5, 0x2, 0x1, 0x8, 0x1F };
-       u8 tx2rx_delays[8] = { 8, 4, 2, 2, 4, 4, 6, 1 };
+       u8 tx2rx_events[7] = { 0x4, 0x3, 0x5, 0x2, 0x1, 0x8, 0x1F };
+       u8 tx2rx_delays[7] = { 8, 4, 4, 4, 4, 6, 1 };
        /* RX to TX */
        u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
                                        0x1F };
@@ -2503,6 +2633,23 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        u8 rx2tx_events[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0x3, 0x4, 0x1F };
        u8 rx2tx_delays[9] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 };
 
+       u16 vmids[5][4] = {
+               { 0xa2, 0xb4, 0xb4, 0x89, }, /* 0 */
+               { 0xb4, 0xb4, 0xb4, 0x24, }, /* 1 */
+               { 0xa2, 0xb4, 0xb4, 0x74, }, /* 2 */
+               { 0xa2, 0xb4, 0xb4, 0x270, }, /* 3 */
+               { 0xa2, 0xb4, 0xb4, 0x00, }, /* 4 and 5 */
+       };
+       u16 gains[5][4] = {
+               { 0x02, 0x02, 0x02, 0x00, }, /* 0 */
+               { 0x02, 0x02, 0x02, 0x02, }, /* 1 */
+               { 0x02, 0x02, 0x02, 0x04, }, /* 2 */
+               { 0x02, 0x02, 0x02, 0x00, }, /* 3 */
+               { 0x02, 0x02, 0x02, 0x00, }, /* 4 and 5 */
+       };
+       u16 *vmid, *gain;
+
+       u8 pdet_range;
        u16 tmp16;
        u32 tmp32;
 
@@ -2561,7 +2708,71 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        b43_ntab_write(dev, B43_NTAB16(8, 0), 2);
        b43_ntab_write(dev, B43_NTAB16(8, 16), 2);
 
-       /* TODO */
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+               pdet_range = sprom->fem.ghz2.pdet_range;
+       else
+               pdet_range = sprom->fem.ghz5.pdet_range;
+       vmid = vmids[min_t(u16, pdet_range, 4)];
+       gain = gains[min_t(u16, pdet_range, 4)];
+       switch (pdet_range) {
+       case 3:
+               if (!(dev->phy.rev >= 4 &&
+                     b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ))
+                       break;
+               /* FALL THROUGH */
+       case 0:
+       case 1:
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4, vmid);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4, vmid);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0c), 4, gain);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1c), 4, gain);
+               break;
+       case 2:
+               if (dev->phy.rev >= 6) {
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                               vmid[3] = 0x94;
+                       else
+                               vmid[3] = 0x8e;
+                       gain[3] = 3;
+               } else if (dev->phy.rev == 5) {
+                       vmid[3] = 0x84;
+                       gain[3] = 2;
+               }
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4, vmid);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4, vmid);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0c), 4, gain);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1c), 4, gain);
+               break;
+       case 4:
+       case 5:
+               if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) {
+                       if (pdet_range == 4) {
+                               vmid[3] = 0x8e;
+                               tmp16 = 0x96;
+                               gain[3] = 0x2;
+                       } else {
+                               vmid[3] = 0x89;
+                               tmp16 = 0x89;
+                               gain[3] = 0;
+                       }
+               } else {
+                       if (pdet_range == 4) {
+                               vmid[3] = 0x89;
+                               tmp16 = 0x8b;
+                               gain[3] = 0x2;
+                       } else {
+                               vmid[3] = 0x74;
+                               tmp16 = 0x70;
+                               gain[3] = 0;
+                       }
+               }
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4, vmid);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0c), 4, gain);
+               vmid[3] = tmp16;
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4, vmid);
+               b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1c), 4, gain);
+               break;
+       }
 
        b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00);
        b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00);
@@ -2600,7 +2811,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        /* Dropped probably-always-true condition */
        b43_phy_write(dev, B43_NPHY_ED_CRS40ASSERTTHRESH0, 0x03eb);
        b43_phy_write(dev, B43_NPHY_ED_CRS40ASSERTTHRESH1, 0x03eb);
-       b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341);
+       b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH0, 0x0341);
        b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341);
        b43_phy_write(dev, B43_NPHY_ED_CRS20LASSERTTHRESH0, 0x042b);
        b43_phy_write(dev, B43_NPHY_ED_CRS20LASSERTTHRESH1, 0x042b);
@@ -3211,6 +3422,20 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev)
        u8 idx, delta;
        u8 i, stf_mode;
 
+       /* Array adj_pwr_tbl corresponds to the hardware table. It consists of
+        * 21 groups, each containing 4 entries.
+        *
+        * First group has entries for CCK modulation.
+        * The rest of groups has 1 entry per modulation (SISO, CDD, STBC, SDM).
+        *
+        * Group 0 is for CCK
+        * Groups 1..4 use BPSK (group per coding rate)
+        * Groups 5..8 use QPSK (group per coding rate)
+        * Groups 9..12 use 16-QAM (group per coding rate)
+        * Groups 13..16 use 64-QAM (group per coding rate)
+        * Groups 17..20 are unknown
+        */
+
        for (i = 0; i < 4; i++)
                nphy->adj_pwr_tbl[i] = nphy->tx_power_offset[i];
 
@@ -3409,10 +3634,8 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
        }
 
        b43_nphy_tx_prepare_adjusted_power_table(dev);
-       /*
        b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84, nphy->adj_pwr_tbl);
        b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84, nphy->adj_pwr_tbl);
-       */
 
        if (nphy->hang_avoid)
                b43_nphy_stay_in_carrier_search(dev, false);
@@ -5124,7 +5347,7 @@ static int b43_phy_initn(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
        b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
        if (phy->rev >= 3 && phy->rev <= 6)
-               b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014);
+               b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0032);
        b43_nphy_tx_lp_fbw(dev);
        if (phy->rev >= 3)
                b43_nphy_spur_workaround(dev);
@@ -5441,8 +5664,11 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
 {
        /* Register 1 is a 32-bit register. */
        B43_WARN_ON(reg == 1);
-       /* N-PHY needs 0x100 for read access */
-       reg |= 0x100;
+
+       if (dev->phy.rev >= 7)
+               reg |= 0x200; /* Radio 0x2057 */
+       else
+               reg |= 0x100;
 
        b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
index b4fd9345d673a3542d94e66260ebc685eed7ef8d..a07e4cacab7727619dedb2f1e7b642e39d23fb5f 100644 (file)
@@ -48,7 +48,7 @@ struct b2056_inittabs_pts {
        unsigned int rx_length;
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev3_syn[] = {
+static const struct b2056_inittab_entry b2056_inittab_phy_rev3_syn[] = {
        [B2056_SYN_RESERVED_ADDR2]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR3]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR4]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -232,7 +232,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev3_syn[] = {
        [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev3_tx[] = {
+static const struct b2056_inittab_entry b2056_inittab_phy_rev3_tx[] = {
        [B2056_TX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -380,7 +380,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev3_tx[] = {
        [B2056_TX_STATUS_TXLPF_RC]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev3_rx[] = {
+static const struct b2056_inittab_entry b2056_inittab_phy_rev3_rx[] = {
        [B2056_RX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -530,7 +530,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev3_rx[] = {
        [B2056_RX_STATUS_HPC_RC]        = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev4_syn[] = {
+static const struct b2056_inittab_entry b2056_inittab_phy_rev4_syn[] = {
        [B2056_SYN_RESERVED_ADDR2]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR3]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR4]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -714,7 +714,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev4_syn[] = {
        [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev4_tx[] = {
+static const struct b2056_inittab_entry b2056_inittab_phy_rev4_tx[] = {
        [B2056_TX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -862,7 +862,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev4_tx[] = {
        [B2056_TX_STATUS_TXLPF_RC]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev4_rx[] = {
+static const struct b2056_inittab_entry b2056_inittab_phy_rev4_rx[] = {
        [B2056_RX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1012,7 +1012,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev4_rx[] = {
        [B2056_RX_STATUS_HPC_RC]        = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev5_syn[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev5_syn[] = {
        [B2056_SYN_RESERVED_ADDR2]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR3]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR4]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1196,7 +1196,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev5_syn[] = {
        [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev5_tx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev5_tx[] = {
        [B2056_TX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1352,7 +1352,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev5_tx[] = {
        [B2056_TX_GMBB_IDAC7]           = { .ghz5 = 0x0075, .ghz2 = 0x0075, UPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev5_rx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev5_rx[] = {
        [B2056_RX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1502,7 +1502,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev5_rx[] = {
        [B2056_RX_STATUS_HPC_RC]        = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev6_syn[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev6_syn[] = {
        [B2056_SYN_RESERVED_ADDR2]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR3]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR4]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1686,7 +1686,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_syn[] = {
        [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev6_tx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev6_tx[] = {
        [B2056_TX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1842,7 +1842,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_tx[] = {
        [B2056_TX_GMBB_IDAC7]           = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev6_rx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev6_rx[] = {
        [B2056_RX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -1992,7 +1992,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_rx[] = {
        [B2056_RX_STATUS_HPC_RC]        = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev7_syn[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev7_9_syn[] = {
        [B2056_SYN_RESERVED_ADDR2]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR3]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR4]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -2176,7 +2176,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev7_syn[] = {
        [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev7_tx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev7_9_tx[] = {
        [B2056_TX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -2332,7 +2332,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev7_tx[] = {
        [B2056_TX_GMBB_IDAC7]           = { .ghz5 = 0x0075, .ghz2 = 0x0075, UPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev7_rx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev7_9_rx[] = {
        [B2056_RX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -2482,7 +2482,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev7_rx[] = {
        [B2056_RX_STATUS_HPC_RC]        = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev8_syn[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev8_syn[] = {
        [B2056_SYN_RESERVED_ADDR2]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR3]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_SYN_RESERVED_ADDR4]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -2666,7 +2666,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_syn[] = {
        [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev8_tx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev8_tx[] = {
        [B2056_TX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_TX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -2822,7 +2822,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_tx[] = {
        [B2056_TX_GMBB_IDAC7]           = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
 };
 
-static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = {
+static const struct b2056_inittab_entry b2056_inittab_radio_rev8_rx[] = {
        [B2056_RX_RESERVED_ADDR2]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR3]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
        [B2056_RX_RESERVED_ADDR4]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
@@ -2972,24 +2972,69 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = {
        [B2056_RX_STATUS_HPC_RC]        = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
 };
 
-#define INITTABSPTS(prefix) \
-       .syn            = prefix##_syn,                 \
-       .syn_length     = ARRAY_SIZE(prefix##_syn),     \
-       .tx             = prefix##_tx,                  \
-       .tx_length      = ARRAY_SIZE(prefix##_tx),      \
-       .rx             = prefix##_rx,                  \
-       .rx_length      = ARRAY_SIZE(prefix##_rx)
+static const struct b2056_inittab_entry b2056_inittab_radio_rev11_syn[] = {
+       [B2056_SYN_PLL_PFD]             = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, },
+       [B2056_SYN_PLL_CP2]             = { .ghz5 = 0x003f, .ghz2 = 0x003f, UPLOAD, },
+       [B2056_SYN_PLL_LOOPFILTER1]     = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, },
+       [B2056_SYN_PLL_LOOPFILTER2]     = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, },
+       [B2056_SYN_PLL_LOOPFILTER4]     = { .ghz5 = 0x002b, .ghz2 = 0x002b, UPLOAD, },
+       [B2056_SYN_PLL_VCO2]            = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+       [B2056_SYN_PLL_VCOCAL12]        = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+       [B2056_SYN_LOGENBUF2]           = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+};
 
-static const struct b2056_inittabs_pts b2056_inittabs[] = {
-       [3] = { INITTABSPTS(b2056_inittab_rev3) },
-       [4] = { INITTABSPTS(b2056_inittab_rev4) },
-       [5] = { INITTABSPTS(b2056_inittab_rev5) },
-       [6] = { INITTABSPTS(b2056_inittab_rev6) },
-       [7] = { INITTABSPTS(b2056_inittab_rev7) },
-       [8] = { INITTABSPTS(b2056_inittab_rev8) },
-       [9] = { INITTABSPTS(b2056_inittab_rev7) },
+static const struct b2056_inittab_entry b2056_inittab_radio_rev11_tx[] = {
+       [B2056_TX_PA_SPARE2]            = { .ghz5 = 0x00ee, .ghz2 = 0x00ee, UPLOAD, },
+       [B2056_TX_INTPAA_IAUX_STAT]     = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+       [B2056_TX_INTPAA_IMAIN_STAT]    = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+       [B2056_TX_INTPAA_PASLOPE]       = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+       [B2056_TX_INTPAG_PASLOPE]       = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+       [B2056_TX_PADA_IDAC]            = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+       [B2056_TX_PADA_SLOPE]           = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+       [B2056_TX_PADG_SLOPE]           = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+       [B2056_TX_PGAA_IDAC]            = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+       [B2056_TX_PGAA_SLOPE]           = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+       [B2056_TX_PGAG_SLOPE]           = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+       [B2056_TX_GMBB_IDAC]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+       [B2056_TX_TXSPARE1]             = { .ghz5 = 0x0030, .ghz2 = 0x0030, UPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_radio_rev11_rx[] = {
+       [B2056_RX_BIASPOLE_LNAA1_IDAC]  = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+       [B2056_RX_LNAA2_IDAC]           = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+       [B2056_RX_BIASPOLE_LNAG1_IDAC]  = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+       [B2056_RX_LNAG2_IDAC]           = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+       [B2056_RX_MIXA_VCM]             = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+       [B2056_RX_MIXA_LOB_BIAS]        = { .ghz5 = 0x0088, .ghz2 = 0x0088, UPLOAD, },
+       [B2056_RX_MIXA_BIAS_AUX]        = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+       [B2056_RX_MIXG_VCM]             = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+       [B2056_RX_TIA_IOPAMP]           = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+       [B2056_RX_TIA_QOPAMP]           = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+       [B2056_RX_TIA_IMISC]            = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+       [B2056_RX_TIA_QMISC]            = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+       [B2056_RX_RXLPF_OUTVCM]         = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+       [B2056_RX_VGA_BIAS_DCCANCEL]    = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+       [B2056_RX_RXSPARE3]             = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
 };
 
+#define INITTABSPTS(prefix) \
+       static const struct b2056_inittabs_pts prefix = {       \
+               .syn            = prefix##_syn,                 \
+               .syn_length     = ARRAY_SIZE(prefix##_syn),     \
+               .tx             = prefix##_tx,                  \
+               .tx_length      = ARRAY_SIZE(prefix##_tx),      \
+               .rx             = prefix##_rx,                  \
+               .rx_length      = ARRAY_SIZE(prefix##_rx),      \
+       }
+
+INITTABSPTS(b2056_inittab_phy_rev3);
+INITTABSPTS(b2056_inittab_phy_rev4);
+INITTABSPTS(b2056_inittab_radio_rev5);
+INITTABSPTS(b2056_inittab_radio_rev6);
+INITTABSPTS(b2056_inittab_radio_rev7_9);
+INITTABSPTS(b2056_inittab_radio_rev8);
+INITTABSPTS(b2056_inittab_radio_rev11);
+
 #define RADIOREGS3(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
                   r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
                   r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, \
@@ -3041,7 +3086,7 @@ static const struct b2056_inittabs_pts b2056_inittabs[] = {
        .phy_regs.phy_bw6       = r5
 
 /* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */
-static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = {
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_phy_rev3[] = {
   {    .freq                   = 4920,
        RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
                   0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
@@ -4036,7 +4081,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] =
   },
 };
 
-static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev4[] = {
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_phy_rev4[] = {
   {    .freq                   = 4920,
        RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
                   0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
@@ -5031,7 +5076,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev4[] =
   },
 };
 
-static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev5[] = {
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev5[] = {
   {    .freq                   = 4920,
        RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
                   0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
@@ -6026,7 +6071,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev5[] =
   },
 };
 
-static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev6[] = {
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev6[] = {
   {    .freq                   = 4920,
        RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
                   0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
@@ -7021,7 +7066,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev6[] =
   },
 };
 
-static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev7_9[] = {
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev7_9[] = {
   {    .freq                   = 4920,
        RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
                   0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
@@ -8016,7 +8061,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev7_9[]
   },
 };
 
-static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev8[] = {
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev8[] = {
   {    .freq                   = 4920,
        RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
                   0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
@@ -9011,6 +9056,236 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev8[] =
   },
 };
 
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev11[] = {
+       {
+               .freq                   = 5180,
+               RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x02,
+                          0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+                          0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e,
+                          0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77,
+                          0x00, 0x0e, 0x00, 0x6f, 0x00),
+               PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+       },
+       {
+               .freq                   = 5200,
+               RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x02,
+                          0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+                          0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+                          0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77,
+                          0x00, 0x0d, 0x00, 0x6f, 0x00),
+               PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+       },
+       {
+               .freq                   = 5220,
+               RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x02,
+                          0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+                          0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+                          0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77,
+                          0x00, 0x0d, 0x00, 0x6f, 0x00),
+               PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+       },
+       {
+               .freq                   = 5745,
+               RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x05, 0x05, 0x02,
+                          0x15, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+                          0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+                          0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+                          0x00, 0x06, 0x00, 0x6d, 0x00),
+               PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+       },
+       {
+               .freq                   = 5765,
+               RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x05, 0x05, 0x02,
+                          0x15, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+                          0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+                          0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+                          0x00, 0x05, 0x00, 0x6c, 0x00),
+               PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+       },
+       {
+               .freq                   = 5785,
+               RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x05, 0x05, 0x02,
+                          0x15, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+                          0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+                          0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+                          0x00, 0x05, 0x00, 0x6b, 0x00),
+               PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+       },
+       {
+               .freq                   = 5805,
+               RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x05, 0x05, 0x02,
+                          0x15, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+                          0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+                          0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+                          0x00, 0x05, 0x00, 0x6a, 0x00),
+               PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+       },
+       {
+               .freq                   = 5825,
+               RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x05, 0x05, 0x02,
+                          0x15, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+                          0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+                          0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+                          0x00, 0x05, 0x00, 0x69, 0x00),
+               PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+       },
+       {
+               .freq                   = 2412,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+                          0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+                          0x70, 0x00, 0x0b, 0x00, 0x0a),
+               PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+       },
+       {
+               .freq                   = 2417,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+                          0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+                          0x70, 0x00, 0x0b, 0x00, 0x0a),
+               PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+       },
+       {
+               .freq                   = 2422,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00,
+                          0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+                          0x70, 0x00, 0x0b, 0x00, 0x0a),
+               PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+       },
+       {
+               .freq                   = 2427,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x0a),
+               PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+       },
+       {
+               .freq                   = 2432,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x0a),
+               PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+       },
+       {
+               .freq                   = 2437,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x0a),
+               PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+       },
+       {
+               .freq                   = 2442,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x0a),
+               PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+       },
+       {
+               .freq                   = 2447,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x09),
+               PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+       },
+       {
+               .freq                   = 2452,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x09),
+               PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+       },
+       {
+               .freq                   = 2457,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x0a, 0x00, 0x09),
+               PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+       },
+       {
+               .freq                   = 2462,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x09, 0x00, 0x09),
+               PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+       },
+       {
+               .freq                   = 2467,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x09, 0x00, 0x09),
+               PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+       },
+       {
+               .freq                   = 2472,
+               RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+                          0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x09, 0x00, 0x09),
+               PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+       },
+       {
+               .freq                   = 2484,
+               RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x06, 0x06, 0x04,
+                          0x2b, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00,
+                          0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+                          0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00,
+                          0x70, 0x00, 0x09, 0x00, 0x09),
+               PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+       },
+};
+
+static const struct b2056_inittabs_pts
+*b43_nphy_get_inittabs_rev3(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+
+       switch (dev->phy.rev) {
+       case 3:
+               return &b2056_inittab_phy_rev3;
+       case 4:
+               return &b2056_inittab_phy_rev4;
+       default:
+               switch (phy->radio_rev) {
+               case 5:
+                       return &b2056_inittab_radio_rev5;
+               case 6:
+                       return &b2056_inittab_radio_rev6;
+               case 7:
+               case 9:
+                       return &b2056_inittab_radio_rev7_9;
+               case 8:
+                       return &b2056_inittab_radio_rev8;
+               case 11:
+                       return &b2056_inittab_radio_rev11;
+               }
+       }
+
+       return NULL;
+}
+
 static void b2056_upload_inittab(struct b43_wldev *dev, bool ghz5,
                                 bool ignore_uploadflag, u16 routing,
                                 const struct b2056_inittab_entry *e,
@@ -9037,11 +9312,11 @@ void b2056_upload_inittabs(struct b43_wldev *dev,
 {
        const struct b2056_inittabs_pts *pts;
 
-       if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
+       pts = b43_nphy_get_inittabs_rev3(dev);
+       if (!pts) {
                B43_WARN_ON(1);
                return;
        }
-       pts = &b2056_inittabs[dev->phy.rev];
 
        b2056_upload_inittab(dev, ghz5, ignore_uploadflag,
                                B2056_SYN, pts->syn, pts->syn_length);
@@ -9060,11 +9335,12 @@ void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5)
        const struct b2056_inittabs_pts *pts;
        const struct b2056_inittab_entry *e;
 
-       if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
+       pts = b43_nphy_get_inittabs_rev3(dev);
+       if (!pts) {
                B43_WARN_ON(1);
                return;
        }
-       pts = &b2056_inittabs[dev->phy.rev];
+
        e = &pts->syn[B2056_SYN_PLL_CP2];
 
        b43_radio_write(dev, B2056_SYN_PLL_CP2, ghz5 ? e->ghz5 : e->ghz2);
@@ -9073,38 +9349,46 @@ void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5)
 const struct b43_nphy_channeltab_entry_rev3 *
 b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq)
 {
+       struct b43_phy *phy = &dev->phy;
        const struct b43_nphy_channeltab_entry_rev3 *e;
        unsigned int length, i;
 
-       switch (dev->phy.rev) {
+       switch (phy->rev) {
        case 3:
-               e = b43_nphy_channeltab_rev3;
-               length = ARRAY_SIZE(b43_nphy_channeltab_rev3);
+               e = b43_nphy_channeltab_phy_rev3;
+               length = ARRAY_SIZE(b43_nphy_channeltab_phy_rev3);
                break;
        case 4:
-               e = b43_nphy_channeltab_rev4;
-               length = ARRAY_SIZE(b43_nphy_channeltab_rev4);
-               break;
-       case 5:
-               e = b43_nphy_channeltab_rev5;
-               length = ARRAY_SIZE(b43_nphy_channeltab_rev5);
-               break;
-       case 6:
-               e = b43_nphy_channeltab_rev6;
-               length = ARRAY_SIZE(b43_nphy_channeltab_rev6);
-               break;
-       case 7:
-       case 9:
-               e = b43_nphy_channeltab_rev7_9;
-               length = ARRAY_SIZE(b43_nphy_channeltab_rev7_9);
-               break;
-       case 8:
-               e = b43_nphy_channeltab_rev8;
-               length = ARRAY_SIZE(b43_nphy_channeltab_rev8);
+               e = b43_nphy_channeltab_phy_rev4;
+               length = ARRAY_SIZE(b43_nphy_channeltab_phy_rev4);
                break;
        default:
-               B43_WARN_ON(1);
-               return NULL;
+               switch (phy->radio_rev) {
+               case 5:
+                       e = b43_nphy_channeltab_radio_rev5;
+                       length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev5);
+                       break;
+               case 6:
+                       e = b43_nphy_channeltab_radio_rev6;
+                       length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev6);
+                       break;
+               case 7:
+               case 9:
+                       e = b43_nphy_channeltab_radio_rev7_9;
+                       length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev7_9);
+                       break;
+               case 8:
+                       e = b43_nphy_channeltab_radio_rev8;
+                       length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev8);
+                       break;
+               case 11:
+                       e = b43_nphy_channeltab_radio_rev11;
+                       length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev11);
+                       break;
+               default:
+                       B43_WARN_ON(1);
+                       return NULL;
+               }
        }
 
        for (i = 0; i < length; i++, e++) {
index 94c755fdda14749eaa36716032283b8cb9fea7d2..50d03ffeac8c57337b090f467899648d5be2f607 100644 (file)
@@ -1627,74 +1627,7 @@ static const u32 b43_ntab_tdtrn_r3[] = {
        0xfa58fc00, 0x0b64fc7e, 0x0800f7b6, 0x00f006be,
 };
 
-static const u32 b43_ntab_noisevar0_r3[] = {
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-       0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
-};
-
-static const u32 b43_ntab_noisevar1_r3[] = {
+static const u32 b43_ntab_noisevar_r3[] = {
        0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
        0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
        0x02110211, 0x0000014d, 0x02110211, 0x0000014d,
@@ -3114,8 +3047,7 @@ static void b43_nphy_tables_init_rev3(struct b43_wldev *dev)
        ntab_upload(dev, B43_NTAB_TMAP_R3, b43_ntab_tmap_r3);
        ntab_upload(dev, B43_NTAB_INTLEVEL_R3, b43_ntab_intlevel_r3);
        ntab_upload(dev, B43_NTAB_TDTRN_R3, b43_ntab_tdtrn_r3);
-       ntab_upload(dev, B43_NTAB_NOISEVAR0_R3, b43_ntab_noisevar0_r3);
-       ntab_upload(dev, B43_NTAB_NOISEVAR1_R3, b43_ntab_noisevar1_r3);
+       ntab_upload(dev, B43_NTAB_NOISEVAR_R3, b43_ntab_noisevar_r3);
        ntab_upload(dev, B43_NTAB_MCS_R3, b43_ntab_mcs_r3);
        ntab_upload(dev, B43_NTAB_TDI20A0_R3, b43_ntab_tdi20a0_r3);
        ntab_upload(dev, B43_NTAB_TDI20A1_R3, b43_ntab_tdi20a1_r3);
index 9ff33adcff891cad9551bafab507924a59a54afb..3a58aee4c4cf714aa72bc22a8c85670b135eb934 100644 (file)
@@ -143,8 +143,7 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
 #define B43_NTAB_TMAP_R3               B43_NTAB32(12,   0) /* TM AP  */
 #define B43_NTAB_INTLEVEL_R3           B43_NTAB32(13,   0) /* INT LV  */
 #define B43_NTAB_TDTRN_R3              B43_NTAB32(14,   0) /* TD TRN  */
-#define B43_NTAB_NOISEVAR0_R3          B43_NTAB32(16,   0) /* noise variance 0  */
-#define B43_NTAB_NOISEVAR1_R3          B43_NTAB32(16, 128) /* noise variance 1  */
+#define B43_NTAB_NOISEVAR_R3           B43_NTAB32(16,   0) /* noise variance */
 #define B43_NTAB_MCS_R3                        B43_NTAB16(18,   0) /* MCS  */
 #define B43_NTAB_TDI20A0_R3            B43_NTAB32(19, 128) /* TDI 20/0  */
 #define B43_NTAB_TDI20A1_R3            B43_NTAB32(19, 256) /* TDI 20/1  */
index 9b1a038be08b860da91461b82c6bd84dd5000531..c218c08fb2f5b15ad3233b475b5d275d2f4ba0df 100644 (file)
@@ -441,7 +441,7 @@ static void b43_wa_altagc(struct b43_wldev *dev)
 
 static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */
 {
-       b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480);
+       b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0x7654);
 }
 
 static void b43_wa_cpll_nonpilot(struct b43_wldev *dev)
index df130ef53d1c4054f59f2fe10d197a80673000c9..c7c9f15c0fe08170ee2f953e9690a13e605a3291 100644 (file)
@@ -303,10 +303,10 @@ static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core,
 
        ci = core->chip;
 
-       /* if core is already in reset, just return */
+       /* if core is already in reset, skip reset */
        regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL);
        if ((regdata & BCMA_RESET_CTL_RESET) != 0)
-               return;
+               goto in_reset_configure;
 
        /* configure reset */
        ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
@@ -322,6 +322,7 @@ static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core,
        SPINWAIT(ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) !=
                 BCMA_RESET_CTL_RESET, 300);
 
+in_reset_configure:
        /* in-reset configure */
        ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
                         reset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
index 8c5fa4e581392d73d28ba29b790151be8f37f569..43c71bfaa4744fe4094069b28ff4d9084d6c679f 100644 (file)
@@ -897,7 +897,8 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
        return result;
 }
 
-static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                           u32 queues, bool drop)
 {
        struct brcms_info *wl = hw->priv;
        int ret;
index 103f7bce893208c30eb692cca9aa9adf51b8d8b9..cd0cad7f775993661af9e8f4577c89976b15b811 100644 (file)
@@ -936,7 +936,8 @@ static int __cw1200_flush(struct cw1200_common *priv, bool drop)
        return ret;
 }
 
-void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                 u32 queues, bool drop)
 {
        struct cw1200_common *priv = hw->priv;
 
index 35babb62cc6a8b5a952f0a989c15ad4edf802f17..b7e386b7662b668b8299a9ab52f3c22f2633dfe5 100644 (file)
@@ -40,7 +40,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
 
 int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
 
-void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
+void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                 u32 queues, bool drop);
 
 u64 cw1200_prepare_multicast(struct ieee80211_hw *hw,
                             struct netdev_hw_addr_list *mc_list);
index d37a6fd90d400a6dfd90d20cdf02d73e7e536d42..b598e2803500ec7b109111f5118dde1414547a22 100644 (file)
@@ -573,7 +573,7 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
                rx_status.flag |= RX_FLAG_SHORTPRE;
 
        if ((unlikely(rx_stats->phy_count > 20))) {
-               D_DROP("dsp size out of range [0,20]: %d/n",
+               D_DROP("dsp size out of range [0,20]: %d\n",
                       rx_stats->phy_count);
                return;
        }
index 888ad5c74639e351a3727c8b934a68f7969849e5..c159c05db6ef212b8b684c5726e61a8a97c62c39 100644 (file)
@@ -670,7 +670,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
        }
 
        if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
-               D_DROP("dsp size out of range [0,20]: %d/n",
+               D_DROP("dsp size out of range [0,20]: %d\n",
                       phy_res->cfg_phy_cnt);
                return;
        }
index 4f42174d999412102e273744fc39ff692b9a9234..ecc674627e6e10b30a5a7b11ab3150c1ad42b37e 100644 (file)
@@ -4755,7 +4755,8 @@ out:
 }
 EXPORT_SYMBOL(il_mac_change_interface);
 
-void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                 u32 queues, bool drop)
 {
        struct il_priv *il = hw->priv;
        unsigned long timeout = jiffies + msecs_to_jiffies(500);
index dfb13c70efe83ea8415f93ef2dad9c97a0cb6891..ea5c0f863c4ee35b2cf6738569a5cb3253553c12 100644 (file)
@@ -1723,7 +1723,8 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif);
 int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            enum nl80211_iftype newtype, bool newp2p);
-void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
+void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                 u32 queues, bool drop);
 int il_alloc_txq_mem(struct il_priv *il);
 void il_free_txq_mem(struct il_priv *il);
 
index 576f7ee38ca5894150cba0e54eff4bcc5ff2f079..d169228f59e7006528df76a96d300010f8e44a4b 100644 (file)
@@ -180,7 +180,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv)
                goto done;
        }
        IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans);
+       iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
 done:
        ieee80211_wake_queues(priv->hw);
        mutex_unlock(&priv->mutex);
index dd55c9cf7ba80376ef3ae507b434e79d6dd1cca4..29af7b51e3708788d02f4a1651205a348a5102dd 100644 (file)
@@ -1091,7 +1091,8 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                            u32 queues, bool drop)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
@@ -1119,7 +1120,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
                }
        }
        IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans);
+       iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
 done:
        mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
index 6a6df71af1d7ba6e4b4dfec16a2042c6cc357de4..6a00353768f328b1931d54a51eef8c7eb8bbc248 100644 (file)
@@ -2053,6 +2053,17 @@ static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
        return false;
 }
 
+static void iwl_napi_add(struct iwl_op_mode *op_mode,
+                        struct napi_struct *napi,
+                        struct net_device *napi_dev,
+                        int (*poll)(struct napi_struct *, int),
+                        int weight)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       ieee80211_napi_add(priv->hw, napi, napi_dev, poll, weight);
+}
+
 static const struct iwl_op_mode_ops iwl_dvm_ops = {
        .start = iwl_op_mode_dvm_start,
        .stop = iwl_op_mode_dvm_stop,
@@ -2065,6 +2076,7 @@ static const struct iwl_op_mode_ops iwl_dvm_ops = {
        .cmd_queue_full = iwl_cmd_queue_full,
        .nic_config = iwl_nic_config,
        .wimax_active = iwl_wimax_active,
+       .napi_add = iwl_napi_add,
 };
 
 /*****************************************************************************
index 854ba84ccb730995f0d786d26a85a1c2fc14c0dc..c3817fae16c04207136e5d45e8cc65bd3a125429 100644 (file)
@@ -62,6 +62,7 @@ static const struct iwl_base_params iwl1000_base_params = {
        .led_compensation = 51,
        .wd_timeout = IWL_WATCHDOG_DISABLED,
        .max_event_log_size = 128,
+       .scd_chain_ext_wa = true,
 };
 
 static const struct iwl_ht_params iwl1000_ht_params = {
index 3e63323637f3f593dd895528dac4e5fb794fdb4c..21e5d0843a62a84a0f21ff337d1b674750fa3999 100644 (file)
@@ -75,6 +75,7 @@ static const struct iwl_base_params iwl2000_base_params = {
        .wd_timeout = IWL_DEF_WD_TIMEOUT,
        .max_event_log_size = 512,
        .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .scd_chain_ext_wa = true,
 };
 
 
@@ -88,6 +89,7 @@ static const struct iwl_base_params iwl2030_base_params = {
        .wd_timeout = IWL_LONG_WD_TIMEOUT,
        .max_event_log_size = 512,
        .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .scd_chain_ext_wa = true,
 };
 
 static const struct iwl_ht_params iwl2000_ht_params = {
index 6674f2c4541c183fbae6c2a1bb0861d9eb3a966f..332bbede39e5b0fc6bb25b7ab30bbbd22c929b8b 100644 (file)
@@ -61,6 +61,7 @@ static const struct iwl_base_params iwl5000_base_params = {
        .led_compensation = 51,
        .wd_timeout = IWL_WATCHDOG_DISABLED,
        .max_event_log_size = 512,
+       .scd_chain_ext_wa = true,
 };
 
 static const struct iwl_ht_params iwl5000_ht_params = {
index 8048de90233fa038545e9d752eaaffbfc3968c72..8f2c3c8c6b843f78f346225d371ee3ad3df54f23 100644 (file)
@@ -85,6 +85,7 @@ static const struct iwl_base_params iwl6000_base_params = {
        .wd_timeout = IWL_DEF_WD_TIMEOUT,
        .max_event_log_size = 512,
        .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .scd_chain_ext_wa = true,
 };
 
 static const struct iwl_base_params iwl6050_base_params = {
@@ -97,6 +98,7 @@ static const struct iwl_base_params iwl6050_base_params = {
        .wd_timeout = IWL_DEF_WD_TIMEOUT,
        .max_event_log_size = 1024,
        .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .scd_chain_ext_wa = true,
 };
 
 static const struct iwl_base_params iwl6000_g2_base_params = {
@@ -109,6 +111,7 @@ static const struct iwl_base_params iwl6000_g2_base_params = {
        .wd_timeout = IWL_LONG_WD_TIMEOUT,
        .max_event_log_size = 512,
        .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .scd_chain_ext_wa = true,
 };
 
 static const struct iwl_ht_params iwl6000_ht_params = {
index 4c2d4ef28b220c719ac49f9f9726b931c2d35442..f73de239cdc112d09f0f65097063a59bd9378bca 100644 (file)
 #define IWL3160_UCODE_API_MAX  9
 
 /* Oldest version we won't warn about */
-#define IWL7260_UCODE_API_OK   8
-#define IWL3160_UCODE_API_OK   8
+#define IWL7260_UCODE_API_OK   9
+#define IWL3160_UCODE_API_OK   9
 
 /* Lowest firmware API version supported */
-#define IWL7260_UCODE_API_MIN  7
-#define IWL3160_UCODE_API_MIN  7
+#define IWL7260_UCODE_API_MIN  8
+#define IWL3160_UCODE_API_MIN  8
 
 /* NVM versions */
 #define IWL7260_NVM_VERSION            0x0a1d
@@ -107,6 +107,7 @@ static const struct iwl_base_params iwl7000_base_params = {
        .max_event_log_size = 512,
        .shadow_reg_enable = true,
        .pcie_l1_allowed = true,
+       .apmg_wake_up_wa = true,
 };
 
 static const struct iwl_ht_params iwl7000_ht_params = {
index 3f17dc3f2c8a9fdde83bddb254efb8cc8d33502f..7ce82d9c72226d7ee2e76a3d9a3f0426df1cbf25 100644 (file)
@@ -146,6 +146,9 @@ static inline u8 num_of_ant(u8 mask)
  * @wd_timeout: TX queues watchdog timeout
  * @max_event_log_size: size of event log buffer size for ucode event logging
  * @shadow_reg_enable: HW shadow register support
+ * @apmg_wake_up_wa: should the MAC access REQ be asserted when a command
+ *     is in flight. This is due to a HW bug in 7260, 3160 and 7265.
+ * @scd_chain_ext_wa: should the chain extension feature in SCD be disabled.
  */
 struct iwl_base_params {
        int eeprom_size;
@@ -160,6 +163,8 @@ struct iwl_base_params {
        u32 max_event_log_size;
        const bool shadow_reg_enable;
        const bool pcie_l1_allowed;
+       const bool apmg_wake_up_wa;
+       const bool scd_chain_ext_wa;
 };
 
 /*
index d14f19339d6140607c99d1b6660b039f9ac4aa66..f5927d0cf9b66dca59c13ede6e3a6627a368fecf 100644 (file)
  * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
  * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan
  *     offload profile config command.
- * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
- * @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API.
  * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six
  *     (rather than two) IPv6 addresses
- * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
  * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
  *     from the probe request template.
- * @IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping
- *     connection when going back to D0
  * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version)
  * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
- * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
- * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
- * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
- *     containing CAM (Continuous Active Mode) indication.
+ * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC
  * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and
  *     P2P client interfaces simultaneously if they are in different bindings.
+ * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and
+ *     P2P client interfaces simultaneously if they are in same bindings.
  * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
  * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
  * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
+ * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS.
  */
 enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_PAN                 = BIT(0),
@@ -104,22 +99,15 @@ enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_MFP                 = BIT(2),
        IWL_UCODE_TLV_FLAGS_P2P                 = BIT(3),
        IWL_UCODE_TLV_FLAGS_DW_BC_TABLE         = BIT(4),
-       IWL_UCODE_TLV_FLAGS_NEWBT_COEX          = BIT(5),
-       IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT      = BIT(6),
        IWL_UCODE_TLV_FLAGS_SHORT_BL            = BIT(7),
-       IWL_UCODE_TLV_FLAGS_RX_ENERGY_API       = BIT(8),
-       IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2   = BIT(9),
        IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS     = BIT(10),
-       IWL_UCODE_TLV_FLAGS_BF_UPDATED          = BIT(11),
        IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID       = BIT(12),
-       IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API   = BIT(14),
        IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL    = BIT(15),
        IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE    = BIT(16),
-       IWL_UCODE_TLV_FLAGS_SCHED_SCAN          = BIT(17),
-       IWL_UCODE_TLV_FLAGS_STA_KEY_CMD         = BIT(19),
-       IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD       = BIT(20),
+       IWL_UCODE_TLV_FLAGS_P2P_PM              = BIT(21),
        IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM      = BIT(22),
-       IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT       = BIT(24),
+       IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM      = BIT(23),
+       IWL_UCODE_TLV_FLAGS_EBS_SUPPORT         = BIT(25),
        IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD        = BIT(26),
        IWL_UCODE_TLV_FLAGS_BCAST_FILTERING     = BIT(29),
        IWL_UCODE_TLV_FLAGS_GO_UAPSD            = BIT(30),
@@ -183,6 +171,7 @@ enum iwl_ucode_sec {
 #define IWL_UCODE_SECTION_MAX 12
 #define IWL_API_ARRAY_SIZE     1
 #define IWL_CAPABILITIES_ARRAY_SIZE    1
+#define CPU1_CPU2_SEPARATOR_SECTION    0xFFFFCCCC
 
 struct iwl_ucode_capabilities {
        u32 max_probe_length;
index 6be30c69850619f81c2468febb3634fd5cf390fd..4049c0d626ba5dfb2f6be5754b27074175730dbc 100644 (file)
@@ -134,12 +134,13 @@ static const u8 iwl_nvm_channels_family_8000[] = {
        149, 153, 157, 161, 165, 169, 173, 177, 181
 };
 
-#define IWL_NUM_CHANNELS       ARRAY_SIZE(iwl_nvm_channels)
+#define IWL_NUM_CHANNELS               ARRAY_SIZE(iwl_nvm_channels)
 #define IWL_NUM_CHANNELS_FAMILY_8000   ARRAY_SIZE(iwl_nvm_channels_family_8000)
-#define NUM_2GHZ_CHANNELS      14
-#define FIRST_2GHZ_HT_MINUS    5
-#define LAST_2GHZ_HT_PLUS      9
-#define LAST_5GHZ_HT           161
+#define NUM_2GHZ_CHANNELS              14
+#define NUM_2GHZ_CHANNELS_FAMILY_8000  13
+#define FIRST_2GHZ_HT_MINUS            5
+#define LAST_2GHZ_HT_PLUS              9
+#define LAST_5GHZ_HT                   161
 
 #define DEFAULT_MAX_TX_POWER 16
 
@@ -202,21 +203,23 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
        struct ieee80211_channel *channel;
        u16 ch_flags;
        bool is_5ghz;
-       int num_of_ch;
+       int num_of_ch, num_2ghz_channels;
        const u8 *nvm_chan;
 
        if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
                num_of_ch = IWL_NUM_CHANNELS;
                nvm_chan = &iwl_nvm_channels[0];
+               num_2ghz_channels = NUM_2GHZ_CHANNELS;
        } else {
                num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
                nvm_chan = &iwl_nvm_channels_family_8000[0];
+               num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000;
        }
 
        for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
                ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
-               if (ch_idx >= NUM_2GHZ_CHANNELS &&
+               if (ch_idx >= num_2ghz_channels &&
                    !data->sku_cap_band_52GHz_enable)
                        ch_flags &= ~NVM_CHANNEL_VALID;
 
@@ -225,7 +228,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                                         "Ch. %d Flags %x [%sGHz] - No traffic\n",
                                         nvm_chan[ch_idx],
                                         ch_flags,
-                                        (ch_idx >= NUM_2GHZ_CHANNELS) ?
+                                        (ch_idx >= num_2ghz_channels) ?
                                         "5.2" : "2.4");
                        continue;
                }
@@ -234,7 +237,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                n_channels++;
 
                channel->hw_value = nvm_chan[ch_idx];
-               channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
+               channel->band = (ch_idx < num_2ghz_channels) ?
                                IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
                channel->center_freq =
                        ieee80211_channel_to_frequency(
@@ -242,7 +245,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 
                /* TODO: Need to be dependent to the NVM */
                channel->flags = IEEE80211_CHAN_NO_HT40;
-               if (ch_idx < NUM_2GHZ_CHANNELS &&
+               if (ch_idx < num_2ghz_channels &&
                    (ch_flags & NVM_CHANNEL_40MHZ)) {
                        if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
@@ -250,7 +253,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
                } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
                           (ch_flags & NVM_CHANNEL_40MHZ)) {
-                       if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
+                       if ((ch_idx - num_2ghz_channels) % 2 == 0)
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
                        else
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
index ea29504ac61704c39c24a117dec0a5d92aa58376..99785c892f963c7435b0048c4a097f6cae9e7808 100644 (file)
@@ -63,6 +63,7 @@
 #ifndef __iwl_op_mode_h__
 #define __iwl_op_mode_h__
 
+#include <linux/netdevice.h>
 #include <linux/debugfs.h>
 
 struct iwl_op_mode;
@@ -112,8 +113,11 @@ struct iwl_cfg;
  * @stop: stop the op_mode. Must free all the memory allocated.
  *     May sleep
  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
- *     HCMD this Rx responds to.
- *     This callback may sleep, it is called from a threaded IRQ handler.
+ *     HCMD this Rx responds to. Can't sleep.
+ * @napi_add: NAPI initialisation. The transport is fully responsible for NAPI,
+ *     but the higher layers need to know about it (in particular mac80211 to
+ *     to able to call the right NAPI RX functions); this function is needed
+ *     to eventually call netif_napi_add() with higher layer involvement.
  * @queue_full: notifies that a HW queue is full.
  *     Must be atomic and called with BH disabled.
  * @queue_not_full: notifies that a HW queue is not full any more.
@@ -143,6 +147,11 @@ struct iwl_op_mode_ops {
        void (*stop)(struct iwl_op_mode *op_mode);
        int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
                  struct iwl_device_cmd *cmd);
+       void (*napi_add)(struct iwl_op_mode *op_mode,
+                        struct napi_struct *napi,
+                        struct net_device *napi_dev,
+                        int (*poll)(struct napi_struct *, int),
+                        int weight);
        void (*queue_full)(struct iwl_op_mode *op_mode, int queue);
        void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue);
        bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
@@ -180,7 +189,6 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode,
                                  struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd)
 {
-       might_sleep();
        return op_mode->ops->rx(op_mode, rxb, cmd);
 }
 
@@ -249,4 +257,15 @@ static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode)
        return op_mode->ops->exit_d0i3(op_mode);
 }
 
+static inline void iwl_op_mode_napi_add(struct iwl_op_mode *op_mode,
+                                       struct napi_struct *napi,
+                                       struct net_device *napi_dev,
+                                       int (*poll)(struct napi_struct *, int),
+                                       int weight)
+{
+       if (!op_mode->ops->napi_add)
+               return;
+       op_mode->ops->napi_add(op_mode, napi, napi_dev, poll, weight);
+}
+
 #endif /* __iwl_op_mode_h__ */
index 5f657c501406cc995f7f8c065f26d9983ba43ffe..779311080a9ef8c0a18dd2a305121fa4d058a128 100644 (file)
@@ -348,4 +348,12 @@ enum secure_load_status_reg {
 
 #define LMPM_SECURE_TIME_OUT   (100)
 
+/* Rx FIFO */
+#define RXF_SIZE_ADDR                  (0xa00c88)
+#define RXF_SIZE_BYTE_CND_POS          (7)
+#define RXF_SIZE_BYTE_CNT_MSK          (0x3ff << RXF_SIZE_BYTE_CND_POS)
+
+#define RXF_LD_FENCE_OFFSET_ADDR       (0xa00c10)
+#define RXF_FIFO_RD_FENCE_ADDR         (0xa00c0c)
+
 #endif                         /* __iwl_prph_h__ */
index 8cdb0dd618a6fdfcc8d57095e41974e6e22984ab..22fd94ec804882651625ab9506840a66029006ff 100644 (file)
@@ -437,8 +437,7 @@ struct iwl_trans;
  *     this one. The op_mode must not configure the HCMD queue. May sleep.
  * @txq_disable: de-configure a Tx queue to send AMPDUs
  *     Must be atomic
- * @wait_tx_queue_empty: wait until all tx queues are empty
- *     May sleep
+ * @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
  * @dbgfs_register: add the dbgfs files under this directory. Files will be
  *     automatically deleted.
  * @write8: write a u8 to a register at offset ofs from the BAR
@@ -490,7 +489,7 @@ struct iwl_trans_ops {
        void (*txq_disable)(struct iwl_trans *trans, int queue);
 
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
-       int (*wait_tx_queue_empty)(struct iwl_trans *trans);
+       int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
 
        void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val);
        void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val);
@@ -759,12 +758,13 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
                             IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0);
 }
 
-static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
+static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
+                                               u32 txq_bm)
 {
        if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
                IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
-       return trans->ops->wait_tx_queue_empty(trans);
+       return trans->ops->wait_tx_queue_empty(trans, txq_bm);
 }
 
 static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
index fa858d548d13c0bd794b98dc4da2053893b460dc..8f4b03dbaf3f4ecae21927a0c976d2b1c3852157 100644 (file)
@@ -104,11 +104,8 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
 #define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD   (-65)
 #define BT_ANTENNA_COUPLING_THRESHOLD          (30)
 
-int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
+static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
 {
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
-               return 0;
-
        return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC,
                                    sizeof(struct iwl_bt_coex_prio_tbl_cmd),
                                    &iwl_bt_prio_tbl);
@@ -573,8 +570,9 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
        int ret;
        u32 flags;
 
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
-               return 0;
+       ret = iwl_send_bt_prio_tbl(mvm);
+       if (ret)
+               return ret;
 
        bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
        if (!bt_cmd)
@@ -582,10 +580,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
        cmd.data[0] = bt_cmd;
 
        bt_cmd->max_kill = 5;
-       bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD,
-       bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling,
-       bt_cmd->bt4_tx_tx_delta_freq_thr = 15,
-       bt_cmd->bt4_tx_rx_max_freq0 = 15,
+       bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
+       bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
+       bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
+       bt_cmd->bt4_tx_rx_max_freq0 = 15;
+       bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT;
+       bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT;
 
        flags = iwlwifi_mod_params.bt_coex_active ?
                        BT_COEX_NW : BT_COEX_DISABLE;
@@ -1215,6 +1215,17 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
        return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT;
 }
 
+bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
+                                   enum ieee80211_band band)
+{
+       u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
+
+       if (band != IEEE80211_BAND_2GHZ)
+               return false;
+
+       return bt_activity >= BT_LOW_TRAFFIC;
+}
+
 u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
                           struct ieee80211_tx_info *info, u8 ac)
 {
@@ -1249,9 +1260,6 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
 
 void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
 {
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
-               return;
-
        iwl_mvm_bt_coex_notif_handle(mvm);
 }
 
index e56f5a0edf855331a1411e76406a143176b5e9d5..7694472a303e0062b511ddb97404a11a1717c75d 100644 (file)
@@ -744,10 +744,8 @@ static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
        int err;
        u32 size;
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) {
-               cmd.data[0] = &query_cmd;
-               cmd.len[0] = sizeof(query_cmd);
-       }
+       cmd.data[0] = &query_cmd;
+       cmd.len[0] = sizeof(query_cmd);
 
        err = iwl_mvm_send_cmd(mvm, &cmd);
        if (err)
@@ -758,10 +756,8 @@ static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
                err = -EINVAL;
        } else {
                err = le16_to_cpup((__le16 *)cmd.resp_pkt->data);
-               /* new API returns next, not last-used seqno */
-               if (mvm->fw->ucode_capa.flags &
-                               IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)
-                       err = (u16) (err - 0x10);
+               /* firmware returns next, not last-used seqno */
+               err = (u16) (err - 0x10);
        }
 
        iwl_free_resp(&cmd);
@@ -785,10 +781,6 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
        mvmvif->seqno_valid = false;
 
-       if (!(mvm->fw->ucode_capa.flags &
-                       IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API))
-               return;
-
        if (iwl_mvm_send_cmd_pdu(mvm, NON_QOS_TX_COUNTER_CMD, CMD_SYNC,
                                 sizeof(query_cmd), &query_cmd))
                IWL_ERR(mvm, "failed to set non-QoS seqno\n");
@@ -1082,6 +1074,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
 int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 {
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+       if (iwl_mvm_is_d0i3_supported(mvm)) {
+               mutex_lock(&mvm->d0i3_suspend_mutex);
+               __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
+               mutex_unlock(&mvm->d0i3_suspend_mutex);
+               return 0;
+       }
+
        return __iwl_mvm_suspend(hw, wowlan, false);
 }
 
@@ -1277,7 +1278,7 @@ static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
 }
 
 static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
-                                  struct iwl_wowlan_status_v6 *status)
+                                  struct iwl_wowlan_status *status)
 {
        union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc;
 
@@ -1294,7 +1295,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
 }
 
 struct iwl_mvm_d3_gtk_iter_data {
-       struct iwl_wowlan_status_v6 *status;
+       struct iwl_wowlan_status *status;
        void *last_gtk;
        u32 cipher;
        bool find_phase, unhandled_cipher;
@@ -1370,7 +1371,7 @@ static void iwl_mvm_d3_update_gtks(struct ieee80211_hw *hw,
 
 static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
                                          struct ieee80211_vif *vif,
-                                         struct iwl_wowlan_status_v6 *status)
+                                         struct iwl_wowlan_status *status)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_d3_gtk_iter_data gtkdata = {
@@ -1468,7 +1469,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
                .flags = CMD_SYNC | CMD_WANT_SKB,
        };
        struct iwl_wowlan_status_data status;
-       struct iwl_wowlan_status_v6 *status_v6;
+       struct iwl_wowlan_status *fw_status;
        int ret, len, status_size, i;
        bool keep;
        struct ieee80211_sta *ap_sta;
@@ -1505,10 +1506,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
        if (!cmd.resp_pkt)
                goto out_unlock;
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)
-               status_size = sizeof(struct iwl_wowlan_status_v6);
-       else
-               status_size = sizeof(struct iwl_wowlan_status_v4);
+       status_size = sizeof(*fw_status);
 
        len = iwl_rx_packet_payload_len(cmd.resp_pkt);
        if (len < status_size) {
@@ -1516,35 +1514,18 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
                goto out_free_resp;
        }
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) {
-               status_v6 = (void *)cmd.resp_pkt->data;
-
-               status.pattern_number = le16_to_cpu(status_v6->pattern_number);
-               for (i = 0; i < 8; i++)
-                       status.qos_seq_ctr[i] =
-                               le16_to_cpu(status_v6->qos_seq_ctr[i]);
-               status.wakeup_reasons = le32_to_cpu(status_v6->wakeup_reasons);
-               status.wake_packet_length =
-                       le32_to_cpu(status_v6->wake_packet_length);
-               status.wake_packet_bufsize =
-                       le32_to_cpu(status_v6->wake_packet_bufsize);
-               status.wake_packet = status_v6->wake_packet;
-       } else {
-               struct iwl_wowlan_status_v4 *status_v4;
-               status_v6 = NULL;
-               status_v4 = (void *)cmd.resp_pkt->data;
-
-               status.pattern_number = le16_to_cpu(status_v4->pattern_number);
-               for (i = 0; i < 8; i++)
-                       status.qos_seq_ctr[i] =
-                               le16_to_cpu(status_v4->qos_seq_ctr[i]);
-               status.wakeup_reasons = le32_to_cpu(status_v4->wakeup_reasons);
-               status.wake_packet_length =
-                       le32_to_cpu(status_v4->wake_packet_length);
-               status.wake_packet_bufsize =
-                       le32_to_cpu(status_v4->wake_packet_bufsize);
-               status.wake_packet = status_v4->wake_packet;
-       }
+       fw_status = (void *)cmd.resp_pkt->data;
+
+       status.pattern_number = le16_to_cpu(fw_status->pattern_number);
+       for (i = 0; i < 8; i++)
+               status.qos_seq_ctr[i] =
+                       le16_to_cpu(fw_status->qos_seq_ctr[i]);
+       status.wakeup_reasons = le32_to_cpu(fw_status->wakeup_reasons);
+       status.wake_packet_length =
+               le32_to_cpu(fw_status->wake_packet_length);
+       status.wake_packet_bufsize =
+               le32_to_cpu(fw_status->wake_packet_bufsize);
+       status.wake_packet = fw_status->wake_packet;
 
        if (len != status_size + ALIGN(status.wake_packet_bufsize, 4)) {
                IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
@@ -1571,7 +1552,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
 
        iwl_mvm_report_wakeup_reasons(mvm, vif, &status);
 
-       keep = iwl_mvm_setup_connection_keep(mvm, vif, status_v6);
+       keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status);
 
        iwl_free_resp(&cmd);
        return keep;
@@ -1674,6 +1655,19 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 
+       if (iwl_mvm_is_d0i3_supported(mvm)) {
+               bool exit_now;
+
+               mutex_lock(&mvm->d0i3_suspend_mutex);
+               __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
+               exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP,
+                                               &mvm->d0i3_suspend_flags);
+               mutex_unlock(&mvm->d0i3_suspend_mutex);
+               if (exit_now)
+                       _iwl_mvm_exit_d0i3(mvm);
+               return 0;
+       }
+
        return __iwl_mvm_resume(mvm, false);
 }
 
index 9b59e1d7ae71ea888973992cb88363ba2371fdad..6047cfdafb959e99b6bb6e56d74d3164f1add1ae 100644 (file)
@@ -103,10 +103,6 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
                IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
                dbgfs_pm->tx_data_timeout = val;
                break;
-       case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
-               IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
-               dbgfs_pm->disable_power_off = val;
-               break;
        case MVM_DEBUGFS_PM_LPRX_ENA:
                IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
                dbgfs_pm->lprx_ena = val;
@@ -154,12 +150,6 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
                if (sscanf(buf + 16, "%d", &val) != 1)
                        return -EINVAL;
                param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
-       } else if (!strncmp("disable_power_off=", buf, 18) &&
-                  !(mvm->fw->ucode_capa.flags &
-                    IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) {
-               if (sscanf(buf + 18, "%d", &val) != 1)
-                       return -EINVAL;
-               param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
        } else if (!strncmp("lprx=", buf, 5)) {
                if (sscanf(buf + 5, "%d", &val) != 1)
                        return -EINVAL;
@@ -592,8 +582,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                return;
        }
 
-       if ((mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) &&
-           iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
+       if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
            ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
             (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
              mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
index 1b52deea60812e4f6ac42c94412b1ecf518f44f7..f462c9baa2b569704fdee9bbfa70e76130ad42c1 100644 (file)
@@ -136,9 +136,6 @@ static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
 
        file->private_data = mvm->fw_error_dump;
        mvm->fw_error_dump = NULL;
-       kfree(mvm->fw_error_sram);
-       mvm->fw_error_sram = NULL;
-       mvm->fw_error_sram_len = 0;
        ret = 0;
 
 out:
@@ -1004,6 +1001,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
        PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
        PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
        PRINT_MVM_REF(IWL_MVM_REF_USER);
+       PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
@@ -1108,9 +1106,9 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
 
 static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
-        .open = iwl_dbgfs_fw_error_dump_open,
-        .read = iwl_dbgfs_fw_error_dump_read,
-        .release = iwl_dbgfs_fw_error_dump_release,
+       .open = iwl_dbgfs_fw_error_dump_open,
+       .read = iwl_dbgfs_fw_error_dump_read,
+       .release = iwl_dbgfs_fw_error_dump_release,
 };
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
@@ -1138,9 +1136,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)
-               MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
-                                    S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
+                            S_IRUSR | S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
index 21877e5966a8093d6780d3297944c1a214dc55e3..5fe82c29c8ad07bcb7bab43726a4e09b136d8b53 100644 (file)
@@ -141,7 +141,8 @@ enum iwl_bt_coex_lut_type {
        BT_COEX_TX_DIS_LUT,
 
        BT_COEX_MAX_LUT,
-};
+       BT_COEX_INVALID_LUT = 0xff,
+}; /* BT_COEX_DECISION_LUT_INDEX_API_E_VER_1 */
 
 #define BT_COEX_LUT_SIZE (12)
 #define BT_COEX_CORUN_LUT_SIZE (32)
@@ -154,19 +155,23 @@ enum iwl_bt_coex_lut_type {
  * @flags:&enum iwl_bt_coex_flags
  * @max_kill:
  * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
- * @bt4_antenna_isolation:
- * @bt4_antenna_isolation_thr:
- * @bt4_tx_tx_delta_freq_thr:
- * @bt4_tx_rx_max_freq0:
- * @bt_prio_boost:
+ * @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT
+ *     should be set by default
+ * @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT
+ *     should be set by default
+ * @bt4_antenna_isolation: antenna isolation
+ * @bt4_antenna_isolation_thr: antenna threshold value
+ * @bt4_tx_tx_delta_freq_thr: TxTx delta frequency
+ * @bt4_tx_rx_max_freq0: TxRx max frequency
+ * @bt_prio_boost: BT priority boost registers
  * @wifi_tx_prio_boost: SW boost of wifi tx priority
  * @wifi_rx_prio_boost: SW boost of wifi rx priority
- * @kill_ack_msk:
- * @kill_cts_msk:
- * @decision_lut:
- * @bt4_multiprio_lut:
- * @bt4_corun_lut20:
- * @bt4_corun_lut40:
+ * @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK.
+ * @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS.
+ * @decision_lut: PTA decision LUT, per Prio-Ch
+ * @bt4_multiprio_lut: multi priority LUT configuration
+ * @bt4_corun_lut20: co-running 20 MHz LUT configuration
+ * @bt4_corun_lut40: co-running 40 MHz LUT configuration
  * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
  *
  * The structure is used for the BT_COEX command.
@@ -175,7 +180,8 @@ struct iwl_bt_coex_cmd {
        __le32 flags;
        u8 max_kill;
        u8 bt_reduced_tx_power;
-       u8 reserved[2];
+       u8 override_primary_lut;
+       u8 override_secondary_lut;
 
        u8 bt4_antenna_isolation;
        u8 bt4_antenna_isolation_thr;
@@ -194,7 +200,7 @@ struct iwl_bt_coex_cmd {
        __le32 bt4_corun_lut40[BT_COEX_CORUN_LUT_SIZE];
 
        __le32 valid_bit_msk;
-} __packed; /* BT_COEX_CMD_API_S_VER_3 */
+} __packed; /* BT_COEX_CMD_API_S_VER_5 */
 
 /**
  * struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command
@@ -282,7 +288,7 @@ enum iwl_bt_activity_grading {
        BT_ON_NO_CONNECTION     = 1,
        BT_LOW_TRAFFIC          = 2,
        BT_HIGH_TRAFFIC         = 3,
-};
+}; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */
 
 /**
  * struct iwl_bt_coex_profile_notif - notification about BT coex
@@ -310,7 +316,7 @@ struct iwl_bt_coex_profile_notif {
        __le32 primary_ch_lut;
        __le32 secondary_ch_lut;
        __le32 bt_activity_grading;
-} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */
+} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_3 */
 
 enum iwl_bt_coex_prio_table_event {
        BT_COEX_PRIO_TBL_EVT_INIT_CALIB1                = 0,
index 10fcc1a79ebddf3087d7de7c2c29389849a425fa..13696fe419b778c68c9d72d7a289a3dd3c453b39 100644 (file)
@@ -345,21 +345,6 @@ enum iwl_wowlan_wakeup_reason {
        IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET             = BIT(12),
 }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
 
-struct iwl_wowlan_status_v4 {
-       __le64 replay_ctr;
-       __le16 pattern_number;
-       __le16 non_qos_seq_ctr;
-       __le16 qos_seq_ctr[8];
-       __le32 wakeup_reasons;
-       __le32 rekey_status;
-       __le32 num_of_gtk_rekeys;
-       __le32 transmitted_ndps;
-       __le32 received_beacons;
-       __le32 wake_packet_length;
-       __le32 wake_packet_bufsize;
-       u8 wake_packet[]; /* can be truncated from _length to _bufsize */
-} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
-
 struct iwl_wowlan_gtk_status {
        u8 key_index;
        u8 reserved[3];
@@ -368,7 +353,7 @@ struct iwl_wowlan_gtk_status {
        struct iwl_wowlan_rsc_tsc_params_cmd rsc;
 } __packed;
 
-struct iwl_wowlan_status_v6 {
+struct iwl_wowlan_status {
        struct iwl_wowlan_gtk_status gtk;
        __le64 replay_ctr;
        __le16 pattern_number;
index 39148b5bb33262596e1dea348c1ae32c9a2c9166..8bb5b94bf9639689fa6445cd046f97eccbcec834 100644 (file)
@@ -334,7 +334,7 @@ enum {
  */
 struct iwl_lq_cmd {
        u8 sta_id;
-       u8 reserved1;
+       u8 reduced_tpc;
        u16 control;
        /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */
        u8 flags;
index 9426905de6b283dc0230cf51d5a694478da7797a..6174c027ff594e30c29c5c263c1efa33e6a5f5e8 100644 (file)
@@ -169,8 +169,12 @@ enum iwl_scan_type {
        SCAN_TYPE_DISCOVERY_FORCED      = 6,
 }; /* SCAN_ACTIVITY_TYPE_E_VER_1 */
 
-/* Maximal number of channels to scan */
-#define MAX_NUM_SCAN_CHANNELS 0x24
+/**
+ * Maximal number of channels to scan
+ * it should be equal to:
+ * max(IWL_NUM_CHANNELS, IWL_NUM_CHANNELS_FAMILY_8000)
+ */
+#define MAX_NUM_SCAN_CHANNELS 50
 
 /**
  * struct iwl_scan_cmd - scan request command
@@ -534,13 +538,16 @@ struct iwl_scan_offload_schedule {
  *
  * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering.
  * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
- * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan
- *     on A band.
+ * IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE: EBS duration is 100mSec - typical
+ *     beacon period. Finding channel activity in this mode is not guaranteed.
+ * IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE: EBS duration is 200mSec.
+ *     Assuming beacon period is 100ms finding channel activity is guaranteed.
  */
 enum iwl_scan_offload_flags {
        IWL_SCAN_OFFLOAD_FLAG_PASS_ALL          = BIT(0),
        IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL    = BIT(2),
-       IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN       = BIT(3),
+       IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE    = BIT(5),
+       IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE = BIT(6),
 };
 
 /**
@@ -563,17 +570,24 @@ enum iwl_scan_offload_compleate_status {
        IWL_SCAN_OFFLOAD_ABORTED        = 2,
 };
 
+enum iwl_scan_ebs_status {
+       IWL_SCAN_EBS_SUCCESS,
+       IWL_SCAN_EBS_FAILED,
+       IWL_SCAN_EBS_CHAN_NOT_FOUND,
+};
+
 /**
  * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1
  * @last_schedule_line:                last schedule line executed (fast or regular)
  * @last_schedule_iteration:   last scan iteration executed before scan abort
  * @status:                    enum iwl_scan_offload_compleate_status
+ * @ebs_status: last EBS status, see IWL_SCAN_EBS_*
  */
 struct iwl_scan_offload_complete {
        u8 last_schedule_line;
        u8 last_schedule_iteration;
        u8 status;
-       u8 reserved;
+       u8 ebs_status;
 } __packed;
 
 /**
index d636478672626e9436c12dc2313d3288d94303ed..39cebee8016feaab62f005e5e843447784594429 100644 (file)
@@ -255,22 +255,19 @@ struct iwl_mvm_keyinfo {
 } __packed;
 
 /**
- * struct iwl_mvm_add_sta_cmd_v5 - Add/modify a station in the fw's sta table.
+ * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table.
  * ( REPLY_ADD_STA = 0x18 )
  * @add_modify: 1: modify existing, 0: add new station
- * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent
- * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key
- *     sent
+ * @awake_acs:
+ * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
+ *     AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
  * @mac_id_n_color: the Mac context this station belongs to
  * @addr[ETH_ALEN]: station's MAC address
  * @sta_id: index of station in uCode's station table
  * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
  *     alone. 1 - modify, 0 - don't change.
- * @key: look at %iwl_mvm_keyinfo
  * @station_flags: look at %iwl_sta_flags
  * @station_flags_msk: what of %station_flags have changed
- * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
- *     AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
  * @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
  *     Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
  *     add_immediate_ba_ssn.
@@ -294,40 +291,7 @@ struct iwl_mvm_keyinfo {
  * ADD_STA sets up the table entry for one station, either creating a new
  * entry, or modifying a pre-existing one.
  */
-struct iwl_mvm_add_sta_cmd_v5 {
-       u8 add_modify;
-       u8 unicast_tx_key_id;
-       u8 multicast_tx_key_id;
-       u8 reserved1;
-       __le32 mac_id_n_color;
-       u8 addr[ETH_ALEN];
-       __le16 reserved2;
-       u8 sta_id;
-       u8 modify_mask;
-       __le16 reserved3;
-       struct iwl_mvm_keyinfo key;
-       __le32 station_flags;
-       __le32 station_flags_msk;
-       __le16 tid_disable_tx;
-       __le16 reserved4;
-       u8 add_immediate_ba_tid;
-       u8 remove_immediate_ba_tid;
-       __le16 add_immediate_ba_ssn;
-       __le16 sleep_tx_count;
-       __le16 sleep_state_flags;
-       __le16 assoc_id;
-       __le16 beamform_flags;
-       __le32 tfd_queue_msk;
-} __packed; /* ADD_STA_CMD_API_S_VER_5 */
-
-/**
- * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station
- * VER_7 of this command is quite similar to VER_5 except
- * exclusion of all fields related to the security key installation.
- * It only differs from VER_6 by the "awake_acs" field that is
- * reserved and ignored in VER_6.
- */
-struct iwl_mvm_add_sta_cmd_v7 {
+struct iwl_mvm_add_sta_cmd {
        u8 add_modify;
        u8 awake_acs;
        __le16 tid_disable_tx;
index 8e122f3a7a74e8a97914a13d9821a7229bc7c2bc..6cc5f52b807f1bc343ea632674e215423c3abb1d 100644 (file)
@@ -482,7 +482,8 @@ struct iwl_mvm_tx_resp {
        u8 pa_integ_res_b[3];
        u8 pa_integ_res_c[3];
        __le16 measurement_req_id;
-       __le16 reserved;
+       u8 reduced_tpc;
+       u8 reserved;
 
        __le32 tfd_info;
        __le16 seq_ctl;
index 6e75b52588de3ca68a44c41ca339df1e57eae37f..309a9b9a94fecc26918f967e7b9e7a01374d43b3 100644 (file)
@@ -71,6 +71,7 @@
 #include "fw-api-power.h"
 #include "fw-api-d3.h"
 #include "fw-api-coex.h"
+#include "fw-api-scan.h"
 
 /* maximal number of Tx queues in any platform */
 #define IWL_MVM_MAX_QUEUES     20
@@ -604,52 +605,7 @@ enum {
        TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7),
 }; /* MAC_EVENT_ACTION_API_E_VER_2 */
 
-
-/**
- * struct iwl_time_event_cmd_api_v1 - configuring Time Events
- * with struct MAC_TIME_EVENT_DATA_API_S_VER_1 (see also
- * with version 2. determined by IWL_UCODE_TLV_FLAGS)
- * ( TIME_EVENT_CMD = 0x29 )
- * @id_and_color: ID and color of the relevant MAC
- * @action: action to perform, one of FW_CTXT_ACTION_*
- * @id: this field has two meanings, depending on the action:
- *     If the action is ADD, then it means the type of event to add.
- *     For all other actions it is the unique event ID assigned when the
- *     event was added by the FW.
- * @apply_time: When to start the Time Event (in GP2)
- * @max_delay: maximum delay to event's start (apply time), in TU
- * @depends_on: the unique ID of the event we depend on (if any)
- * @interval: interval between repetitions, in TU
- * @interval_reciprocal: 2^32 / interval
- * @duration: duration of event in TU
- * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS
- * @dep_policy: one of TE_V1_INDEPENDENT, TE_V1_DEP_OTHER, TE_V1_DEP_TSF
- *     and TE_V1_EVENT_SOCIOPATHIC
- * @is_present: 0 or 1, are we present or absent during the Time Event
- * @max_frags: maximal number of fragments the Time Event can be divided to
- * @notify: notifications using TE_V1_NOTIF_* (whom to notify when)
- */
-struct iwl_time_event_cmd_v1 {
-       /* COMMON_INDEX_HDR_API_S_VER_1 */
-       __le32 id_and_color;
-       __le32 action;
-       __le32 id;
-       /* MAC_TIME_EVENT_DATA_API_S_VER_1 */
-       __le32 apply_time;
-       __le32 max_delay;
-       __le32 dep_policy;
-       __le32 depends_on;
-       __le32 is_present;
-       __le32 max_frags;
-       __le32 interval;
-       __le32 interval_reciprocal;
-       __le32 duration;
-       __le32 repeat;
-       __le32 notify;
-} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */
-
-
-/* Time event - defines for command API v2 */
+/* Time event - defines for command API */
 
 /*
  * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed.
@@ -680,7 +636,7 @@ enum {
 #define TE_V2_PLACEMENT_POS    12
 #define TE_V2_ABSENCE_POS      15
 
-/* Time event policy values (for time event cmd api v2)
+/* Time event policy values
  * A notification (both event and fragment) includes a status indicating weather
  * the FW was able to schedule the event or not. For fragment start/end
  * notification the status is always success. There is no start/end fragment
@@ -727,7 +683,7 @@ enum {
 };
 
 /**
- * struct iwl_time_event_cmd_api_v2 - configuring Time Events
+ * struct iwl_time_event_cmd_api - configuring Time Events
  * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also
  * with version 1. determined by IWL_UCODE_TLV_FLAGS)
  * ( TIME_EVENT_CMD = 0x29 )
@@ -750,7 +706,7 @@ enum {
  *     TE_EVENT_SOCIOPATHIC
  *     using TE_ABSENCE and using TE_NOTIF_*
  */
-struct iwl_time_event_cmd_v2 {
+struct iwl_time_event_cmd {
        /* COMMON_INDEX_HDR_API_S_VER_1 */
        __le32 id_and_color;
        __le32 action;
index 58c8941c0d95ef6d6e0d6bb51349663dbf3b93dd..f381908be7e56bfaa648dea3340415badd903393 100644 (file)
  * enum iwl_fw_error_dump_type - types of data in the dump file
  * @IWL_FW_ERROR_DUMP_SRAM:
  * @IWL_FW_ERROR_DUMP_REG:
+ * @IWL_FW_ERROR_DUMP_RXF:
  */
 enum iwl_fw_error_dump_type {
        IWL_FW_ERROR_DUMP_SRAM = 0,
        IWL_FW_ERROR_DUMP_REG = 1,
+       IWL_FW_ERROR_DUMP_RXF = 2,
 
        IWL_FW_ERROR_DUMP_MAX,
 };
@@ -89,7 +91,7 @@ struct iwl_fw_error_dump_data {
        __le32 type;
        __le32 len;
        __u8 data[];
-} __packed __aligned(4);
+} __packed;
 
 /**
  * struct iwl_fw_error_dump_file - the layout of the header of the file
@@ -101,6 +103,6 @@ struct iwl_fw_error_dump_file {
        __le32 barker;
        __le32 file_len;
        u8 data[0];
-} __packed __aligned(4);
+} __packed;
 
 #endif /* __fw_error_dump_h__ */
index 7ce20062f32d443be34fe87865d91afd71a0a014..3d99cf564ba6ee472eac8a3afee40f9a8e692b85 100644 (file)
@@ -288,7 +288,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
                goto error;
        }
 
-       ret = iwl_send_bt_prio_tbl(mvm);
+       ret = iwl_send_bt_init_conf(mvm);
        if (ret)
                goto error;
 
@@ -424,10 +424,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
-       ret = iwl_send_bt_prio_tbl(mvm);
-       if (ret)
-               goto error;
-
        ret = iwl_send_bt_init_conf(mvm);
        if (ret)
                goto error;
@@ -468,12 +464,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        /* Initialize tx backoffs to the minimal possible */
        iwl_mvm_tt_tx_backoff(mvm, 0);
 
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
-               ret = iwl_power_legacy_set_cam_mode(mvm);
-               if (ret)
-                       goto error;
-       }
-
        ret = iwl_mvm_power_update_device(mvm);
        if (ret)
                goto error;
index 9ccec10bba166299cc91cf1706992937127d277a..7110ec2605d667ddd4913fa89427dc05b2a083ea 100644 (file)
@@ -667,12 +667,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
        if (vif->bss_conf.qos)
                cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
 
-       /* Don't use cts to self as the fw doesn't support it currently. */
        if (vif->bss_conf.use_cts_prot) {
                cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
-               if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
-                       cmd->protection_flags |=
-                               cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN);
+               cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN);
        }
        IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n",
                       vif->bss_conf.use_cts_prot,
index f0cebf12c7b8415a3c787d0cc77a9b2b1c2a15ef..97c3deae655273ff3c5184cd86a4722f34714eae 100644 (file)
@@ -276,6 +276,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_TIMING_BEACON_ONLY |
                    IEEE80211_HW_CONNECTION_MONITOR |
+                   IEEE80211_HW_SUPPORTS_UAPSD |
                    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                    IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 
@@ -285,6 +286,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                                    IEEE80211_RADIOTAP_MCS_HAVE_STBC;
        hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
        hw->rate_control_algorithm = "iwl-mvm-rs";
+       hw->uapsd_queues = IWL_UAPSD_AC_INFO;
+       hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
 
        /*
         * Enable 11w if advertised by firmware and software crypto
@@ -295,11 +298,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
            !iwlwifi_mod_params.sw_crypto)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
-       if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) {
-               hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
-               hw->uapsd_queues = IWL_UAPSD_AC_INFO;
-               hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
-       }
+       /* Disable uAPSD due to firmware issues */
+       if (true)
+               hw->flags &= ~IEEE80211_HW_SUPPORTS_UAPSD;
 
        hw->sta_data_size = sizeof(struct iwl_mvm_sta);
        hw->vif_data_size = sizeof(struct iwl_mvm_vif);
@@ -309,11 +310,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                BIT(NL80211_IFTYPE_P2P_CLIENT) |
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_P2P_GO) |
-               BIT(NL80211_IFTYPE_P2P_DEVICE);
-
-       /* IBSS has bugs in older versions */
-       if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
-               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+               BIT(NL80211_IFTYPE_P2P_DEVICE) |
+               BIT(NL80211_IFTYPE_ADHOC);
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
        hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
@@ -365,14 +363,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        else
                hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) {
-               hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-               hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
-               hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
-               /* we create the 802.11 header and zero length SSID IE. */
-               hw->wiphy->max_sched_scan_ie_len =
-                                       SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
-       }
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+       hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
+       hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
+       /* we create the 802.11 header and zero length SSID IE. */
+       hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
 
        hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
                               NL80211_FEATURE_P2P_GO_OPPPS;
@@ -386,7 +381,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        }
 
 #ifdef CONFIG_PM_SLEEP
-       if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+       if (iwl_mvm_is_d0i3_supported(mvm) &&
+           device_can_wakeup(mvm->trans->dev)) {
+               mvm->wowlan.flags = WIPHY_WOWLAN_ANY;
+               hw->wiphy->wowlan = &mvm->wowlan;
+       } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
            mvm->trans->ops->d3_suspend &&
            mvm->trans->ops->d3_resume &&
            device_can_wakeup(mvm->trans->dev)) {
@@ -827,8 +826,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                goto out_remove_mac;
 
        if (!mvm->bf_allowed_vif &&
-           vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
-           mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){
+           vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
                mvm->bf_allowed_vif = mvmvif;
                vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
                                     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
@@ -1223,6 +1221,10 @@ static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
                return 0;
 
+       /* bcast filtering isn't supported for P2P client */
+       if (vif->p2p)
+               return 0;
+
        if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
                return 0;
 
@@ -1697,6 +1699,11 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
+               /*
+                * EBS may be disabled due to previous failures reported by FW.
+                * Reset EBS status here assuming environment has been changed.
+                */
+               mvm->last_ebs_successful = true;
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC) {
index d564233a65da6157c1aaf16a099ddf94b3be933e..17c42da5f9f272e253175e42837d665e7e1b3061 100644 (file)
@@ -164,7 +164,6 @@ enum iwl_dbgfs_pm_mask {
        MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS = BIT(2),
        MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3),
        MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4),
-       MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5),
        MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
        MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
        MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
@@ -177,7 +176,6 @@ struct iwl_dbgfs_pm {
        u32 tx_data_timeout;
        bool skip_over_dtim;
        u8 skip_dtim_periods;
-       bool disable_power_off;
        bool lprx_ena;
        u32 lprx_rssi_threshold;
        bool snooze_ena;
@@ -232,6 +230,7 @@ enum iwl_mvm_ref_type {
        IWL_MVM_REF_USER,
        IWL_MVM_REF_TX,
        IWL_MVM_REF_TX_AGG,
+       IWL_MVM_REF_EXIT_WORK,
 
        IWL_MVM_REF_COUNT,
 };
@@ -265,6 +264,7 @@ struct iwl_mvm_vif_bf_data {
  * @uploaded: indicates the MAC context has been added to the device
  * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
  *     should get quota etc.
+ * @pm_enabled - Indicate if MAC power management is allowed
  * @monitor_active: indicates that monitor context is configured, and that the
  *     interface should get quota etc.
  * @low_latency: indicates that this interface is in low-latency mode
@@ -283,6 +283,7 @@ struct iwl_mvm_vif {
 
        bool uploaded;
        bool ap_ibss_active;
+       bool pm_enabled;
        bool monitor_active;
        bool low_latency;
        struct iwl_mvm_vif_bf_data bf_data;
@@ -451,6 +452,11 @@ struct iwl_mvm_frame_stats {
        int last_frame_idx;
 };
 
+enum {
+       D0I3_DEFER_WAKEUP,
+       D0I3_PENDING_WAKEUP,
+};
+
 struct iwl_mvm {
        /* for logger access */
        struct device *dev;
@@ -535,6 +541,8 @@ struct iwl_mvm {
        /* Internal station */
        struct iwl_mvm_int_sta aux_sta;
 
+       bool last_ebs_successful;
+
        u8 scan_last_antenna_idx; /* to toggle TX between antennas */
        u8 mgmt_last_antenna_idx;
 
@@ -578,6 +586,8 @@ struct iwl_mvm {
        void *fw_error_dump;
        void *fw_error_sram;
        u32 fw_error_sram_len;
+       u32 *fw_error_rxf;
+       u32 fw_error_rxf_len;
 
        struct led_classdev led;
 
@@ -601,6 +611,9 @@ struct iwl_mvm {
        bool d0i3_offloading;
        struct work_struct d0i3_exit_work;
        struct sk_buff_head d0i3_tx;
+       /* protect d0i3_suspend_flags */
+       struct mutex d0i3_suspend_mutex;
+       unsigned long d0i3_suspend_flags;
        /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */
        spinlock_t d0i3_tx_lock;
        wait_queue_head_t d0i3_exit_waitq;
@@ -629,8 +642,6 @@ struct iwl_mvm {
 
        /* Indicate if device power save is allowed */
        bool ps_disabled;
-       /* Indicate if device power management is allowed */
-       bool pm_disabled;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -705,6 +716,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
 void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm);
+void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm);
 #endif
 u8 first_antenna(u8 mask);
 u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
@@ -874,8 +886,6 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
 int rs_pretty_print_rate(char *buf, const u32 rate);
 
 /* power management */
-int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
-
 int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -922,9 +932,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
 void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
 void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
 void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
+int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
 
 /* BT Coex */
-int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
 int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
 int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
                             struct iwl_rx_cmd_buffer *rxb,
@@ -936,6 +946,8 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
                                struct ieee80211_sta *sta);
 bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
                                     struct ieee80211_sta *sta);
+bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
+                                   enum ieee80211_band band);
 u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
                           struct ieee80211_tx_info *info, u8 ac);
 int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable);
index 9545d7fdd4bfc69dfb1fb8c4e07de097d58b6ea7..7a5a8bac5fd0612f0f10e7d34847c39ca2428906 100644 (file)
@@ -402,6 +402,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        mvm->sf_state = SF_UNINIT;
 
        mutex_init(&mvm->mutex);
+       mutex_init(&mvm->d0i3_suspend_mutex);
        spin_lock_init(&mvm->async_handlers_lock);
        INIT_LIST_HEAD(&mvm->time_event_list);
        INIT_LIST_HEAD(&mvm->async_handlers_list);
@@ -538,6 +539,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        kfree(mvm->scan_cmd);
        vfree(mvm->fw_error_dump);
        kfree(mvm->fw_error_sram);
+       kfree(mvm->fw_error_rxf);
        kfree(mvm->mcast_filter_cmd);
        mvm->mcast_filter_cmd = NULL;
 
@@ -821,8 +823,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                return;
 
        file_len = mvm->fw_error_sram_len +
+                  mvm->fw_error_rxf_len +
                   sizeof(*dump_file) +
-                  sizeof(*dump_data);
+                  sizeof(*dump_data) * 2;
 
        dump_file = vmalloc(file_len);
        if (!dump_file)
@@ -833,7 +836,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
        dump_file->file_len = cpu_to_le32(file_len);
        dump_data = (void *)dump_file->data;
-       dump_data->type = IWL_FW_ERROR_DUMP_SRAM;
+       dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
+       dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len);
+       memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len);
+
+       dump_data = (void *)((u8 *)dump_data->data + mvm->fw_error_rxf_len);
+       dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM);
        dump_data->len = cpu_to_le32(mvm->fw_error_sram_len);
 
        /*
@@ -842,6 +850,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
         * mvm->fw_error_sram right now.
         */
        memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len);
+
+       kfree(mvm->fw_error_rxf);
+       mvm->fw_error_rxf = NULL;
+       mvm->fw_error_rxf_len = 0;
+
+       kfree(mvm->fw_error_sram);
+       mvm->fw_error_sram = NULL;
+       mvm->fw_error_sram_len = 0;
 }
 #endif
 
@@ -853,6 +869,7 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        iwl_mvm_fw_error_sram_dump(mvm);
+       iwl_mvm_fw_error_rxf_dump(mvm);
 #endif
 
        iwl_mvm_nic_restart(mvm);
@@ -1128,7 +1145,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
                .id = WOWLAN_GET_STATUSES,
                .flags = CMD_SYNC | CMD_HIGH_PRIO | CMD_WANT_SKB,
        };
-       struct iwl_wowlan_status_v6 *status;
+       struct iwl_wowlan_status *status;
        int ret;
        u32 disconnection_reasons, wakeup_reasons;
        __le16 *qos_seq = NULL;
@@ -1158,18 +1175,27 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
        iwl_free_resp(&get_status_cmd);
 out:
        iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
+       iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK);
        mutex_unlock(&mvm->mutex);
 }
 
-static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
+int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm)
 {
-       struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE |
                    CMD_WAKE_UP_TRANS;
        int ret;
 
        IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n");
 
+       mutex_lock(&mvm->d0i3_suspend_mutex);
+       if (test_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags)) {
+               IWL_DEBUG_RPM(mvm, "Deferring d0i3 exit until resume\n");
+               __set_bit(D0I3_PENDING_WAKEUP, &mvm->d0i3_suspend_flags);
+               mutex_unlock(&mvm->d0i3_suspend_mutex);
+               return 0;
+       }
+       mutex_unlock(&mvm->d0i3_suspend_mutex);
+
        ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL);
        if (ret)
                goto out;
@@ -1183,6 +1209,25 @@ out:
        return ret;
 }
 
+static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
+{
+       struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+       iwl_mvm_ref(mvm, IWL_MVM_REF_EXIT_WORK);
+       return _iwl_mvm_exit_d0i3(mvm);
+}
+
+static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode,
+                            struct napi_struct *napi,
+                            struct net_device *napi_dev,
+                            int (*poll)(struct napi_struct *, int),
+                            int weight)
+{
+       struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+       ieee80211_napi_add(mvm->hw, napi, napi_dev, poll, weight);
+}
+
 static const struct iwl_op_mode_ops iwl_mvm_ops = {
        .start = iwl_op_mode_mvm_start,
        .stop = iwl_op_mode_mvm_stop,
@@ -1196,4 +1241,5 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = {
        .nic_config = iwl_mvm_nic_config,
        .enter_d0i3 = iwl_mvm_enter_d0i3,
        .exit_d0i3 = iwl_mvm_exit_d0i3,
+       .napi_add = iwl_mvm_napi_add,
 };
index 6b636eab33391cbec4957180efe2e74d2ad07388..78309f7d0b7b8caea2c9443c81ae42e1f299e7ec 100644 (file)
@@ -268,6 +268,30 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
                IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
 }
 
+static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
+                                      struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+                   ETH_ALEN))
+               return false;
+
+       if (vif->p2p &&
+           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
+               return false;
+       /*
+        * Avoid using uAPSD if P2P client is associated to GO that uses
+        * opportunistic power save. This is due to current FW limitation.
+        */
+       if (vif->p2p &&
+           (vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
+           IEEE80211_P2P_OPPPS_ENABLE_BIT))
+               return false;
+
+       return true;
+}
+
 static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif,
                                    struct iwl_mac_power_cmd *cmd)
@@ -280,7 +304,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
        bool radar_detect = false;
        struct iwl_mvm_vif *mvmvif __maybe_unused =
                iwl_mvm_vif_from_mac80211(vif);
-       bool allow_uapsd = true;
 
        cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
                                                            mvmvif->color));
@@ -303,13 +326,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
-           mvmvif->dbgfs_pm.disable_power_off)
-               cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
-#endif
        if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
-           mvm->pm_disabled)
+           !mvmvif->pm_enabled)
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -351,23 +369,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                        cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
        }
 
-       if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
-                   ETH_ALEN))
-               allow_uapsd = false;
-
-       if (vif->p2p &&
-           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
-               allow_uapsd = false;
-       /*
-        * Avoid using uAPSD if P2P client is associated to GO that uses
-        * opportunistic power save. This is due to current FW limitation.
-        */
-       if (vif->p2p &&
-           vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
-           IEEE80211_P2P_OPPPS_ENABLE_BIT)
-               allow_uapsd = false;
-
-       if (allow_uapsd)
+       if (iwl_mvm_power_allow_uapsd(mvm, vif))
                iwl_mvm_power_configure_uapsd(mvm, vif, cmd);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -421,13 +423,6 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
 {
        struct iwl_mac_power_cmd cmd = {};
 
-       if (vif->type != NL80211_IFTYPE_STATION)
-               return 0;
-
-       if (vif->p2p &&
-           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))
-               return 0;
-
        iwl_mvm_power_build_cmd(mvm, vif, &cmd);
        iwl_mvm_power_log(mvm, &cmd);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -444,12 +439,6 @@ int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
                .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
        };
 
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
-               return 0;
-
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
-               return 0;
-
        if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
                mvm->ps_disabled = true;
 
@@ -508,86 +497,69 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
        return 0;
 }
 
-struct iwl_power_constraint {
+struct iwl_power_vifs {
        struct ieee80211_vif *bf_vif;
        struct ieee80211_vif *bss_vif;
        struct ieee80211_vif *p2p_vif;
-       u16 bss_phyctx_id;
-       u16 p2p_phyctx_id;
-       bool pm_disabled;
-       bool ps_disabled;
-       struct iwl_mvm *mvm;
+       struct ieee80211_vif *ap_vif;
+       struct ieee80211_vif *monitor_vif;
+       bool p2p_active;
+       bool bss_active;
+       bool ap_active;
+       bool monitor_active;
 };
 
 static void iwl_mvm_power_iterator(void *_data, u8 *mac,
                                   struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_power_constraint *power_iterator = _data;
-       struct iwl_mvm *mvm = power_iterator->mvm;
+       struct iwl_power_vifs *power_iterator = _data;
 
+       mvmvif->pm_enabled = false;
        switch (ieee80211_vif_type_p2p(vif)) {
        case NL80211_IFTYPE_P2P_DEVICE:
                break;
 
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_AP:
-               /* no BSS power mgmt if we have an active AP */
-               if (mvmvif->ap_ibss_active)
-                       power_iterator->pm_disabled = true;
+               /* only a single MAC of the same type */
+               WARN_ON(power_iterator->ap_vif);
+               power_iterator->ap_vif = vif;
+               if (mvmvif->phy_ctxt)
+                       if (mvmvif->phy_ctxt->id < MAX_PHYS)
+                               power_iterator->ap_active = true;
                break;
 
        case NL80211_IFTYPE_MONITOR:
-               /* no BSS power mgmt and no device power save */
-               power_iterator->pm_disabled = true;
-               power_iterator->ps_disabled = true;
+               /* only a single MAC of the same type */
+               WARN_ON(power_iterator->monitor_vif);
+               power_iterator->monitor_vif = vif;
+               if (mvmvif->phy_ctxt)
+                       if (mvmvif->phy_ctxt->id < MAX_PHYS)
+                               power_iterator->monitor_active = true;
                break;
 
        case NL80211_IFTYPE_P2P_CLIENT:
-               if (mvmvif->phy_ctxt)
-                       power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id;
-
-               /* we should have only one P2P vif */
+               /* only a single MAC of the same type */
                WARN_ON(power_iterator->p2p_vif);
                power_iterator->p2p_vif = vif;
-
-               IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n",
-                               power_iterator->p2p_phyctx_id,
-                               power_iterator->bss_phyctx_id);
-               if (!(mvm->fw->ucode_capa.flags &
-                     IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) {
-                       /* no BSS power mgmt if we have a P2P client*/
-                       power_iterator->pm_disabled = true;
-               } else if (power_iterator->p2p_phyctx_id < MAX_PHYS &&
-                          power_iterator->bss_phyctx_id < MAX_PHYS &&
-                          power_iterator->p2p_phyctx_id ==
-                          power_iterator->bss_phyctx_id) {
-                       power_iterator->pm_disabled = true;
-               }
+               if (mvmvif->phy_ctxt)
+                       if (mvmvif->phy_ctxt->id < MAX_PHYS)
+                               power_iterator->p2p_active = true;
                break;
 
        case NL80211_IFTYPE_STATION:
-               if (mvmvif->phy_ctxt)
-                       power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id;
-
-               /* we should have only one BSS vif */
+               /* only a single MAC of the same type */
                WARN_ON(power_iterator->bss_vif);
                power_iterator->bss_vif = vif;
+               if (mvmvif->phy_ctxt)
+                       if (mvmvif->phy_ctxt->id < MAX_PHYS)
+                               power_iterator->bss_active = true;
 
                if (mvmvif->bf_data.bf_enabled &&
                    !WARN_ON(power_iterator->bf_vif))
                        power_iterator->bf_vif = vif;
 
-               IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n",
-                               power_iterator->p2p_phyctx_id,
-                               power_iterator->bss_phyctx_id);
-               if (mvm->fw->ucode_capa.flags &
-                   IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM &&
-                       (power_iterator->p2p_phyctx_id < MAX_PHYS &&
-                        power_iterator->bss_phyctx_id < MAX_PHYS &&
-                        power_iterator->p2p_phyctx_id ==
-                        power_iterator->bss_phyctx_id))
-                       power_iterator->pm_disabled = true;
                break;
 
        default:
@@ -596,70 +568,118 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
 }
 
 static void
-iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm,
-                                   struct iwl_power_constraint *constraint)
+iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
+                                   struct iwl_power_vifs *vifs)
 {
-       lockdep_assert_held(&mvm->mutex);
+       struct iwl_mvm_vif *bss_mvmvif = NULL;
+       struct iwl_mvm_vif *p2p_mvmvif = NULL;
+       struct iwl_mvm_vif *ap_mvmvif = NULL;
+       bool client_same_channel = false;
+       bool ap_same_channel = false;
 
-       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
-               constraint->pm_disabled = true;
-               constraint->ps_disabled = true;
-       }
+       lockdep_assert_held(&mvm->mutex);
 
+       /* get vifs info + set pm_enable to false */
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_power_iterator, constraint);
+                                           iwl_mvm_power_iterator, vifs);
+
+       if (vifs->bss_vif)
+               bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
+
+       if (vifs->p2p_vif)
+               p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif);
+
+       if (vifs->ap_vif)
+               ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
+
+       /* enable PM on bss if bss stand alone */
+       if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
+               bss_mvmvif->pm_enabled = true;
+               return;
+       }
+
+       /* enable PM on p2p if p2p stand alone */
+       if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
+               if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
+                       p2p_mvmvif->pm_enabled = true;
+               return;
+       }
+
+       if (vifs->bss_active && vifs->p2p_active)
+               client_same_channel = (bss_mvmvif->phy_ctxt->id ==
+                                      p2p_mvmvif->phy_ctxt->id);
+       if (vifs->bss_active && vifs->ap_active)
+               ap_same_channel = (bss_mvmvif->phy_ctxt->id ==
+                                  ap_mvmvif->phy_ctxt->id);
+
+       /* bss is not stand alone: enable PM if alone on its channel */
+       if (vifs->bss_active && !(client_same_channel || ap_same_channel) &&
+           (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) {
+                       bss_mvmvif->pm_enabled = true;
+                       return;
+       }
+
+       /*
+        * There is only one channel in the system and there are only
+        * bss and p2p clients that share it
+        */
+       if (client_same_channel && !vifs->ap_active &&
+           (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM)) {
+               /* share same channel*/
+               bss_mvmvif->pm_enabled = true;
+               if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
+                       p2p_mvmvif->pm_enabled = true;
+       }
 }
 
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_power_constraint constraint = {
-                   .p2p_phyctx_id = MAX_PHYS,
-                   .bss_phyctx_id = MAX_PHYS,
-                   .mvm = mvm,
-       };
+       struct iwl_mvm_vif *mvmvif;
+       struct iwl_power_vifs vifs = {};
        bool ba_enable;
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
-               return 0;
-
-       iwl_mvm_power_get_global_constraint(mvm, &constraint);
-       mvm->ps_disabled = constraint.ps_disabled;
-       mvm->pm_disabled = constraint.pm_disabled;
+       iwl_mvm_power_set_pm(mvm, &vifs);
 
+       /* disable PS if CAM */
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
+               mvm->ps_disabled = true;
+       } else {
        /* don't update device power state unless we add / remove monitor */
-       if (vif->type == NL80211_IFTYPE_MONITOR) {
-               ret = iwl_mvm_power_update_device(mvm);
-               if (ret)
-                       return ret;
+               if (vifs.monitor_vif) {
+                       if (vifs.monitor_active)
+                               mvm->ps_disabled = true;
+                       ret = iwl_mvm_power_update_device(mvm);
+                       if (ret)
+                               return ret;
+               }
        }
 
-       if (constraint.bss_vif) {
-               ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif);
+       if (vifs.bss_vif) {
+               ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
                if (ret)
                        return ret;
        }
 
-       if (constraint.p2p_vif) {
-               ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif);
+       if (vifs.p2p_vif) {
+               ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif);
                if (ret)
                        return ret;
        }
 
-       if (!constraint.bf_vif)
+       if (!vifs.bf_vif)
                return 0;
 
-       vif = constraint.bf_vif;
+       vif = vifs.bf_vif;
        mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
-       ba_enable = !(constraint.pm_disabled || constraint.ps_disabled ||
+       ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
                      !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
 
-       return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable);
+       return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable);
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -671,19 +691,10 @@ int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
        struct iwl_mac_power_cmd cmd = {};
        int pos = 0;
 
-       if (WARN_ON(!(mvm->fw->ucode_capa.flags &
-                     IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)))
-               return 0;
-
        mutex_lock(&mvm->mutex);
        memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd));
        mutex_unlock(&mvm->mutex);
 
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
-               pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
-                                (cmd.flags &
-                                cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ?
-                                0 : 1);
        pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
                         iwlmvm_mod_params.power_scheme);
        pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
@@ -826,8 +837,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
 
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED) ||
-           vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
                return 0;
 
        ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
@@ -914,13 +924,3 @@ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
 
        return iwl_mvm_enable_beacon_filter(mvm, vif, flags);
 }
-
-int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm)
-{
-       struct iwl_powertable_cmd cmd = {
-               .keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC,
-       };
-
-       return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
-                                   sizeof(cmd), &cmd);
-}
index 9f52c5b3f0ec0e9b2da5949f2af88bbcd13d89ce..d44b2b33b5ccca71b1f1e6ad0ec6ab2573fdd083 100644 (file)
@@ -527,6 +527,9 @@ static void rs_rate_scale_clear_tbl_windows(struct iwl_mvm *mvm,
        IWL_DEBUG_RATE(mvm, "Clearing up window stats\n");
        for (i = 0; i < IWL_RATE_COUNT; i++)
                rs_rate_scale_clear_window(&tbl->win[i]);
+
+       for (i = 0; i < ARRAY_SIZE(tbl->tpc_win); i++)
+               rs_rate_scale_clear_window(&tbl->tpc_win[i]);
 }
 
 static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
@@ -656,17 +659,34 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
        return 0;
 }
 
-static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
-                             int scale_index, int attempts, int successes)
+static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
+                             struct iwl_scale_tbl_info *tbl,
+                             int scale_index, int attempts, int successes,
+                             u8 reduced_txp)
 {
        struct iwl_rate_scale_data *window = NULL;
+       int ret;
 
        if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
                return -EINVAL;
 
+       if (tbl->column != RS_COLUMN_INVALID) {
+               lq_sta->tx_stats[tbl->column][scale_index].total += attempts;
+               lq_sta->tx_stats[tbl->column][scale_index].success += successes;
+       }
+
        /* Select window for current tx bit rate */
        window = &(tbl->win[scale_index]);
 
+       ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes,
+                                 window);
+       if (ret)
+               return ret;
+
+       if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION))
+               return -EINVAL;
+
+       window = &tbl->tpc_win[reduced_txp];
        return _rs_collect_tx_data(tbl, scale_index, attempts, successes,
                                   window);
 }
@@ -1000,6 +1020,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
        u32 ucode_rate;
        struct rs_rate rate;
        struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+       u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0];
 
        /* Treat uninitialized rate scaling data same as non-existing. */
        if (!lq_sta) {
@@ -1141,9 +1162,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
        if (info->flags & IEEE80211_TX_STAT_AMPDU) {
                ucode_rate = le32_to_cpu(table->rs_table[0]);
                rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
-               rs_collect_tx_data(curr_tbl, rate.index,
+               rs_collect_tx_data(lq_sta, curr_tbl, rate.index,
                                   info->status.ampdu_len,
-                                  info->status.ampdu_ack_len);
+                                  info->status.ampdu_ack_len,
+                                  reduced_txp);
 
                /* Update success/fail counts if not searching for new mode */
                if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
@@ -1176,8 +1198,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
                        else
                                continue;
 
-                       rs_collect_tx_data(tmp_tbl, rate.index, 1,
-                                          i < retries ? 0 : legacy_success);
+                       rs_collect_tx_data(lq_sta, tmp_tbl, rate.index, 1,
+                                          i < retries ? 0 : legacy_success,
+                                          reduced_txp);
                }
 
                /* Update success/fail counts if not searching for new mode */
@@ -1188,6 +1211,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
        }
        /* The last TX rate is cached in lq_sta; it's set in if/else above */
        lq_sta->last_rate_n_flags = ucode_rate;
+       IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
 done:
        /* See if there's a better rate or modulation mode to try. */
        if (sta && sta->supp_rates[sband->band])
@@ -1769,6 +1793,198 @@ out:
        return action;
 }
 
+static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
+                               int *weaker, int *stronger)
+{
+       *weaker = index + TPC_TX_POWER_STEP;
+       if (*weaker > TPC_MAX_REDUCTION)
+               *weaker = TPC_INVALID;
+
+       *stronger = index - TPC_TX_POWER_STEP;
+       if (*stronger < 0)
+               *stronger = TPC_INVALID;
+}
+
+static bool rs_tpc_allowed(struct iwl_mvm *mvm, struct rs_rate *rate,
+                          enum ieee80211_band band)
+{
+       int index = rate->index;
+
+       /*
+        * allow tpc only if power management is enabled, or bt coex
+        * activity grade allows it and we are on 2.4Ghz.
+        */
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM &&
+           !iwl_mvm_bt_coex_is_tpc_allowed(mvm, band))
+               return false;
+
+       IWL_DEBUG_RATE(mvm, "check rate, table type: %d\n", rate->type);
+       if (is_legacy(rate))
+               return index == IWL_RATE_54M_INDEX;
+       if (is_ht(rate))
+               return index == IWL_RATE_MCS_7_INDEX;
+       if (is_vht(rate))
+               return index == IWL_RATE_MCS_7_INDEX ||
+                      index == IWL_RATE_MCS_8_INDEX ||
+                      index == IWL_RATE_MCS_9_INDEX;
+
+       WARN_ON_ONCE(1);
+       return false;
+}
+
+enum tpc_action {
+       TPC_ACTION_STAY,
+       TPC_ACTION_DECREASE,
+       TPC_ACTION_INCREASE,
+       TPC_ACTION_NO_RESTIRCTION,
+};
+
+static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
+                                        s32 sr, int weak, int strong,
+                                        int current_tpt,
+                                        int weak_tpt, int strong_tpt)
+{
+       /* stay until we have valid tpt */
+       if (current_tpt == IWL_INVALID_VALUE) {
+               IWL_DEBUG_RATE(mvm, "no current tpt. stay.\n");
+               return TPC_ACTION_STAY;
+       }
+
+       /* Too many failures, increase txp */
+       if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) {
+               IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n");
+               return TPC_ACTION_NO_RESTIRCTION;
+       }
+
+       /* try decreasing first if applicable */
+       if (weak != TPC_INVALID) {
+               if (weak_tpt == IWL_INVALID_VALUE &&
+                   (strong_tpt == IWL_INVALID_VALUE ||
+                    current_tpt >= strong_tpt)) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "no weak txp measurement. decrease txp\n");
+                       return TPC_ACTION_DECREASE;
+               }
+
+               if (weak_tpt > current_tpt) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "lower txp has better tpt. decrease txp\n");
+                       return TPC_ACTION_DECREASE;
+               }
+       }
+
+       /* next, increase if needed */
+       if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) {
+               if (weak_tpt == IWL_INVALID_VALUE &&
+                   strong_tpt != IWL_INVALID_VALUE &&
+                   current_tpt < strong_tpt) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "higher txp has better tpt. increase txp\n");
+                       return TPC_ACTION_INCREASE;
+               }
+
+               if (weak_tpt < current_tpt &&
+                   (strong_tpt == IWL_INVALID_VALUE ||
+                    strong_tpt > current_tpt)) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "lower txp has worse tpt. increase txp\n");
+                       return TPC_ACTION_INCREASE;
+               }
+       }
+
+       IWL_DEBUG_RATE(mvm, "no need to increase or decrease txp - stay\n");
+       return TPC_ACTION_STAY;
+}
+
+static bool rs_tpc_perform(struct iwl_mvm *mvm,
+                          struct ieee80211_sta *sta,
+                          struct iwl_lq_sta *lq_sta,
+                          struct iwl_scale_tbl_info *tbl)
+{
+       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct ieee80211_vif *vif = mvm_sta->vif;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       enum ieee80211_band band;
+       struct iwl_rate_scale_data *window;
+       struct rs_rate *rate = &tbl->rate;
+       enum tpc_action action;
+       s32 sr;
+       u8 cur = lq_sta->lq.reduced_tpc;
+       int current_tpt;
+       int weak, strong;
+       int weak_tpt = IWL_INVALID_VALUE, strong_tpt = IWL_INVALID_VALUE;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       if (lq_sta->dbg_fixed_txp_reduction <= TPC_MAX_REDUCTION) {
+               IWL_DEBUG_RATE(mvm, "fixed tpc: %d",
+                              lq_sta->dbg_fixed_txp_reduction);
+               lq_sta->lq.reduced_tpc = lq_sta->dbg_fixed_txp_reduction;
+               return cur != lq_sta->dbg_fixed_txp_reduction;
+       }
+#endif
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(vif->chanctx_conf);
+       if (WARN_ON(!chanctx_conf))
+               band = IEEE80211_NUM_BANDS;
+       else
+               band = chanctx_conf->def.chan->band;
+       rcu_read_unlock();
+
+       if (!rs_tpc_allowed(mvm, rate, band)) {
+               IWL_DEBUG_RATE(mvm,
+                              "tpc is not allowed. remove txp restrictions");
+               lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION;
+               return cur != TPC_NO_REDUCTION;
+       }
+
+       rs_get_adjacent_txp(mvm, cur, &weak, &strong);
+
+       /* Collect measured throughputs for current and adjacent rates */
+       window = tbl->tpc_win;
+       sr = window[cur].success_ratio;
+       current_tpt = window[cur].average_tpt;
+       if (weak != TPC_INVALID)
+               weak_tpt = window[weak].average_tpt;
+       if (strong != TPC_INVALID)
+               strong_tpt = window[strong].average_tpt;
+
+       IWL_DEBUG_RATE(mvm,
+                      "(TPC: %d): cur_tpt %d SR %d weak %d strong %d weak_tpt %d strong_tpt %d\n",
+                      cur, current_tpt, sr, weak, strong,
+                      weak_tpt, strong_tpt);
+
+       action = rs_get_tpc_action(mvm, sr, weak, strong,
+                                  current_tpt, weak_tpt, strong_tpt);
+
+       /* override actions if we are on the edge */
+       if (weak == TPC_INVALID && action == TPC_ACTION_DECREASE) {
+               IWL_DEBUG_RATE(mvm, "already in lowest txp, stay");
+               action = TPC_ACTION_STAY;
+       } else if (strong == TPC_INVALID &&
+                  (action == TPC_ACTION_INCREASE ||
+                   action == TPC_ACTION_NO_RESTIRCTION)) {
+               IWL_DEBUG_RATE(mvm, "already in highest txp, stay");
+               action = TPC_ACTION_STAY;
+       }
+
+       switch (action) {
+       case TPC_ACTION_DECREASE:
+               lq_sta->lq.reduced_tpc = weak;
+               return true;
+       case TPC_ACTION_INCREASE:
+               lq_sta->lq.reduced_tpc = strong;
+               return true;
+       case TPC_ACTION_NO_RESTIRCTION:
+               lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION;
+               return true;
+       case TPC_ACTION_STAY:
+               /* do nothing */
+               break;
+       }
+       return false;
+}
+
 /*
  * Do rate scaling and search for new modulation mode.
  */
@@ -2019,6 +2235,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                break;
        case RS_ACTION_STAY:
                /* No change */
+               update_lq = rs_tpc_perform(mvm, sta, lq_sta, tbl);
+               break;
        default:
                break;
        }
@@ -2478,6 +2696,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        lq_sta->is_agg = 0;
 #ifdef CONFIG_MAC80211_DEBUGFS
        lq_sta->dbg_fixed_rate = 0;
+       lq_sta->dbg_fixed_txp_reduction = TPC_INVALID;
 #endif
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
@@ -2653,6 +2872,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
                rs_build_rates_table_from_fixed(mvm, lq_cmd,
                                                lq_sta->band,
                                                lq_sta->dbg_fixed_rate);
+               lq_cmd->reduced_tpc = 0;
                ant = (lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
                        RATE_MCS_ANT_POS;
        } else
@@ -2783,7 +3003,6 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
        size_t buf_size;
        u32 parsed_rate;
 
-
        mvm = lq_sta->drv;
        memset(buf, 0, sizeof(buf));
        buf_size = min(count, sizeof(buf) -  1);
@@ -2856,6 +3075,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        lq_sta->lq.agg_disable_start_th,
                        lq_sta->lq.agg_frame_cnt_limit);
 
+       desc += sprintf(buff+desc, "reduced tpc=%d\n", lq_sta->lq.reduced_tpc);
        desc += sprintf(buff+desc,
                        "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
                        lq_sta->lq.initial_rate_index[0],
@@ -2928,6 +3148,94 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
        .llseek = default_llseek,
 };
 
+static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file,
+                                             char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       static const char * const column_name[] = {
+               [RS_COLUMN_LEGACY_ANT_A] = "LEGACY_ANT_A",
+               [RS_COLUMN_LEGACY_ANT_B] = "LEGACY_ANT_B",
+               [RS_COLUMN_SISO_ANT_A] = "SISO_ANT_A",
+               [RS_COLUMN_SISO_ANT_B] = "SISO_ANT_B",
+               [RS_COLUMN_SISO_ANT_A_SGI] = "SISO_ANT_A_SGI",
+               [RS_COLUMN_SISO_ANT_B_SGI] = "SISO_ANT_B_SGI",
+               [RS_COLUMN_MIMO2] = "MIMO2",
+               [RS_COLUMN_MIMO2_SGI] = "MIMO2_SGI",
+       };
+
+       static const char * const rate_name[] = {
+               [IWL_RATE_1M_INDEX] = "1M",
+               [IWL_RATE_2M_INDEX] = "2M",
+               [IWL_RATE_5M_INDEX] = "5.5M",
+               [IWL_RATE_11M_INDEX] = "11M",
+               [IWL_RATE_6M_INDEX] = "6M|MCS0",
+               [IWL_RATE_9M_INDEX] = "9M",
+               [IWL_RATE_12M_INDEX] = "12M|MCS1",
+               [IWL_RATE_18M_INDEX] = "18M|MCS2",
+               [IWL_RATE_24M_INDEX] = "24M|MCS3",
+               [IWL_RATE_36M_INDEX] = "36M|MCS4",
+               [IWL_RATE_48M_INDEX] = "48M|MCS5",
+               [IWL_RATE_54M_INDEX] = "54M|MCS6",
+               [IWL_RATE_MCS_7_INDEX] = "MCS7",
+               [IWL_RATE_MCS_8_INDEX] = "MCS8",
+               [IWL_RATE_MCS_9_INDEX] = "MCS9",
+       };
+
+       char *buff, *pos, *endpos;
+       int col, rate;
+       ssize_t ret;
+       struct iwl_lq_sta *lq_sta = file->private_data;
+       struct rs_rate_stats *stats;
+       static const size_t bufsz = 1024;
+
+       buff = kmalloc(bufsz, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
+       pos = buff;
+       endpos = pos + bufsz;
+
+       pos += scnprintf(pos, endpos - pos, "COLUMN,");
+       for (rate = 0; rate < IWL_RATE_COUNT; rate++)
+               pos += scnprintf(pos, endpos - pos, "%s,", rate_name[rate]);
+       pos += scnprintf(pos, endpos - pos, "\n");
+
+       for (col = 0; col < RS_COLUMN_COUNT; col++) {
+               pos += scnprintf(pos, endpos - pos,
+                                "%s,", column_name[col]);
+
+               for (rate = 0; rate < IWL_RATE_COUNT; rate++) {
+                       stats = &(lq_sta->tx_stats[col][rate]);
+                       pos += scnprintf(pos, endpos - pos,
+                                        "%llu/%llu,",
+                                        stats->success,
+                                        stats->total);
+               }
+               pos += scnprintf(pos, endpos - pos, "\n");
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
+       kfree(buff);
+       return ret;
+}
+
+static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file,
+                                              const char __user *user_buf,
+                                              size_t count, loff_t *ppos)
+{
+       struct iwl_lq_sta *lq_sta = file->private_data;
+       memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats));
+
+       return count;
+}
+
+static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = {
+       .read = rs_sta_dbgfs_drv_tx_stats_read,
+       .write = rs_sta_dbgfs_drv_tx_stats_write,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
 static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
 {
        struct iwl_lq_sta *lq_sta = mvm_sta;
@@ -2937,9 +3245,15 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
        lq_sta->rs_sta_dbgfs_stats_table_file =
                debugfs_create_file("rate_stats_table", S_IRUSR, dir,
                                    lq_sta, &rs_sta_dbgfs_stats_table_ops);
+       lq_sta->rs_sta_dbgfs_drv_tx_stats_file =
+               debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir,
+                                   lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops);
        lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
                debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
                                  &lq_sta->tx_agg_tid_en);
+       lq_sta->rs_sta_dbgfs_reduced_txp_file =
+               debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir,
+                                 &lq_sta->dbg_fixed_txp_reduction);
 }
 
 static void rs_remove_debugfs(void *mvm, void *mvm_sta)
@@ -2947,7 +3261,9 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta)
        struct iwl_lq_sta *lq_sta = mvm_sta;
        debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
        debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+       debugfs_remove(lq_sta->rs_sta_dbgfs_drv_tx_stats_file);
        debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+       debugfs_remove(lq_sta->rs_sta_dbgfs_reduced_txp_file);
 }
 #endif
 
index 0acfac96a56c6dca2d2799812231404921abd15b..374a83d7db25a98dd76da34d3fdff9557e48664f 100644 (file)
@@ -158,6 +158,13 @@ enum {
 #define RS_SR_FORCE_DECREASE           1920    /*  15% */
 #define RS_SR_NO_DECREASE              10880   /*  85% */
 
+#define TPC_SR_FORCE_INCREASE          9600    /* 75% */
+#define TPC_SR_NO_INCREASE             10880   /* 85% */
+#define TPC_TX_POWER_STEP              3
+#define TPC_MAX_REDUCTION              15
+#define TPC_NO_REDUCTION               0
+#define TPC_INVALID                    0xff
+
 #define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000) /* 4 milliseconds */
 #define LINK_QUAL_AGG_TIME_LIMIT_MAX   (8000)
 #define LINK_QUAL_AGG_TIME_LIMIT_MIN   (100)
@@ -266,9 +273,16 @@ enum rs_column {
        RS_COLUMN_MIMO2_SGI,
 
        RS_COLUMN_LAST = RS_COLUMN_MIMO2_SGI,
+       RS_COLUMN_COUNT = RS_COLUMN_LAST + 1,
        RS_COLUMN_INVALID,
 };
 
+/* Packet stats per rate */
+struct rs_rate_stats {
+       u64 success;
+       u64 total;
+};
+
 /**
  * struct iwl_scale_tbl_info -- tx params and success history for all rates
  *
@@ -280,6 +294,8 @@ struct iwl_scale_tbl_info {
        enum rs_column column;
        const u16 *expected_tpt;        /* throughput metrics; expected_tpt_G, etc. */
        struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+       /* per txpower-reduction history */
+       struct iwl_rate_scale_data tpc_win[TPC_MAX_REDUCTION + 1];
 };
 
 enum {
@@ -315,6 +331,8 @@ struct iwl_lq_sta {
        bool is_vht;
        enum ieee80211_band band;
 
+       struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
+
        /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
        unsigned long active_legacy_rate;
        unsigned long active_siso_rate;
@@ -334,8 +352,11 @@ struct iwl_lq_sta {
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct dentry *rs_sta_dbgfs_scale_table_file;
        struct dentry *rs_sta_dbgfs_stats_table_file;
+       struct dentry *rs_sta_dbgfs_drv_tx_stats_file;
        struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+       struct dentry *rs_sta_dbgfs_reduced_txp_file;
        u32 dbg_fixed_rate;
+       u8 dbg_fixed_txp_reduction;
 #endif
        struct iwl_mvm *drv;
 
@@ -345,6 +366,9 @@ struct iwl_lq_sta {
        u32 last_rate_n_flags;
        /* packets destined for this STA are aggregated */
        u8 is_agg;
+
+       /* tx power reduce for this sta */
+       int tpc_reduce;
 };
 
 /* Initialize station's rate scaling information after adding station */
index 6061553a5e444956c7b5d626695a2950fb1f3fd1..cf7276967acdec6439392c82e44e94de52d453c8 100644 (file)
@@ -60,7 +60,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 #include "iwl-trans.h"
-
 #include "mvm.h"
 #include "fw-api.h"
 
@@ -130,42 +129,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
 
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
-       ieee80211_rx_ni(mvm->hw, skb);
-}
-
-static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm,
-                             struct iwl_rx_phy_info *phy_info,
-                             struct ieee80211_rx_status *rx_status)
-{
-       int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm;
-       u32 agc_a, agc_b;
-       u32 val;
-
-       val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]);
-       agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS;
-       agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS;
-
-       val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);
-       rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;
-       rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS;
-
-       /*
-        * dBm = rssi dB - agc dB - constant.
-        * Higher AGC (higher radio gain) means lower signal.
-        */
-       rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a;
-       rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b;
-       max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm);
-
-       IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n",
-                       rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b);
-
-       rx_status->signal = max_rssi_dbm;
-       rx_status->chains = (le16_to_cpu(phy_info->phy_flags) &
-                               RX_RES_PHY_FLAGS_ANTENNA)
-                                       >> RX_RES_PHY_FLAGS_ANTENNA_POS;
-       rx_status->chain_signal[0] = rssi_a_dbm;
-       rx_status->chain_signal[1] = rssi_b_dbm;
+       ieee80211_rx(mvm->hw, skb);
 }
 
 /*
@@ -337,10 +301,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
         */
        /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_RX_ENERGY_API)
-               iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status);
-       else
-               iwl_mvm_calc_rssi(mvm, phy_info, &rx_status);
+       iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status);
 
        IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal,
                              (unsigned long long)rx_status.mactime);
@@ -394,6 +355,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
                rx_status.flag |= RX_FLAG_VHT;
                rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT;
+               if (rate_n_flags & RATE_MCS_BF_MSK)
+                       rx_status.vht_flag |= RX_VHT_FLAG_BF;
        } else {
                rx_status.rate_idx =
                        iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
index c91dc8498852c46653cc43fddb57c382d3d7f3f0..63e7b16edb552be4b626fca9d0b64b064adc6fd2 100644 (file)
@@ -348,7 +348,10 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
        struct iwl_mvm_scan_params params = {};
 
        lockdep_assert_held(&mvm->mutex);
-       BUG_ON(mvm->scan_cmd == NULL);
+
+       /* we should have failed registration if scan_cmd was NULL */
+       if (WARN_ON(mvm->scan_cmd == NULL))
+               return -ENOMEM;
 
        IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n");
        mvm->scan_status = IWL_MVM_SCAN_OS;
@@ -567,9 +570,13 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
        /* scan status must be locked for proper checking */
        lockdep_assert_held(&mvm->mutex);
 
-       IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n",
+       IWL_DEBUG_SCAN(mvm,
+                      "Scheduled scan completed, status %s EBS status %s:%d\n",
                       scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
-                      "completed" : "aborted");
+                      "completed" : "aborted", scan_notif->ebs_status ==
+                      IWL_SCAN_EBS_SUCCESS ? "success" : "failed",
+                      scan_notif->ebs_status);
+
 
        /* only call mac80211 completion if the stop was initiated by FW */
        if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
@@ -577,6 +584,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
                ieee80211_sched_scan_stopped(mvm->hw);
        }
 
+       mvm->last_ebs_successful = !scan_notif->ebs_status;
+
        return 0;
 }
 
@@ -913,6 +922,11 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL);
        }
 
+       if (mvm->last_ebs_successful &&
+           mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT)
+               scan_req.flags |=
+                       cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE);
+
        return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC,
                                    sizeof(scan_req), &scan_req);
 }
index 88809b2d165445fcf9188c8f91bcf755a9e6704f..7edfd15efc9d001f227ea2c35b046c0f47cb55af 100644 (file)
@@ -237,9 +237,6 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
                .sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT,
        };
 
-       if (IWL_UCODE_API(mvm->fw->ucode_ver) < 8)
-               return 0;
-
        /*
         * Ignore the call if we are in HW Restart flow, or if the handled
         * vif is a p2p device.
index f339ef8842508774e2ff7d51c9bdce069e014a1b..3e11b9d802e75981ad5731955d9367996a8cec47 100644 (file)
 #include "sta.h"
 #include "rs.h"
 
-static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7,
-                                        struct iwl_mvm_add_sta_cmd_v5 *cmd_v5)
-{
-       memset(cmd_v5, 0, sizeof(*cmd_v5));
-
-       cmd_v5->add_modify = cmd_v7->add_modify;
-       cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx;
-       cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color;
-       memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN);
-       cmd_v5->sta_id = cmd_v7->sta_id;
-       cmd_v5->modify_mask = cmd_v7->modify_mask;
-       cmd_v5->station_flags = cmd_v7->station_flags;
-       cmd_v5->station_flags_msk = cmd_v7->station_flags_msk;
-       cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid;
-       cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid;
-       cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn;
-       cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count;
-       cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags;
-       cmd_v5->assoc_id = cmd_v7->assoc_id;
-       cmd_v5->beamform_flags = cmd_v7->beamform_flags;
-       cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk;
-}
-
-static void
-iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd,
-                                     struct iwl_mvm_add_sta_cmd_v5 *sta_cmd,
-                                     u32 mac_id_n_color)
-{
-       memset(sta_cmd, 0, sizeof(*sta_cmd));
-
-       sta_cmd->sta_id = key_cmd->sta_id;
-       sta_cmd->add_modify = STA_MODE_MODIFY;
-       sta_cmd->modify_mask = STA_MODIFY_KEY;
-       sta_cmd->mac_id_n_color = cpu_to_le32(mac_id_n_color);
-
-       sta_cmd->key.key_offset = key_cmd->key_offset;
-       sta_cmd->key.key_flags = key_cmd->key_flags;
-       memcpy(sta_cmd->key.key, key_cmd->key, sizeof(sta_cmd->key.key));
-       sta_cmd->key.tkip_rx_tsc_byte2 = key_cmd->tkip_rx_tsc_byte2;
-       memcpy(sta_cmd->key.tkip_rx_ttak, key_cmd->tkip_rx_ttak,
-              sizeof(sta_cmd->key.tkip_rx_ttak));
-}
-
-static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
-                                          struct iwl_mvm_add_sta_cmd_v7 *cmd,
-                                          int *status)
-{
-       struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
-
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
-               return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd),
-                                                  cmd, status);
-
-       iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5);
-
-       return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5),
-                                          &cmd_v5, status);
-}
-
-static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
-                                   struct iwl_mvm_add_sta_cmd_v7 *cmd)
-{
-       struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
-
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
-               return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags,
-                                           sizeof(*cmd), cmd);
-
-       iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5);
-
-       return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5),
-                                   &cmd_v5);
-}
-
-static int
-iwl_mvm_send_add_sta_key_cmd_status(struct iwl_mvm *mvm,
-                                   struct iwl_mvm_add_sta_key_cmd *cmd,
-                                   u32 mac_id_n_color,
-                                   int *status)
-{
-       struct iwl_mvm_add_sta_cmd_v5 sta_cmd;
-
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
-               return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY,
-                                                  sizeof(*cmd), cmd, status);
-
-       iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color);
-
-       return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(sta_cmd),
-                                          &sta_cmd, status);
-}
-
-static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm,
-                                       u32 flags,
-                                       struct iwl_mvm_add_sta_key_cmd *cmd,
-                                       u32 mac_id_n_color)
-{
-       struct iwl_mvm_add_sta_cmd_v5 sta_cmd;
-
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
-               return iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, flags,
-                                           sizeof(*cmd), cmd);
-
-       iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color);
-
-       return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(sta_cmd),
-                                   &sta_cmd);
-}
-
 static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
                                    enum nl80211_iftype iftype)
 {
@@ -207,7 +98,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                           bool update)
 {
        struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
-       struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd;
+       struct iwl_mvm_add_sta_cmd add_sta_cmd;
        int ret;
        u32 status;
        u32 agg_size = 0, mpdu_dens = 0;
@@ -295,7 +186,8 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_add_sta_cmd_status(mvm, &add_sta_cmd, &status);
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd),
+                                         &add_sta_cmd, &status);
        if (ret)
                return ret;
 
@@ -380,7 +272,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm,
 int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
                      bool drain)
 {
-       struct iwl_mvm_add_sta_cmd_v7 cmd = {};
+       struct iwl_mvm_add_sta_cmd cmd = {};
        int ret;
        u32 status;
 
@@ -393,7 +285,8 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
        cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+                                         &cmd, &status);
        if (ret)
                return ret;
 
@@ -498,7 +391,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
                                sta_id);
                        continue;
                }
-               rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL);
+               RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
                clear_bit(sta_id, mvm->sta_drained);
        }
 
@@ -520,14 +413,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
                /* flush its queues here since we are freeing mvm_sta */
                ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
 
-               /*
-                * Put a non-NULL since the fw station isn't removed.
-                * It will be removed after the MAC will be set as
-                * unassoc.
-                */
-               rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
-                                  ERR_PTR(-EINVAL));
-
                /* if we are associated - we can't remove the AP STA now */
                if (vif->bss_conf.assoc)
                        return ret;
@@ -557,7 +442,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
        } else {
                spin_unlock_bh(&mvm_sta->lock);
                ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
-               rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
+               RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
        }
 
        return ret;
@@ -571,7 +456,7 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
 
        lockdep_assert_held(&mvm->mutex);
 
-       rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL);
+       RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
        return ret;
 }
 
@@ -593,7 +478,7 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
 
 void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
 {
-       rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
+       RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
        memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
        sta->sta_id = IWL_MVM_STATION_COUNT;
 }
@@ -603,13 +488,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
                                      const u8 *addr,
                                      u16 mac_id, u16 color)
 {
-       struct iwl_mvm_add_sta_cmd_v7 cmd;
+       struct iwl_mvm_add_sta_cmd cmd;
        int ret;
        u32 status;
 
        lockdep_assert_held(&mvm->mutex);
 
-       memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7));
+       memset(&cmd, 0, sizeof(cmd));
        cmd.sta_id = sta->sta_id;
        cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
                                                             color));
@@ -619,7 +504,8 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
        if (addr)
                memcpy(cmd.addr, addr, ETH_ALEN);
 
-       ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+                                         &cmd, &status);
        if (ret)
                return ret;
 
@@ -753,7 +639,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                       int tid, u16 ssn, bool start)
 {
        struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
-       struct iwl_mvm_add_sta_cmd_v7 cmd = {};
+       struct iwl_mvm_add_sta_cmd cmd = {};
        int ret;
        u32 status;
 
@@ -777,7 +663,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                                  STA_MODIFY_REMOVE_BA_TID;
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+                                         &cmd, &status);
        if (ret)
                return ret;
 
@@ -812,7 +699,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                              int tid, u8 queue, bool start)
 {
        struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
-       struct iwl_mvm_add_sta_cmd_v7 cmd = {};
+       struct iwl_mvm_add_sta_cmd cmd = {};
        int ret;
        u32 status;
 
@@ -834,7 +721,8 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+                                         &cmd, &status);
        if (ret)
                return ret;
 
@@ -1129,12 +1017,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
                                u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
                                u32 cmd_flags)
 {
-       __le16 key_flags;
        struct iwl_mvm_add_sta_key_cmd cmd = {};
+       __le16 key_flags;
        int ret, status;
        u16 keyidx;
        int i;
-       u32 mac_id_n_color = mvm_sta->mac_id_n_color;
 
        keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
                 STA_KEY_FLG_KEYID_MSK;
@@ -1167,12 +1054,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
 
        status = ADD_STA_SUCCESS;
        if (cmd_flags == CMD_SYNC)
-               ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd,
-                                                         mac_id_n_color,
-                                                         &status);
+               ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd),
+                                                 &cmd, &status);
        else
-               ret = iwl_mvm_send_add_sta_key_cmd(mvm, CMD_ASYNC, &cmd,
-                                                  mac_id_n_color);
+               ret =  iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, CMD_ASYNC,
+                                           sizeof(cmd), &cmd);
 
        switch (status) {
        case ADD_STA_SUCCESS:
@@ -1399,9 +1285,8 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
        cmd.sta_id = sta_id;
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd,
-                                                 mvm_sta->mac_id_n_color,
-                                                 &status);
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd),
+                                         &cmd, &status);
 
        switch (status) {
        case ADD_STA_SUCCESS:
@@ -1448,7 +1333,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
                                struct ieee80211_sta *sta)
 {
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-       struct iwl_mvm_add_sta_cmd_v7 cmd = {
+       struct iwl_mvm_add_sta_cmd cmd = {
                .add_modify = STA_MODE_MODIFY,
                .sta_id = mvmsta->sta_id,
                .station_flags_msk = cpu_to_le32(STA_FLG_PS),
@@ -1456,7 +1341,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
        };
        int ret;
 
-       ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
@@ -1468,7 +1353,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
                                       bool agg)
 {
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-       struct iwl_mvm_add_sta_cmd_v7 cmd = {
+       struct iwl_mvm_add_sta_cmd cmd = {
                .add_modify = STA_MODE_MODIFY,
                .sta_id = mvmsta->sta_id,
                .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
@@ -1538,7 +1423,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
                cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD);
        }
 
-       ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
index 2ed84c421481c79dfa1e847b1940ac78da8a9d9c..e5e3071ff2523a41d45283bec1a3106ac28e8c0b 100644 (file)
@@ -253,6 +253,8 @@ enum iwl_mvm_agg_state {
  *     This is basically (last acked packet++).
  * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
  *     Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
+ * @reduced_tpc: Reduced tx power. Holds the data between the
+ *     Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
  * @state: state of the BA agreement establishment / tear down.
  * @txq_id: Tx queue used by the BA session
  * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
@@ -265,6 +267,7 @@ struct iwl_mvm_tid_data {
        u16 next_reclaimed;
        /* The rest is Tx AGG related */
        u32 rate_n_flags;
+       u8 reduced_tpc;
        enum iwl_mvm_agg_state state;
        u16 txq_id;
        u16 ssn;
index 61331245ad9324f29ec5a86f12a3239725619673..a9402937f767a3492cb3783e0aee5848d3aa867c 100644 (file)
@@ -273,67 +273,10 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
        return true;
 }
 
-/* used to convert from time event API v2 to v1 */
-#define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\
-                            TE_V2_EVENT_SOCIOPATHIC)
-static inline u16 te_v2_get_notify(__le16 policy)
-{
-       return le16_to_cpu(policy) & TE_V2_NOTIF_MSK;
-}
-
-static inline u16 te_v2_get_dep_policy(__le16 policy)
-{
-       return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >>
-               TE_V2_PLACEMENT_POS;
-}
-
-static inline u16 te_v2_get_absence(__le16 policy)
-{
-       return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS;
-}
-
-static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2,
-                               struct iwl_time_event_cmd_v1 *cmd_v1)
-{
-       cmd_v1->id_and_color = cmd_v2->id_and_color;
-       cmd_v1->action = cmd_v2->action;
-       cmd_v1->id = cmd_v2->id;
-       cmd_v1->apply_time = cmd_v2->apply_time;
-       cmd_v1->max_delay = cmd_v2->max_delay;
-       cmd_v1->depends_on = cmd_v2->depends_on;
-       cmd_v1->interval = cmd_v2->interval;
-       cmd_v1->duration = cmd_v2->duration;
-       if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS)
-               cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS);
-       else
-               cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat);
-       cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags);
-       cmd_v1->interval_reciprocal = 0; /* unused */
-
-       cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy));
-       cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy));
-       cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy));
-}
-
-static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm,
-                                      const struct iwl_time_event_cmd_v2 *cmd)
-{
-       struct iwl_time_event_cmd_v1 cmd_v1;
-
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2)
-               return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
-                                           sizeof(*cmd), cmd);
-
-       iwl_mvm_te_v2_to_v1(cmd, &cmd_v1);
-       return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
-                                   sizeof(cmd_v1), &cmd_v1);
-}
-
-
 static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
                                       struct ieee80211_vif *vif,
                                       struct iwl_mvm_time_event_data *te_data,
-                                      struct iwl_time_event_cmd_v2 *te_cmd)
+                                      struct iwl_time_event_cmd *te_cmd)
 {
        static const u8 time_event_response[] = { TIME_EVENT_CMD };
        struct iwl_notification_wait wait_time_event;
@@ -369,7 +312,8 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
                                   ARRAY_SIZE(time_event_response),
                                   iwl_mvm_time_event_response, te_data);
 
-       ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+                                           sizeof(*te_cmd), te_cmd);
        if (ret) {
                IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
@@ -397,7 +341,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
-       struct iwl_time_event_cmd_v2 time_cmd = {};
+       struct iwl_time_event_cmd time_cmd = {};
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -453,7 +397,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
                               struct iwl_mvm_vif *mvmvif,
                               struct iwl_mvm_time_event_data *te_data)
 {
-       struct iwl_time_event_cmd_v2 time_cmd = {};
+       struct iwl_time_event_cmd time_cmd = {};
        u32 id, uid;
        int ret;
 
@@ -490,7 +434,8 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
                cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
 
        IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
-       ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+                                  sizeof(time_cmd), &time_cmd);
        if (WARN_ON(ret))
                return;
 }
@@ -510,7 +455,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
-       struct iwl_time_event_cmd_v2 time_cmd = {};
+       struct iwl_time_event_cmd time_cmd = {};
 
        lockdep_assert_held(&mvm->mutex);
        if (te_data->running) {
index 7a99fa361954e0bc1d5e9e82bf94130b0692ac6f..39a3e03a0acdcc6aa594279906613b6fb53fa343 100644 (file)
@@ -468,13 +468,14 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
        }
 
        if (params->support_tx_backoff) {
-               tx_backoff = 0;
+               tx_backoff = tt->min_backoff;
                for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) {
                        if (temperature < params->tx_backoff[i].temperature)
                                break;
-                       tx_backoff = params->tx_backoff[i].backoff;
+                       tx_backoff = max(tt->min_backoff,
+                                        params->tx_backoff[i].backoff);
                }
-               if (tx_backoff != 0)
+               if (tx_backoff != tt->min_backoff)
                        throttle_enable = true;
                if (tt->tx_backoff != tx_backoff)
                        iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
@@ -484,7 +485,8 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
                IWL_WARN(mvm,
                         "Due to high temperature thermal throttling initiated\n");
                tt->throttle = true;
-       } else if (tt->throttle && !tt->dynamic_smps && tt->tx_backoff == 0 &&
+       } else if (tt->throttle && !tt->dynamic_smps &&
+                  tt->tx_backoff == tt->min_backoff &&
                   temperature <= params->tx_protection_exit) {
                IWL_WARN(mvm,
                         "Temperature is back to normal thermal throttling stopped\n");
index 879aeac46cc103112fef914bcc2b38df9f028b06..ff1b630e130eed5ab07a2bbcb222088df410d557 100644 (file)
@@ -636,7 +636,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                        seq_ctl = le16_to_cpu(hdr->seq_ctrl);
                }
 
-               ieee80211_tx_status_ni(mvm->hw, skb);
+               BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1);
+               info->status.status_driver_data[0] =
+                               (void *)(uintptr_t)tx_resp->reduced_tpc;
+
+               ieee80211_tx_status(mvm->hw, skb);
        }
 
        if (txq_id >= mvm->first_agg_queue) {
@@ -815,6 +819,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
                struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
                mvmsta->tid_data[tid].rate_n_flags =
                        le32_to_cpu(tx_resp->initial_rate);
+               mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc;
        }
 
        rcu_read_unlock();
@@ -928,6 +933,8 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                        info->status.ampdu_len = ba_notif->txed;
                        iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
                                                    info);
+                       info->status.status_driver_data[0] =
+                               (void *)(uintptr_t)tid_data->reduced_tpc;
                }
        }
 
@@ -937,7 +944,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 
        while (!skb_queue_empty(&reclaimed_skbs)) {
                skb = __skb_dequeue(&reclaimed_skbs);
-               ieee80211_tx_status_ni(mvm->hw, skb);
+               ieee80211_tx_status(mvm->hw, skb);
        }
 
        return 0;
index d619851745a19ba6d3bf605555fcdbd5a09f8341..c5f4532cafa94e4eaf3c454a34fa3597da1a66b1 100644 (file)
@@ -64,6 +64,7 @@
 
 #include "iwl-debug.h"
 #include "iwl-io.h"
+#include "iwl-prph.h"
 
 #include "mvm.h"
 #include "fw-api-rs.h"
@@ -469,6 +470,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
                        mvm->status, table.valid);
        }
 
+       /* Do not change this output - scripts rely on it */
+
        IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
 
        trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
@@ -522,7 +525,7 @@ void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm)
        u32 ofs, sram_len;
        void *sram;
 
-       if (!mvm->ucode_loaded || mvm->fw_error_sram)
+       if (!mvm->ucode_loaded || mvm->fw_error_sram || mvm->fw_error_dump)
                return;
 
        img = &mvm->fw->img[mvm->cur_ucode];
@@ -538,6 +541,47 @@ void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm)
        mvm->fw_error_sram_len = sram_len;
 }
 
+void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm)
+{
+       int i, reg_val;
+       unsigned long flags;
+
+       if (!mvm->ucode_loaded || mvm->fw_error_rxf || mvm->fw_error_dump)
+               return;
+
+       /* reading buffer size */
+       reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR);
+       mvm->fw_error_rxf_len =
+               (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS;
+
+       /* the register holds the value divided by 128 */
+       mvm->fw_error_rxf_len = mvm->fw_error_rxf_len << 7;
+
+       if (!mvm->fw_error_rxf_len)
+               return;
+
+       mvm->fw_error_rxf =  kzalloc(mvm->fw_error_rxf_len, GFP_ATOMIC);
+       if (!mvm->fw_error_rxf) {
+               mvm->fw_error_rxf_len = 0;
+               return;
+       }
+
+       if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) {
+               kfree(mvm->fw_error_rxf);
+               mvm->fw_error_rxf = NULL;
+               mvm->fw_error_rxf_len = 0;
+               return;
+       }
+
+       for (i = 0; i < (mvm->fw_error_rxf_len / sizeof(u32)); i++) {
+               iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR,
+                                    i * sizeof(u32));
+               mvm->fw_error_rxf[i] =
+                       iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_ADDR);
+       }
+       iwl_trans_release_nic_access(mvm->trans, &flags);
+}
+
 /**
  * iwl_mvm_send_lq_cmd() - Send link quality command
  * @init: This command is sent as part of station initialization right
index 9091513ea7388ce11f2294fbb609b3581073e2a0..1b95d856dfd53b7c29bd39fe1060c706b6816a91 100644 (file)
@@ -102,7 +102,7 @@ struct iwl_rxq {
        u32 write_actual;
        struct list_head rx_free;
        struct list_head rx_used;
-       int need_update;
+       bool need_update;
        struct iwl_rb_status *rb_stts;
        dma_addr_t rb_stts_dma;
        spinlock_t lock;
@@ -231,7 +231,7 @@ struct iwl_txq {
        spinlock_t lock;
        struct timer_list stuck_timer;
        struct iwl_trans_pcie *trans_pcie;
-       u8 need_update;
+       bool need_update;
        u8 active;
        bool ampdu;
 };
@@ -270,6 +270,9 @@ struct iwl_trans_pcie {
        struct iwl_trans *trans;
        struct iwl_drv *drv;
 
+       struct net_device napi_dev;
+       struct napi_struct napi;
+
        /* INT ICT Table */
        __le32 *ict_tbl;
        dma_addr_t ict_tbl_dma;
@@ -362,7 +365,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
 void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
 int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                      struct iwl_device_cmd *dev_cmd, int txq_id);
-void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq);
+void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);
 int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                            struct iwl_rx_cmd_buffer *rxb, int handler_status);
index fdfa3969cac986c1824bd65c41512a9ac4ba7b39..4a26a082a1ba1bf27b8da9a183b4f10e9804a511 100644 (file)
@@ -145,15 +145,13 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans)
 /*
  * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue
  */
-static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
-                                   struct iwl_rxq *rxq)
+static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
        u32 reg;
 
-       spin_lock(&rxq->lock);
-
-       if (rxq->need_update == 0)
-               goto exit_unlock;
+       lockdep_assert_held(&rxq->lock);
 
        /*
         * explicitly wake up the NIC if:
@@ -169,13 +167,27 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
                                       reg);
                        iwl_set_bit(trans, CSR_GP_CNTRL,
                                    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                       goto exit_unlock;
+                       rxq->need_update = true;
+                       return;
                }
        }
 
        rxq->write_actual = round_down(rxq->write, 8);
        iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
-       rxq->need_update = 0;
+}
+
+static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
+
+       spin_lock(&rxq->lock);
+
+       if (!rxq->need_update)
+               goto exit_unlock;
+
+       iwl_pcie_rxq_inc_wr_ptr(trans);
+       rxq->need_update = false;
 
  exit_unlock:
        spin_unlock(&rxq->lock);
@@ -236,9 +248,8 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
         * Increment device's write pointer in multiples of 8. */
        if (rxq->write_actual != (rxq->write & ~0x7)) {
                spin_lock(&rxq->lock);
-               rxq->need_update = 1;
+               iwl_pcie_rxq_inc_wr_ptr(trans);
                spin_unlock(&rxq->lock);
-               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
        }
 }
 
@@ -362,20 +373,9 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
  * Also restock the Rx queue via iwl_pcie_rxq_restock.
  * This is called as a scheduled work item (except for during initialization)
  */
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);
-
-       spin_lock(&trans_pcie->irq_lock);
-       iwl_pcie_rxq_restock(trans);
-       spin_unlock(&trans_pcie->irq_lock);
-}
-
-static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans)
+static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp)
 {
-       iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC);
+       iwl_pcie_rxq_alloc_rbs(trans, gfp);
 
        iwl_pcie_rxq_restock(trans);
 }
@@ -385,7 +385,7 @@ static void iwl_pcie_rx_replenish_work(struct work_struct *data)
        struct iwl_trans_pcie *trans_pcie =
            container_of(data, struct iwl_trans_pcie, rx_replenish);
 
-       iwl_pcie_rx_replenish(trans_pcie->trans);
+       iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL);
 }
 
 static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
@@ -521,14 +521,13 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
        spin_unlock(&rxq->lock);
 
-       iwl_pcie_rx_replenish(trans);
+       iwl_pcie_rx_replenish(trans, GFP_KERNEL);
 
        iwl_pcie_rx_hw_init(trans, rxq);
 
-       spin_lock(&trans_pcie->irq_lock);
-       rxq->need_update = 1;
-       iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
-       spin_unlock(&trans_pcie->irq_lock);
+       spin_lock(&rxq->lock);
+       iwl_pcie_rxq_inc_wr_ptr(trans);
+       spin_unlock(&rxq->lock);
 
        return 0;
 }
@@ -673,7 +672,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
        /* Reuse the page if possible. For notification packets and
         * SKBs that fail to Rx correctly, add them back into the
         * rx_free list for reuse later. */
-       spin_lock(&rxq->lock);
        if (rxb->page != NULL) {
                rxb->page_dma =
                        dma_map_page(trans->dev, rxb->page, 0,
@@ -694,7 +692,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                }
        } else
                list_add_tail(&rxb->list, &rxq->rx_used);
-       spin_unlock(&rxq->lock);
 }
 
 /*
@@ -709,6 +706,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)
        u32 count = 8;
        int total_empty;
 
+restart:
+       spin_lock(&rxq->lock);
        /* uCode's read index (stored in shared DRAM) indicates the last Rx
         * buffer that the driver may process (last buffer filled by ucode). */
        r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
@@ -743,18 +742,25 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)
                        count++;
                        if (count >= 8) {
                                rxq->read = i;
-                               iwl_pcie_rx_replenish_now(trans);
+                               spin_unlock(&rxq->lock);
+                               iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
                                count = 0;
+                               goto restart;
                        }
                }
        }
 
        /* Backtrack one entry */
        rxq->read = i;
+       spin_unlock(&rxq->lock);
+
        if (fill_rx)
-               iwl_pcie_rx_replenish_now(trans);
+               iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
        else
                iwl_pcie_rxq_restock(trans);
+
+       if (trans_pcie->napi.poll)
+               napi_gro_flush(&trans_pcie->napi, false);
 }
 
 /*
@@ -876,7 +882,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
        struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
        u32 inta = 0;
        u32 handled = 0;
-       u32 i;
 
        lock_map_acquire(&trans->sync_cmd_lockdep_map);
 
@@ -1028,9 +1033,8 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
        /* uCode wakes up after power-down sleep */
        if (inta & CSR_INT_BIT_WAKEUP) {
                IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
-               iwl_pcie_rxq_inc_wr_ptr(trans, &trans_pcie->rxq);
-               for (i = 0; i < trans->cfg->base_params->num_of_queues; i++)
-                       iwl_pcie_txq_inc_wr_ptr(trans, &trans_pcie->txq[i]);
+               iwl_pcie_rxq_check_wrptr(trans);
+               iwl_pcie_txq_check_wrptrs(trans);
 
                isr_stats->wakeup++;
 
@@ -1068,8 +1072,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                iwl_write8(trans, CSR_INT_PERIODIC_REG,
                            CSR_INT_PERIODIC_DIS);
 
-               iwl_pcie_rx_handle(trans);
-
                /*
                 * Enable periodic interrupt in 8 msec only if we received
                 * real RX interrupt (instead of just periodic int), to catch
@@ -1082,6 +1084,10 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                                   CSR_INT_PERIODIC_ENA);
 
                isr_stats->rx++;
+
+               local_bh_disable();
+               iwl_pcie_rx_handle(trans);
+               local_bh_enable();
        }
 
        /* This "Tx" DMA channel is used only for loading uCode */
index dcfd6d866d095081d7001795c4ec802c3044926f..f98ef1e62eb9795fad48ea56d7251f5f658ef5cd 100644 (file)
@@ -103,7 +103,6 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 
 /* PCI registers */
 #define PCI_CFG_RETRY_TIMEOUT  0x041
-#define CPU1_CPU2_SEPARATOR_SECTION    0xFFFFCCCC
 
 static void iwl_pcie_apm_config(struct iwl_trans *trans)
 {
@@ -1053,6 +1052,12 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
        iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
 }
 
+static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
+{
+       WARN_ON(1);
+       return 0;
+}
+
 static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                                     const struct iwl_trans_config *trans_cfg)
 {
@@ -1079,6 +1084,18 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
 
        trans_pcie->command_names = trans_cfg->command_names;
        trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
+
+       /* Initialize NAPI here - it should be before registering to mac80211
+        * in the opmode but after the HW struct is allocated.
+        * As this function may be called again in some corner cases don't
+        * do anything if NAPI was already initialized.
+        */
+       if (!trans_pcie->napi.poll && trans->op_mode->ops->napi_add) {
+               init_dummy_netdev(&trans_pcie->napi_dev);
+               iwl_op_mode_napi_add(trans->op_mode, &trans_pcie->napi,
+                                    &trans_pcie->napi_dev,
+                                    iwl_pcie_dummy_napi_poll, 64);
+       }
 }
 
 void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1099,6 +1116,9 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
        pci_disable_device(trans_pcie->pci_dev);
        kmem_cache_destroy(trans->dev_cmd_pool);
 
+       if (trans_pcie->napi.poll)
+               netif_napi_del(&trans_pcie->napi);
+
        kfree(trans);
 }
 
@@ -1237,7 +1257,7 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
 
 #define IWL_FLUSH_WAIT_MS      2000
 
-static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
+static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_txq *txq;
@@ -1250,13 +1270,31 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
 
        /* waiting for all the tx frames complete might take a while */
        for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+               u8 wr_ptr;
+
                if (cnt == trans_pcie->cmd_queue)
                        continue;
+               if (!test_bit(cnt, trans_pcie->queue_used))
+                       continue;
+               if (!(BIT(cnt) & txq_bm))
+                       continue;
+
+               IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt);
                txq = &trans_pcie->txq[cnt];
                q = &txq->q;
-               while (q->read_ptr != q->write_ptr && !time_after(jiffies,
-                      now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
+               wr_ptr = ACCESS_ONCE(q->write_ptr);
+
+               while (q->read_ptr != ACCESS_ONCE(q->write_ptr) &&
+                      !time_after(jiffies,
+                                  now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) {
+                       u8 write_ptr = ACCESS_ONCE(q->write_ptr);
+
+                       if (WARN_ONCE(wr_ptr != write_ptr,
+                                     "WR pointer moved while flushing %d -> %d\n",
+                                     wr_ptr, write_ptr))
+                               return -ETIMEDOUT;
                        msleep(1);
+               }
 
                if (q->read_ptr != q->write_ptr) {
                        IWL_ERR(trans,
@@ -1264,6 +1302,7 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
                        ret = -ETIMEDOUT;
                        break;
                }
+               IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt);
        }
 
        if (!ret)
index 3b0c72c1005446d2d93f7eb15ed6d3207e1c3ea1..dde6031f4257f0b3a8fd8d46e5d5fe712f3a4ea0 100644 (file)
@@ -287,14 +287,14 @@ static void iwl_pcie_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
 /*
  * iwl_pcie_txq_inc_wr_ptr - Send new write index to hardware
  */
-void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
+static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans,
+                                   struct iwl_txq *txq)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 reg = 0;
        int txq_id = txq->q.id;
 
-       if (txq->need_update == 0)
-               return;
+       lockdep_assert_held(&txq->lock);
 
        /*
         * explicitly wake up the NIC if:
@@ -317,6 +317,7 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
                                       txq_id, reg);
                        iwl_set_bit(trans, CSR_GP_CNTRL,
                                    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       txq->need_update = true;
                        return;
                }
        }
@@ -327,8 +328,23 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
         */
        IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr);
        iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8));
+}
+
+void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int i;
 
-       txq->need_update = 0;
+       for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
+               struct iwl_txq *txq = &trans_pcie->txq[i];
+
+               spin_lock(&txq->lock);
+               if (trans_pcie->txq[i].need_update) {
+                       iwl_pcie_txq_inc_wr_ptr(trans, txq);
+                       trans_pcie->txq[i].need_update = false;
+               }
+               spin_unlock(&txq->lock);
+       }
 }
 
 static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
@@ -542,7 +558,7 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
 {
        int ret;
 
-       txq->need_update = 0;
+       txq->need_update = false;
 
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
         * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
@@ -680,7 +696,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
        /* The chain extension of the SCD doesn't work well. This feature is
         * enabled by default by the HW, so we need to disable it manually.
         */
-       iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
+       if (trans->cfg->base_params->scd_chain_ext_wa)
+               iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
 
        iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue,
                                trans_pcie->cmd_fifo);
@@ -1028,7 +1045,8 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
                }
        }
 
-       if (q->read_ptr == q->write_ptr) {
+       if (trans->cfg->base_params->apmg_wake_up_wa &&
+           q->read_ptr == q->write_ptr) {
                spin_lock_irqsave(&trans_pcie->reg_lock, flags);
                WARN_ON(!trans_pcie->cmd_in_flight);
                trans_pcie->cmd_in_flight = false;
@@ -1392,8 +1410,6 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
                kfree(txq->entries[idx].free_buf);
        txq->entries[idx].free_buf = dup_buf;
 
-       txq->need_update = 1;
-
        trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
 
        /* start timer if queue currently empty */
@@ -1405,9 +1421,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
        /*
         * wake up the NIC to make sure that the firmware will see the host
         * command - we will let the NIC sleep once all the host commands
-        * returned.
+        * returned. This needs to be done only on NICs that have
+        * apmg_wake_up_wa set.
         */
-       if (!trans_pcie->cmd_in_flight) {
+       if (trans->cfg->base_params->apmg_wake_up_wa &&
+           !trans_pcie->cmd_in_flight) {
                trans_pcie->cmd_in_flight = true;
                __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
                                         CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -1661,7 +1679,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        dma_addr_t tb0_phys, tb1_phys, scratch_phys;
        void *tb1_addr;
        u16 len, tb1_len, tb2_len;
-       u8 wait_write_ptr = 0;
+       bool wait_write_ptr;
        __le16 fc = hdr->frame_control;
        u8 hdr_len = ieee80211_hdrlen(fc);
        u16 wifi_seq;
@@ -1762,12 +1780,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        trace_iwlwifi_dev_tx_data(trans->dev, skb,
                                  skb->data + hdr_len, tb2_len);
 
-       if (!ieee80211_has_morefrags(fc)) {
-               txq->need_update = 1;
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
+       wait_write_ptr = ieee80211_has_morefrags(fc);
 
        /* start timer if queue currently empty */
        if (txq->need_update && q->read_ptr == q->write_ptr &&
@@ -1776,21 +1789,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
        /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_pcie_txq_inc_wr_ptr(trans, txq);
+       if (!wait_write_ptr)
+               iwl_pcie_txq_inc_wr_ptr(trans, txq);
 
        /*
         * At this point the frame is "transmitted" successfully
-        * and we will get a TX status notification eventually,
-        * regardless of the value of ret. "ret" only indicates
-        * whether or not we should update the write pointer.
+        * and we will get a TX status notification eventually.
         */
        if (iwl_queue_space(q) < q->high_mark) {
-               if (wait_write_ptr) {
-                       txq->need_update = 1;
+               if (wait_write_ptr)
                        iwl_pcie_txq_inc_wr_ptr(trans, txq);
-               } else {
+               else
                        iwl_stop_queue(trans, txq);
-               }
        }
        spin_unlock(&txq->lock);
        return 0;
index 9d7a52f5a4102abedd2dbebc03c26c3866da2a64..a312c653d1163fcc5c4ff394a54b0c7a96370d8f 100644 (file)
@@ -1676,7 +1676,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
        return 0;
 }
 
-static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                u32 queues, bool drop)
 {
        /* Not implemented, queues only on kernel side */
 }
@@ -2056,6 +2058,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                            WIPHY_FLAG_AP_UAPSD |
                            WIPHY_FLAG_HAS_CHANNEL_SWITCH;
        hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+       hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
 
        /* ask mac80211 to reserve space for magic */
        hw->vif_data_size = sizeof(struct hwsim_vif_priv);
index c92f27aa71ede1f049c101a0ba185f31d982aaa3..706831df1fa2a4183cb3c5ad849f1aa8df8dbb14 100644 (file)
@@ -212,8 +212,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
                                      sizeof(struct mwifiex_ie_types_header));
                        memcpy((u8 *)vht_op +
                                sizeof(struct mwifiex_ie_types_header),
-                              (u8 *)bss_desc->bcn_vht_oper +
-                              sizeof(struct ieee_types_header),
+                              (u8 *)bss_desc->bcn_vht_oper,
                               le16_to_cpu(vht_op->header.len));
 
                        /* negotiate the channel width and central freq
index d14ead8beca860dba6c984d26df095b104bb1375..2bd07d681c5e7fbedfacd35e9bcad038fcf56970 100644 (file)
@@ -345,8 +345,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 
                        memcpy((u8 *) ht_info +
                               sizeof(struct mwifiex_ie_types_header),
-                              (u8 *) bss_desc->bcn_ht_oper +
-                              sizeof(struct ieee_types_header),
+                              (u8 *)bss_desc->bcn_ht_oper,
                               le16_to_cpu(ht_info->header.len));
 
                        if (!(sband->ht_cap.cap &
index 63211707f93955c851bfb96d71f12d5ef1f4a313..860dfe71cf965b0b7e2033d1eb5a07702f6ef57c 100644 (file)
@@ -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;
+       struct timeval tv;
        int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN;
 
        skb_src = skb_peek(&pra_list->skb_head);
@@ -184,6 +185,9 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
        tx_info_aggr->bss_num = tx_info_src->bss_num;
        skb_aggr->priority = skb_src->priority;
 
+       do_gettimeofday(&tv);
+       skb_aggr->tstamp = timeval_to_ktime(tv);
+
        do {
                /* Check if AMSDU can accommodate this MSDU */
                if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN))
@@ -236,18 +240,11 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA,
                                                   skb_aggr, NULL);
        } else {
-               /*
-                * Padding per MSDU will affect the length of next
-                * packet and hence the exact length of next packet
-                * is uncertain here.
-                *
-                * Also, aggregation of transmission buffer, while
-                * downloading the data to the card, wont gain much
-                * on the AMSDU packets as the AMSDU packets utilizes
-                * the transmission buffer space to the maximum
-                * (adapter->tx_buf_size).
-                */
-               tx_param.next_pkt_len = 0;
+               if (skb_src)
+                       tx_param.next_pkt_len =
+                                       skb_src->len + sizeof(struct txpd);
+               else
+                       tx_param.next_pkt_len = 0;
 
                ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
                                                   skb_aggr, &tx_param);
index b9242c3dca435ee9a4d5123fd57ad0733a96a24d..3b55ce5690a54e226c5482f523a3c80d1e95d7bf 100644 (file)
@@ -200,4 +200,11 @@ getlog
 
        cat getlog
 
+fw_dump
+       This command is used to dump firmware memory into files.
+       Separate file will be created for each memory segment.
+       Usage:
+
+       cat fw_dump
+
 ===============================================================================
index 1062c918a7bffb19cf93c1aba0daa4490856ba65..8dee6c86f4f1dc91e65978b6f7443ac9f00c2118 100644 (file)
@@ -955,8 +955,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
                        adapter->cmd_wait_q.status = -ETIMEDOUT;
                        wake_up_interruptible(&adapter->cmd_wait_q.wait);
                        mwifiex_cancel_pending_ioctl(adapter);
-                       /* reset cmd_sent flag to unblock new commands */
-                       adapter->cmd_sent = false;
                }
        }
        if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
index b8a49aad12fd662434ce2a29aaa8edecfb52ba0b..7b419bbcd5444f5c5abdf40ffb2368087b77e89a 100644 (file)
@@ -256,6 +256,29 @@ free_and_exit:
        return ret;
 }
 
+/*
+ * Proc firmware dump read handler.
+ *
+ * This function is called when the 'fw_dump' file is opened for
+ * reading.
+ * This function dumps firmware memory in different files
+ * (ex. DTCM, ITCM, SQRAM etc.) based on the the segments for
+ * debugging.
+ */
+static ssize_t
+mwifiex_fw_dump_read(struct file *file, char __user *ubuf,
+                    size_t count, loff_t *ppos)
+{
+       struct mwifiex_private *priv = file->private_data;
+
+       if (!priv->adapter->if_ops.fw_dump)
+               return -EIO;
+
+       priv->adapter->if_ops.fw_dump(priv->adapter);
+
+       return 0;
+}
+
 /*
  * Proc getlog file read handler.
  *
@@ -699,6 +722,7 @@ static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 MWIFIEX_DFS_FILE_READ_OPS(info);
 MWIFIEX_DFS_FILE_READ_OPS(debug);
 MWIFIEX_DFS_FILE_READ_OPS(getlog);
+MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
 MWIFIEX_DFS_FILE_OPS(regrdwr);
 MWIFIEX_DFS_FILE_OPS(rdeeprom);
 
@@ -722,6 +746,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
        MWIFIEX_DFS_ADD_FILE(getlog);
        MWIFIEX_DFS_ADD_FILE(regrdwr);
        MWIFIEX_DFS_ADD_FILE(rdeeprom);
+       MWIFIEX_DFS_ADD_FILE(fw_dump);
 }
 
 /*
index e7b3e16e5d34f1f8703ec2f6d4e21e9388c49edd..38da6ff6f41623618efa22add335ffef1fa46828 100644 (file)
 #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED      2
 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED      16
 
-#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE        16
-#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE        32
+#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE        64
+#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE        64
 #define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE        32
 #define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE        16
-#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE   32
-#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE   48
+#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE   64
+#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE   64
 #define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE   48
 #define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE   32
 
index ee494db5406097c35a0f22b365e2ad2e1ac674f8..1b576722671d5e6f228363c36c94c4ef47867980 100644 (file)
@@ -303,7 +303,7 @@ struct mwifiex_ds_ant_cfg {
        u32 rx_ant;
 };
 
-#define MWIFIEX_NUM_OF_CMD_BUFFER      20
+#define MWIFIEX_NUM_OF_CMD_BUFFER      50
 #define MWIFIEX_SIZE_OF_CMD_BUFFER     2048
 
 enum {
index 9c771b3e99186ffe838f771b217216ebc5a43454..cbabc12fbda390d063218375eb2b4cadc3911b8f 100644 (file)
@@ -521,7 +521,6 @@ done:
                release_firmware(adapter->firmware);
                adapter->firmware = NULL;
        }
-       complete(&adapter->fw_load);
        if (init_failed)
                mwifiex_free_adapter(adapter);
        up(sem);
@@ -535,7 +534,6 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
 {
        int ret;
 
-       init_completion(&adapter->fw_load);
        ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
                                      adapter->dev, GFP_KERNEL, adapter,
                                      mwifiex_fw_dpc);
index d53e1e8c9467a62663c4d28df86e623237cdc45f..34181192a666b71a759cfd65c6e3c30c2eb1ca38 100644 (file)
@@ -672,6 +672,7 @@ struct mwifiex_if_ops {
        int (*init_fw_port) (struct mwifiex_adapter *);
        int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
        void (*card_reset) (struct mwifiex_adapter *);
+       void (*fw_dump)(struct mwifiex_adapter *);
        int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
 };
 
@@ -787,7 +788,6 @@ struct mwifiex_adapter {
        struct mwifiex_wait_queue cmd_wait_q;
        u8 scan_wait_q_woken;
        spinlock_t queue_lock;          /* lock for tx queues */
-       struct completion fw_load;
        u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
        u16 max_mgmt_ie_index;
        u8 scan_delay_cnt;
index a7e8b96b2d9024de8c34e5e04b317c66d2e22820..c2cfeec466d87b40811515bec11be698943a4f55 100644 (file)
@@ -221,9 +221,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        if (!adapter || !adapter->priv_num)
                return;
 
-       /* In case driver is removed when asynchronous FW load is in progress */
-       wait_for_completion(&adapter->fw_load);
-
        if (user_rmmod) {
 #ifdef CONFIG_PM_SLEEP
                if (adapter->is_suspended)
index 7b3af3d29ded478ad658eed5a3836403d6dd7542..d75f4ebd4bdce7767c797fe28c9fd3f9eb4fa2a9 100644 (file)
@@ -29,9 +29,6 @@
 #define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
 
 #define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD      4
-#define MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD   15
-#define MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD  27
-#define MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD  35
 
 /* Memory needed to store a max sized Channel List TLV for a firmware scan */
 #define CHAN_TLV_MAX_SIZE  (sizeof(struct mwifiex_ie_types_header)         \
@@ -1055,20 +1052,10 @@ mwifiex_config_scan(struct mwifiex_private *priv,
 
        /*
         * In associated state we will reduce the number of channels scanned per
-        * scan command to avoid any traffic delay/loss. This number is decided
-        * based on total number of channels to be scanned due to constraints
-        * of command buffers.
+        * scan command to 1 to avoid any traffic delay/loss.
         */
-       if (priv->media_connected) {
-               if (chan_num < MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD)
+       if (priv->media_connected)
                        *max_chan_per_scan = 1;
-               else if (chan_num < MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD)
-                       *max_chan_per_scan = 2;
-               else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
-                       *max_chan_per_scan = 3;
-               else
-                       *max_chan_per_scan = 4;
-       }
 }
 
 /*
@@ -1353,23 +1340,17 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                                              bss_entry->beacon_buf);
                        break;
                case WLAN_EID_BSS_COEX_2040:
-                       bss_entry->bcn_bss_co_2040 = current_ptr +
-                               sizeof(struct ieee_types_header);
-                       bss_entry->bss_co_2040_offset = (u16) (current_ptr +
-                                       sizeof(struct ieee_types_header) -
-                                               bss_entry->beacon_buf);
+                       bss_entry->bcn_bss_co_2040 = current_ptr;
+                       bss_entry->bss_co_2040_offset =
+                               (u16) (current_ptr - bss_entry->beacon_buf);
                        break;
                case WLAN_EID_EXT_CAPABILITY:
-                       bss_entry->bcn_ext_cap = current_ptr +
-                               sizeof(struct ieee_types_header);
-                       bss_entry->ext_cap_offset = (u16) (current_ptr +
-                                       sizeof(struct ieee_types_header) -
-                                       bss_entry->beacon_buf);
+                       bss_entry->bcn_ext_cap = current_ptr;
+                       bss_entry->ext_cap_offset =
+                               (u16) (current_ptr - bss_entry->beacon_buf);
                        break;
                case WLAN_EID_OPMODE_NOTIF:
-                       bss_entry->oper_mode =
-                               (void *)(current_ptr +
-                                        sizeof(struct ieee_types_header));
+                       bss_entry->oper_mode = (void *)current_ptr;
                        bss_entry->oper_mode_offset =
                                        (u16)((u8 *)bss_entry->oper_mode -
                                              bss_entry->beacon_buf);
index d206f04d499498d6d9c7ba92a80685588ae7bc96..a1773d3cb49f4805503ba8f9c104f685ae7114b4 100644 (file)
@@ -85,6 +85,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
                card->supports_sdio_new_mode = data->supports_sdio_new_mode;
                card->has_control_mask = data->has_control_mask;
                card->tx_buf_size = data->tx_buf_size;
+               card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size;
+               card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;
        }
 
        sdio_claim_host(func);
@@ -177,9 +179,6 @@ mwifiex_sdio_remove(struct sdio_func *func)
        if (!adapter || !adapter->priv_num)
                return;
 
-       /* In case driver is removed when asynchronous FW load is in progress */
-       wait_for_completion(&adapter->fw_load);
-
        if (user_rmmod) {
                if (adapter->is_suspended)
                        mwifiex_sdio_resume(adapter->dev);
@@ -1842,8 +1841,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) *
                                       card->mp_agg_pkt_limit, GFP_KERNEL);
        ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
-                                            SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
-                                            SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
+                                            card->mp_tx_agg_buf_size,
+                                            card->mp_rx_agg_buf_size);
        if (ret) {
                dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
                kfree(card->mp_regs);
index c71201b2e2a333c20f926bacb4842395230c6926..6eea30b43ed714f3bd81f9453a5008001a11b33d 100644 (file)
 #define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U)
 #define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U)
 
-#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE        (8192)     /* 8K */
-
-/* Multi port RX aggregation buffer size */
-#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE        (16384)    /* 16K */
+#define MWIFIEX_MP_AGGR_BUF_SIZE_16K   (16384)
+#define MWIFIEX_MP_AGGR_BUF_SIZE_32K   (32768)
 
 /* Misc. Config Register : Auto Re-enable interrupts */
 #define AUTO_RE_ENABLE_INT              BIT(4)
@@ -234,6 +232,8 @@ struct sdio_mmc_card {
        bool supports_sdio_new_mode;
        bool has_control_mask;
        u16 tx_buf_size;
+       u32 mp_tx_agg_buf_size;
+       u32 mp_rx_agg_buf_size;
 
        u32 mp_rd_bitmap;
        u32 mp_wr_bitmap;
@@ -258,6 +258,8 @@ struct mwifiex_sdio_device {
        bool supports_sdio_new_mode;
        bool has_control_mask;
        u16 tx_buf_size;
+       u32 mp_tx_agg_buf_size;
+       u32 mp_rx_agg_buf_size;
 };
 
 static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
@@ -315,6 +317,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
        .supports_sdio_new_mode = false,
        .has_control_mask = true,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
+       .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+       .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
 };
 
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -325,6 +329,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
        .supports_sdio_new_mode = false,
        .has_control_mask = true,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
+       .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+       .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
 };
 
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -335,6 +341,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
        .supports_sdio_new_mode = false,
        .has_control_mask = true,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
+       .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+       .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
 };
 
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -345,6 +353,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
        .supports_sdio_new_mode = true,
        .has_control_mask = false,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
+       .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
+       .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
 };
 
 /*
index 9be6544bddedf9371e79fd468ebb0aa2dbcabe54..32643555dd2a32a302d1301427e463d877c8260a 100644 (file)
@@ -175,17 +175,19 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
                switch (GET_RXSTBC(cap_info)) {
                case MWIFIEX_RX_STBC1:
                        /* HT_CAP 1X1 mode */
-                       memset(&bss_cfg->ht_cap.mcs, 0xff, 1);
+                       bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff;
                        break;
                case MWIFIEX_RX_STBC12: /* fall through */
                case MWIFIEX_RX_STBC123:
                        /* HT_CAP 2X2 mode */
-                       memset(&bss_cfg->ht_cap.mcs, 0xff, 2);
+                       bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff;
+                       bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff;
                        break;
                default:
                        dev_warn(priv->adapter->dev,
                                 "Unsupported RX-STBC, default to 2x2\n");
-                       memset(&bss_cfg->ht_cap.mcs, 0xff, 2);
+                       bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff;
+                       bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff;
                        break;
                }
                priv->ap_11n_enabled = 1;
index edbe4aff00d85b569534372ea34e7e017552b234..a8ce8130cfaeeda08a2a08f7b693540fe79d9f85 100644 (file)
@@ -22,9 +22,9 @@
 
 #define USB_VERSION    "1.0"
 
+static u8 user_rmmod;
 static struct mwifiex_if_ops usb_ops;
 static struct semaphore add_remove_card_sem;
-static struct usb_card_rec *usb_card;
 
 static struct usb_device_id mwifiex_usb_table[] = {
        /* 8797 */
@@ -532,28 +532,38 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
 static void mwifiex_usb_disconnect(struct usb_interface *intf)
 {
        struct usb_card_rec *card = usb_get_intfdata(intf);
+       struct mwifiex_adapter *adapter;
 
-       if (!card) {
-               pr_err("%s: card is NULL\n", __func__);
+       if (!card || !card->adapter) {
+               pr_err("%s: card or card->adapter is NULL\n", __func__);
                return;
        }
 
-       mwifiex_usb_free(card);
+       adapter = card->adapter;
+       if (!adapter->priv_num)
+               return;
 
-       if (card->adapter) {
-               struct mwifiex_adapter *adapter = card->adapter;
+       if (user_rmmod) {
+#ifdef CONFIG_PM
+               if (adapter->is_suspended)
+                       mwifiex_usb_resume(intf);
+#endif
 
-               if (!adapter->priv_num)
-                       return;
+               mwifiex_deauthenticate_all(adapter);
 
-               dev_dbg(adapter->dev, "%s: removing card\n", __func__);
-               mwifiex_remove_card(adapter, &add_remove_card_sem);
+               mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
+                                                         MWIFIEX_BSS_ROLE_ANY),
+                                        MWIFIEX_FUNC_SHUTDOWN);
        }
 
+       mwifiex_usb_free(card);
+
+       dev_dbg(adapter->dev, "%s: removing card\n", __func__);
+       mwifiex_remove_card(adapter, &add_remove_card_sem);
+
        usb_set_intfdata(intf, NULL);
        usb_put_dev(interface_to_usbdev(intf));
        kfree(card);
-       usb_card = NULL;
 
        return;
 }
@@ -565,6 +575,7 @@ static struct usb_driver mwifiex_usb_driver = {
        .id_table = mwifiex_usb_table,
        .suspend = mwifiex_usb_suspend,
        .resume = mwifiex_usb_resume,
+       .soft_unbind = 1,
 };
 
 static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
@@ -762,7 +773,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 
        card->adapter = adapter;
        adapter->dev = &card->udev->dev;
-       usb_card = card;
 
        switch (le16_to_cpu(card->udev->descriptor.idProduct)) {
        case USB8897_PID_1:
@@ -1025,25 +1035,8 @@ static void mwifiex_usb_cleanup_module(void)
        if (!down_interruptible(&add_remove_card_sem))
                up(&add_remove_card_sem);
 
-       if (usb_card && usb_card->adapter) {
-               struct mwifiex_adapter *adapter = usb_card->adapter;
-
-               /* In case driver is removed when asynchronous FW downloading is
-                * in progress
-                */
-               wait_for_completion(&adapter->fw_load);
-
-#ifdef CONFIG_PM
-               if (adapter->is_suspended)
-                       mwifiex_usb_resume(usb_card->intf);
-#endif
-
-               mwifiex_deauthenticate_all(adapter);
-
-               mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
-                                                         MWIFIEX_BSS_ROLE_ANY),
-                                        MWIFIEX_FUNC_SHUTDOWN);
-       }
+       /* set the flag as user is removing this module */
+       user_rmmod = 1;
 
        usb_deregister(&mwifiex_usb_driver);
 }
index 0a7cc742aed71e0fd31267305be7a26ec71b8b52..94b6c74ba727eed15bc3affaf435444fcec53feb 100644 (file)
@@ -426,15 +426,6 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                                                        priv->tos_to_tid_inv[i];
                }
 
-               priv->aggr_prio_tbl[6].amsdu
-                                       = priv->aggr_prio_tbl[6].ampdu_ap
-                                       = priv->aggr_prio_tbl[6].ampdu_user
-                                       = BA_STREAM_NOT_ALLOWED;
-
-               priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
-                                       = priv->aggr_prio_tbl[7].ampdu_user
-                                       = BA_STREAM_NOT_ALLOWED;
-
                mwifiex_set_ba_params(priv);
                mwifiex_reset_11n_rx_seq_num(priv);
 
index eede90b63f847934a8a0bc45e63695696d88a82d..7be3a4839640c6eda6b8254fd7b81bbe5d01fd33 100644 (file)
@@ -669,7 +669,8 @@ static unsigned int p54_flush_count(struct p54_common *priv)
        return total;
 }
 
-static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop)
+static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+                     u32 queues, bool drop)
 {
        struct p54_common *priv = dev->priv;
        unsigned int total, i;
index cbf0a589d32af08c392271c7bbc3afa50f8e9c84..8330fa33e50b1e2f933f813ee187c407184780ae 100644 (file)
@@ -343,7 +343,7 @@ static void ray_detach(struct pcmcia_device *link)
        ray_release(link);
 
        local = netdev_priv(dev);
-       del_timer(&local->timer);
+       del_timer_sync(&local->timer);
 
        if (link->priv) {
                unregister_netdev(dev);
index 1b28cda6ca88124deff6c112a060f5af6692cefa..2eefbf159bc0d0abdcead9ff1caf6b867d95793f 100644 (file)
@@ -1083,7 +1083,7 @@ void rsi_inform_bss_status(struct rsi_common *common,
 {
        if (status) {
                rsi_hal_send_sta_notify_frame(common,
-                                             NL80211_IFTYPE_STATION,
+                                             RSI_IFTYPE_STATION,
                                              STA_CONNECTED,
                                              bssid,
                                              qos_enable,
@@ -1092,7 +1092,7 @@ void rsi_inform_bss_status(struct rsi_common *common,
                        rsi_send_auto_rate_request(common);
        } else {
                rsi_hal_send_sta_notify_frame(common,
-                                             NL80211_IFTYPE_STATION,
+                                             RSI_IFTYPE_STATION,
                                              STA_DISCONNECTED,
                                              bssid,
                                              qos_enable,
index ac67c4ad63c2d3177e3e70386ff27538b69b536f..225215a3b8bb484d76b47ed853afb3aeb6eb2130 100644 (file)
@@ -73,6 +73,7 @@
 #define RX_BA_INDICATION                1
 #define RSI_TBL_SZ                      40
 #define MAX_RETRIES                     8
+#define RSI_IFTYPE_STATION              0
 
 #define STD_RATE_MCS7                   0x07
 #define STD_RATE_MCS6                   0x06
index 41d4a8167dc32f368a8fdf061bea4fe9944fd0f1..c17fcf272728cb06ae25e95787003f6f59f52dba 100644 (file)
@@ -1005,10 +1005,9 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
                                   entry->skb->len + padding_len);
 
        /*
-        * Enable beaconing again.
+        * Restore beaconing state.
         */
-       rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
 
        /*
         * Clean up beacon skb.
@@ -1039,13 +1038,14 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
 void rt2800_clear_beacon(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       u32 reg;
+       u32 orig_reg, reg;
 
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
         */
-       rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+       rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &orig_reg);
+       reg = orig_reg;
        rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
@@ -1055,10 +1055,9 @@ void rt2800_clear_beacon(struct queue_entry *entry)
        rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
 
        /*
-        * Enabled beaconing again.
+        * Restore beaconing state.
         */
-       rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
 }
 EXPORT_SYMBOL_GPL(rt2800_clear_beacon);
 
index e3b885d8f7dbfddda2f4ae71161b24edeefdc02c..010b76505243ed1cf15d1f176033cabd5ac23f3d 100644 (file)
@@ -1448,7 +1448,8 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
                      struct ieee80211_vif *vif, u16 queue,
                      const struct ieee80211_tx_queue_params *params);
 void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
-void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
+void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                    u32 queues, bool drop);
 int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
 int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
 void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
index ddeb5a709aa36d6375e58597104f4cc3cb632d12..212ac4842c1628a0d141104188626d55c616c487 100644 (file)
@@ -620,21 +620,19 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
                rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
                                      bss_conf->bssid);
 
-       /*
-        * Update the beacon. This is only required on USB devices. PCI
-        * devices fetch beacons periodically.
-        */
-       if (changes & BSS_CHANGED_BEACON && rt2x00_is_usb(rt2x00dev))
-               rt2x00queue_update_beacon(rt2x00dev, vif);
-
        /*
         * Start/stop beaconing.
         */
        if (changes & BSS_CHANGED_BEACON_ENABLED) {
                if (!bss_conf->enable_beacon && intf->enable_beacon) {
-                       rt2x00queue_clear_beacon(rt2x00dev, vif);
                        rt2x00dev->intf_beaconing--;
                        intf->enable_beacon = false;
+                       /*
+                        * Clear beacon in the H/W for this vif. This is needed
+                        * to disable beaconing on this particular interface
+                        * and keep it running on other interfaces.
+                        */
+                       rt2x00queue_clear_beacon(rt2x00dev, vif);
 
                        if (rt2x00dev->intf_beaconing == 0) {
                                /*
@@ -645,11 +643,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
                                rt2x00queue_stop_queue(rt2x00dev->bcn);
                                mutex_unlock(&intf->beacon_skb_mutex);
                        }
-
-
                } else if (bss_conf->enable_beacon && !intf->enable_beacon) {
                        rt2x00dev->intf_beaconing++;
                        intf->enable_beacon = true;
+                       /*
+                        * Upload beacon to the H/W. This is only required on
+                        * USB devices. PCI devices fetch beacons periodically.
+                        */
+                       if (rt2x00_is_usb(rt2x00dev))
+                               rt2x00queue_update_beacon(rt2x00dev, vif);
 
                        if (rt2x00dev->intf_beaconing == 1) {
                                /*
@@ -747,7 +749,8 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
 
-void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                    u32 queues, bool drop)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct data_queue *queue;
index 24402984ee5749f272609d82907cda4a68f750f6..9048a9cbe52cb929cfbd60797a00baa40c5d6583 100644 (file)
@@ -2031,13 +2031,14 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
 static void rt61pci_clear_beacon(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       u32 reg;
+       u32 orig_reg, reg;
 
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
         */
-       rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
+       rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &orig_reg);
+       reg = orig_reg;
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
 
@@ -2048,10 +2049,9 @@ static void rt61pci_clear_beacon(struct queue_entry *entry)
                                  HW_BEACON_OFFSET(entry->entry_idx), 0);
 
        /*
-        * Enable beaconing again.
+        * Restore global beaconing state.
         */
-       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-       rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
+       rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
 }
 
 /*
index a140170b1eb3e63625ecde7b4cc43ec6bf1b87b1..95724ff9c7268700628866f433b66e82a8a9f7c4 100644 (file)
@@ -1597,13 +1597,14 @@ static void rt73usb_clear_beacon(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        unsigned int beacon_base;
-       u32 reg;
+       u32 orig_reg, reg;
 
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
         */
-       rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+       rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &orig_reg);
+       reg = orig_reg;
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
@@ -1614,10 +1615,9 @@ static void rt73usb_clear_beacon(struct queue_entry *entry)
        rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
 
        /*
-        * Enable beaconing again.
+        * Restore beaconing state.
         */
-       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-       rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+       rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
 }
 
 static int rt73usb_get_tx_data_len(struct queue_entry *entry)
index 08b056db4a3b795282d1d9e878ab400d7090bcf2..21005bd8b43c973da6ebd24556da848032727bcf 100644 (file)
@@ -1,5 +1,5 @@
-rtl8180-objs           := dev.o rtl8225.o sa2400.o max2820.o grf5101.o rtl8225se.o
+rtl818x_pci-objs       := dev.o rtl8225.o sa2400.o max2820.o grf5101.o rtl8225se.o
 
-obj-$(CONFIG_RTL8180)  += rtl8180.o
+obj-$(CONFIG_RTL8180)  += rtl818x_pci.o
 
 ccflags-y += -Idrivers/net/wireless/rtl818x
index 98d8256f037788a4d9af76c02a4e939758a08e0e..50d69b13f9848f2a4913e2452d98224284bbf7c0 100644 (file)
@@ -683,9 +683,8 @@ static void rtl8180_int_enable(struct ieee80211_hw *dev)
        struct rtl8180_priv *priv = dev->priv;
 
        if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
-               rtl818x_iowrite32(priv, &priv->map->IMR, IMR_TMGDOK |
-                         IMR_TBDER | IMR_THPDER |
-                         IMR_THPDER | IMR_THPDOK |
+               rtl818x_iowrite32(priv, &priv->map->IMR,
+                         IMR_TBDER | IMR_TBDOK |
                          IMR_TVODER | IMR_TVODOK |
                          IMR_TVIDER | IMR_TVIDOK |
                          IMR_TBEDER | IMR_TBEDOK |
@@ -911,7 +910,10 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
                reg32 &= 0x00ffff00;
                reg32 |= 0xb8000054;
                rtl818x_iowrite32(priv, &priv->map->RF_PARA, reg32);
-       }
+       } else
+               /* stop unused queus (no dma alloc) */
+               rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING,
+                           (1<<1) | (1<<2));
 
        priv->rf->init(dev);
 
index 45ea4e1c4abe157ad952be2d8a5022efc1e1715a..7abef95d278bc61336d2829f40520afc1af81a1a 100644 (file)
@@ -334,9 +334,9 @@ struct rtl818x_csr {
  * I don't like to introduce a ton of "reserved"..
  * They are for RTL8187SE
  */
-#define REG_ADDR1(addr)        ((u8 __iomem *)priv->map + addr)
-#define REG_ADDR2(addr)        ((__le16 __iomem *)priv->map + (addr >> 1))
-#define REG_ADDR4(addr)        ((__le32 __iomem *)priv->map + (addr >> 2))
+#define REG_ADDR1(addr)        ((u8 __iomem *)priv->map + (addr))
+#define REG_ADDR2(addr)        ((__le16 __iomem *)priv->map + ((addr) >> 1))
+#define REG_ADDR4(addr)        ((__le32 __iomem *)priv->map + ((addr) >> 2))
 
 #define FEMR_SE                REG_ADDR2(0x1D4)
 #define ARFR           REG_ADDR2(0x1E0)
index 4ec424f26672028550ab8b19b944d451766ee08c..b1ed6d0796f67e187fb928423edda6977c91f863 100644 (file)
@@ -1387,7 +1387,8 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
  * before switch channel or power save, or tx buffer packet
  * maybe send after offchannel or rf sleep, this may cause
  * dis-association by AP */
-static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void rtl_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                        u32 queues, bool drop)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
index 1b4101bf9974e8243124f70f40e295e841a3f0a1..347af1e4f438e57cf2c37b8975169a7c92941681 100644 (file)
@@ -93,7 +93,6 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
        u8 tid;
 
        rtl8188ee_bt_reg_init(hw);
-       rtlpci->msi_support = true;
 
        rtlpriv->dm.dm_initialgain_enable = 1;
        rtlpriv->dm.dm_flag = 0;
index 06ef47cd62038cc9695078441d545be0ca1b9348..5b4c225396f244cea599bade9755951daa7d15ec 100644 (file)
@@ -293,7 +293,7 @@ static void _rtl88ee_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        u8 *psaddr;
        __le16 fc;
        u16 type, ufc;
-       bool match_bssid, packet_toself, packet_beacon, addr;
+       bool match_bssid, packet_toself, packet_beacon = false, addr;
 
        tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
 
index 68b5c7e92cfbc2c6a76580a2d1dbb3297730c64f..07cb06da67297244131394e60fa19c9ddf86044e 100644 (file)
@@ -1001,7 +1001,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
        err = _rtl92cu_init_mac(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "init mac failed!\n");
-               return err;
+               goto exit;
        }
        err = rtl92c_download_fw(hw);
        if (err) {
index 36b48be8329c08dad5474f43600f2b11d8fcf279..2b3c78baa9f8b3742020aa377b0449785eeb8ab7 100644 (file)
@@ -49,6 +49,12 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb,       u8 skb_queue)
        if (ieee80211_is_nullfunc(fc))
                return QSLT_HIGH;
 
+       /* Kernel commit 1bf4bbb4024dcdab changed EAPOL packets to use
+        * queue V0 at priority 7; however, the RTL8192SE appears to have
+        * that queue at priority 6
+        */
+       if (skb->priority == 7)
+               return QSLT_VO;
        return skb->priority;
 }
 
index b4577ebc4bb0bb5c16d068039cddc7f3fe41b744..a07213645da013157a858c78a84e300f03750eee 100644 (file)
@@ -92,7 +92,7 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
        rtl8723be_bt_reg_init(hw);
-       rtlpci->msi_support = true;
+       rtlpci->msi_support = false;
        rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
 
        rtlpriv->dm.dm_initialgain_enable = 1;
index ed88d39134839e34510d83252949dbbb2a964e83..077eb5b9cd74c7a119c1e74ebbb109477a857ff3 100644 (file)
@@ -5184,7 +5184,8 @@ out:
        mutex_unlock(&wl->mutex);
 }
 
-static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                           u32 queues, bool drop)
 {
        struct wl1271 *wl = hw->priv;
 
index 29ef2492951fcdaa372611449fbc4c3cde4322f1..d3dd7bfdf3f1f33efbfbd9e0be762f664c892926 100644 (file)
@@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = {
 static int wl1271_probe(struct sdio_func *func,
                                  const struct sdio_device_id *id)
 {
-       struct wlcore_platdev_data *pdev_data;
+       struct wlcore_platdev_data pdev_data;
        struct wl12xx_sdio_glue *glue;
        struct resource res[1];
        mmc_pm_flag_t mmcflags;
@@ -228,16 +228,13 @@ static int wl1271_probe(struct sdio_func *func,
        if (func->num != 0x02)
                return -ENODEV;
 
-       pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
-       if (!pdev_data)
-               goto out;
-
-       pdev_data->if_ops = &sdio_ops;
+       memset(&pdev_data, 0x00, sizeof(pdev_data));
+       pdev_data.if_ops = &sdio_ops;
 
        glue = kzalloc(sizeof(*glue), GFP_KERNEL);
        if (!glue) {
                dev_err(&func->dev, "can't allocate glue\n");
-               goto out_free_pdev_data;
+               goto out;
        }
 
        glue->dev = &func->dev;
@@ -248,9 +245,9 @@ static int wl1271_probe(struct sdio_func *func,
        /* Use block mode for transferring over one block size of data */
        func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 
-       pdev_data->pdata = wl12xx_get_platform_data();
-       if (IS_ERR(pdev_data->pdata)) {
-               ret = PTR_ERR(pdev_data->pdata);
+       pdev_data.pdata = wl12xx_get_platform_data();
+       if (IS_ERR(pdev_data.pdata)) {
+               ret = PTR_ERR(pdev_data.pdata);
                dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
                goto out_free_glue;
        }
@@ -260,7 +257,7 @@ static int wl1271_probe(struct sdio_func *func,
        dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
 
        if (mmcflags & MMC_PM_KEEP_POWER)
-               pdev_data->pdata->pwr_in_suspend = true;
+               pdev_data.pdata->pwr_in_suspend = true;
 
        sdio_set_drvdata(func, glue);
 
@@ -289,7 +286,7 @@ static int wl1271_probe(struct sdio_func *func,
 
        memset(res, 0x00, sizeof(res));
 
-       res[0].start = pdev_data->pdata->irq;
+       res[0].start = pdev_data.pdata->irq;
        res[0].flags = IORESOURCE_IRQ;
        res[0].name = "irq";
 
@@ -299,8 +296,8 @@ static int wl1271_probe(struct sdio_func *func,
                goto out_dev_put;
        }
 
-       ret = platform_device_add_data(glue->core, pdev_data,
-                                      sizeof(*pdev_data));
+       ret = platform_device_add_data(glue->core, &pdev_data,
+                                      sizeof(pdev_data));
        if (ret) {
                dev_err(glue->dev, "can't add platform data\n");
                goto out_dev_put;
@@ -319,9 +316,6 @@ out_dev_put:
 out_free_glue:
        kfree(glue);
 
-out_free_pdev_data:
-       kfree(pdev_data);
-
 out:
        return ret;
 }
index dbe826dd7c23c49a38a08988cb24c50764d3efaa..5f3a389dd74cdf573c6d08188fb70edcba10ccfa 100644 (file)
@@ -327,27 +327,25 @@ static struct wl1271_if_operations spi_ops = {
 static int wl1271_probe(struct spi_device *spi)
 {
        struct wl12xx_spi_glue *glue;
-       struct wlcore_platdev_data *pdev_data;
+       struct wlcore_platdev_data pdev_data;
        struct resource res[1];
        int ret = -ENOMEM;
 
-       pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
-       if (!pdev_data)
-               goto out;
+       memset(&pdev_data, 0x00, sizeof(pdev_data));
 
-       pdev_data->pdata = dev_get_platdata(&spi->dev);
-       if (!pdev_data->pdata) {
+       pdev_data.pdata = dev_get_platdata(&spi->dev);
+       if (!pdev_data.pdata) {
                dev_err(&spi->dev, "no platform data\n");
                ret = -ENODEV;
-               goto out_free_pdev_data;
+               goto out;
        }
 
-       pdev_data->if_ops = &spi_ops;
+       pdev_data.if_ops = &spi_ops;
 
        glue = kzalloc(sizeof(*glue), GFP_KERNEL);
        if (!glue) {
                dev_err(&spi->dev, "can't allocate glue\n");
-               goto out_free_pdev_data;
+               goto out;
        }
 
        glue->dev = &spi->dev;
@@ -385,8 +383,8 @@ static int wl1271_probe(struct spi_device *spi)
                goto out_dev_put;
        }
 
-       ret = platform_device_add_data(glue->core, pdev_data,
-                                      sizeof(*pdev_data));
+       ret = platform_device_add_data(glue->core, &pdev_data,
+                                      sizeof(pdev_data));
        if (ret) {
                dev_err(glue->dev, "can't add platform data\n");
                goto out_dev_put;
@@ -406,9 +404,6 @@ out_dev_put:
 out_free_glue:
        kfree(glue);
 
-out_free_pdev_data:
-       kfree(pdev_data);
-
 out:
        return ret;
 }
index 9bcf2cf19357837dcb6dd8e5cce637150a7a32d0..5aeb89411350a4c98a2d769302e16a8d650d075f 100644 (file)
@@ -364,7 +364,7 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
 
                memset(r, 0, sizeof(*r));
                /*
-                * Get optional "interrupts-names" property to add a name
+                * Get optional "interrupt-names" property to add a name
                 * to the resource.
                 */
                of_property_read_string_index(dev, "interrupt-names", index,
@@ -379,6 +379,32 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
 }
 EXPORT_SYMBOL_GPL(of_irq_to_resource);
 
+/**
+ * of_irq_get - Decode a node's IRQ and return it as a Linux irq number
+ * @dev: pointer to device tree node
+ * @index: zero-based index of the irq
+ *
+ * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
+ * is not yet created.
+ *
+ */
+int of_irq_get(struct device_node *dev, int index)
+{
+       int rc;
+       struct of_phandle_args oirq;
+       struct irq_domain *domain;
+
+       rc = of_irq_parse_one(dev, index, &oirq);
+       if (rc)
+               return rc;
+
+       domain = irq_find_host(oirq.np);
+       if (!domain)
+               return -EPROBE_DEFER;
+
+       return irq_create_of_mapping(&oirq);
+}
+
 /**
  * of_irq_count - Count the number of IRQs a node uses
  * @dev: pointer to device tree node
index 404d1daebefa7d7a5d02cbfb611e9585077c00b0..bd47fbc53dc96258fba942d073ee320f25e5627f 100644 (file)
@@ -168,7 +168,9 @@ struct platform_device *of_device_alloc(struct device_node *np,
                        rc = of_address_to_resource(np, i, res);
                        WARN_ON(rc);
                }
-               WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
+               if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
+                       pr_debug("not all legacy IRQ resources mapped for %s\n",
+                                np->name);
        }
 
        dev->dev.of_node = of_node_get(np);
index ae4450070503f1067579f02576ce5ec14b2a7192..fe70b86bcffb9d086edd51c758a17a60ca45cf7b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/of_platform.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -427,6 +428,36 @@ static void __init of_selftest_match_node(void)
        }
 }
 
+static void __init of_selftest_platform_populate(void)
+{
+       int irq;
+       struct device_node *np;
+       struct platform_device *pdev;
+
+       np = of_find_node_by_path("/testcase-data");
+       of_platform_populate(np, of_default_bus_match_table, NULL, NULL);
+
+       /* Test that a missing irq domain returns -EPROBE_DEFER */
+       np = of_find_node_by_path("/testcase-data/testcase-device1");
+       pdev = of_find_device_by_node(np);
+       if (!pdev)
+               selftest(0, "device 1 creation failed\n");
+       irq = platform_get_irq(pdev, 0);
+       if (irq != -EPROBE_DEFER)
+               selftest(0, "device deferred probe failed - %d\n", irq);
+
+       /* Test that a parsing failure does not return -EPROBE_DEFER */
+       np = of_find_node_by_path("/testcase-data/testcase-device2");
+       pdev = of_find_device_by_node(np);
+       if (!pdev)
+               selftest(0, "device 2 creation failed\n");
+       irq = platform_get_irq(pdev, 0);
+       if (irq >= 0 || irq == -EPROBE_DEFER)
+               selftest(0, "device parsing error failed - %d\n", irq);
+
+       selftest(1, "passed");
+}
+
 static int __init of_selftest(void)
 {
        struct device_node *np;
@@ -445,6 +476,7 @@ static int __init of_selftest(void)
        of_selftest_parse_interrupts();
        of_selftest_parse_interrupts_extended();
        of_selftest_match_node();
+       of_selftest_platform_populate();
        pr_info("end of selftest - %i passed, %i failed\n",
                selftest_results.passed, selftest_results.failed);
        return 0;
index c843720bd3e53d7e7f632f4c75152edbefbc7d5f..da4695f60351ad4c7c24aecf791a5a6c2b71edfc 100644 (file)
                                                      <&test_intmap1 1 2>;
                        };
                };
+
+               testcase-device1 {
+                       compatible = "testcase-device";
+                       interrupt-parent = <&test_intc0>;
+                       interrupts = <1>;
+               };
+
+               testcase-device2 {
+                       compatible = "testcase-device";
+                       interrupt-parent = <&test_intc2>;
+                       interrupts = <1>; /* invalid specifier - too short */
+               };
        };
+
 };
index fb8aed307c2821d70404dbac467fc94d914ed7e0..ba2bf55a38df52d99b1f7278560e9c0e9242248a 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 
 #include "pci.h"
index 47aaf22d814e195f7d397237a59267334ccf5ca2..0e5f3c95af5bd75d288d2067b79aacc6abd65a94 100644 (file)
@@ -3,7 +3,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 
index d3d1cfd51e095f058404d96f063df76d227bd652..e384e2534594731a95eb7524fb75583fce208541 100644 (file)
@@ -293,6 +293,58 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
        return PCIBIOS_SUCCESSFUL;
 }
 
+/*
+ * Remove windows, starting from the largest ones to the smallest
+ * ones.
+ */
+static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port,
+                                  phys_addr_t base, size_t size)
+{
+       while (size) {
+               size_t sz = 1 << (fls(size) - 1);
+
+               mvebu_mbus_del_window(base, sz);
+               base += sz;
+               size -= sz;
+       }
+}
+
+/*
+ * MBus windows can only have a power of two size, but PCI BARs do not
+ * have this constraint. Therefore, we have to split the PCI BAR into
+ * areas each having a power of two size. We start from the largest
+ * one (i.e highest order bit set in the size).
+ */
+static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
+                                  unsigned int target, unsigned int attribute,
+                                  phys_addr_t base, size_t size,
+                                  phys_addr_t remap)
+{
+       size_t size_mapped = 0;
+
+       while (size) {
+               size_t sz = 1 << (fls(size) - 1);
+               int ret;
+
+               ret = mvebu_mbus_add_window_remap_by_id(target, attribute, base,
+                                                       sz, remap);
+               if (ret) {
+                       dev_err(&port->pcie->pdev->dev,
+                               "Could not create MBus window at 0x%x, size 0x%x: %d\n",
+                               base, sz, ret);
+                       mvebu_pcie_del_windows(port, base - size_mapped,
+                                              size_mapped);
+                       return;
+               }
+
+               size -= sz;
+               size_mapped += sz;
+               base += sz;
+               if (remap != MVEBU_MBUS_NO_REMAP)
+                       remap += sz;
+       }
+}
+
 static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
 {
        phys_addr_t iobase;
@@ -304,8 +356,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
 
                /* If a window was configured, remove it */
                if (port->iowin_base) {
-                       mvebu_mbus_del_window(port->iowin_base,
-                                             port->iowin_size);
+                       mvebu_pcie_del_windows(port, port->iowin_base,
+                                              port->iowin_size);
                        port->iowin_base = 0;
                        port->iowin_size = 0;
                }
@@ -331,11 +383,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
        port->iowin_base = port->pcie->io.start + iobase;
        port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
                            (port->bridge.iolimitupper << 16)) -
-                           iobase);
+                           iobase) + 1;
 
-       mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr,
-                                         port->iowin_base, port->iowin_size,
-                                         iobase);
+       mvebu_pcie_add_windows(port, port->io_target, port->io_attr,
+                              port->iowin_base, port->iowin_size,
+                              iobase);
 }
 
 static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
@@ -346,8 +398,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
 
                /* If a window was configured, remove it */
                if (port->memwin_base) {
-                       mvebu_mbus_del_window(port->memwin_base,
-                                             port->memwin_size);
+                       mvebu_pcie_del_windows(port, port->memwin_base,
+                                              port->memwin_size);
                        port->memwin_base = 0;
                        port->memwin_size = 0;
                }
@@ -364,10 +416,11 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
        port->memwin_base  = ((port->bridge.membase & 0xFFF0) << 16);
        port->memwin_size  =
                (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
-               port->memwin_base;
+               port->memwin_base + 1;
 
-       mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr,
-                                   port->memwin_base, port->memwin_size);
+       mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr,
+                              port->memwin_base, port->memwin_size,
+                              MVEBU_MBUS_NO_REMAP);
 }
 
 /*
@@ -743,14 +796,21 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
 
        /*
         * On the PCI-to-PCI bridge side, the I/O windows must have at
-        * least a 64 KB size and be aligned on their size, and the
-        * memory windows must have at least a 1 MB size and be
-        * aligned on their size
+        * least a 64 KB size and the memory windows must have at
+        * least a 1 MB size. Moreover, MBus windows need to have a
+        * base address aligned on their size, and their size must be
+        * a power of two. This means that if the BAR doesn't have a
+        * power of two size, several MBus windows will actually be
+        * created. We need to ensure that the biggest MBus window
+        * (which will be the first one) is aligned on its size, which
+        * explains the rounddown_pow_of_two() being done here.
         */
        if (res->flags & IORESOURCE_IO)
-               return round_up(start, max_t(resource_size_t, SZ_64K, size));
+               return round_up(start, max_t(resource_size_t, SZ_64K,
+                                            rounddown_pow_of_two(size)));
        else if (res->flags & IORESOURCE_MEM)
-               return round_up(start, max_t(resource_size_t, SZ_1M, size));
+               return round_up(start, max_t(resource_size_t, SZ_1M,
+                                            rounddown_pow_of_two(size)));
        else
                return start;
 }
index 6258dc260d9f54ac4423998e8b338d4333768ef7..c68366cee6b72efda08d590e29b67222d3b56e35 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/export.h>
 #include "pci.h"
 
-int __ref pci_hp_add_bridge(struct pci_dev *dev)
+int pci_hp_add_bridge(struct pci_dev *dev)
 {
        struct pci_bus *parent = dev->bus;
        int pass, busnr, start = parent->busn_res.start;
index bccc27ee10308f4d1ec388db248d1af1ab08aaba..bb945e33b1ecf23a1fc1aa1e4f44a1490491ef6e 100644 (file)
@@ -41,7 +41,6 @@
 
 #define pr_fmt(fmt) "acpiphp_glue: " fmt
 
-#include <linux/init.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -501,7 +500,7 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
  */
-static void __ref enable_slot(struct acpiphp_slot *slot)
+static void enable_slot(struct acpiphp_slot *slot)
 {
        struct pci_dev *dev;
        struct pci_bus *bus = slot->bus;
index 8c1464851768140f0c31c27f60f04f93df0ff8c6..b238a1a2837223106a58df752a762a984575dea6 100644 (file)
@@ -250,7 +250,7 @@ int cpci_led_off(struct slot* slot)
  * Device configuration functions
  */
 
-int __ref cpci_configure_slot(struct slot *slot)
+int cpci_configure_slot(struct slot *slot)
 {
        struct pci_dev *dev;
        struct pci_bus *parent;
index 76ba8a1c774dfa716d947fc12092e82b8ebfef78..9600a392eaae8612436beadf4cc2373817b40c18 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/workqueue.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
-#include <linux/init.h>
 #include <asm/uaccess.h>
 #include "cpqphp.h"
 #include "cpqphp_nvram.h"
index 8a66866b8cf1ad799de42c2a15075f7549f0ca3a..8e9012dca450df581f718431e25e85d469827534 100644 (file)
@@ -127,7 +127,7 @@ struct controller {
 #define HP_SUPR_RM(ctrl)       ((ctrl)->slot_cap & PCI_EXP_SLTCAP_HPS)
 #define EMI(ctrl)              ((ctrl)->slot_cap & PCI_EXP_SLTCAP_EIP)
 #define NO_CMD_CMPL(ctrl)      ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS)
-#define PSN(ctrl)              ((ctrl)->slot_cap >> 19)
+#define PSN(ctrl)              (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19)
 
 int pciehp_sysfs_enable_slot(struct slot *slot);
 int pciehp_sysfs_disable_slot(struct slot *slot);
index d7d058fa19a428e5503c919979e5a6e1e5e5e0b2..1463412cf7f8e9b1d63cfc31a6d4a2085de3b21d 100644 (file)
@@ -159,6 +159,8 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
 
        pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
        if (slot_status & PCI_EXP_SLTSTA_CC) {
+               pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
+                                          PCI_EXP_SLTSTA_CC);
                if (!ctrl->no_cmd_complete) {
                        /*
                         * After 1 sec and CMD_COMPLETED still not set, just
index 16f9203523179c46e99505443675c964f16f4b1a..e246a10a0d2c5e4eb729e3d4c822f6dda19f176a 100644 (file)
@@ -160,8 +160,7 @@ void pci_configure_slot(struct pci_dev *dev)
                        (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
                return;
 
-       if (dev->bus)
-               pcie_bus_configure_settings(dev->bus);
+       pcie_bus_configure_settings(dev->bus);
 
        memset(&hpp, 0, sizeof(hpp));
        ret = pci_get_hp_params(dev, &hpp);
index 4796c15fba941df07c4d3bbeed94413d2df48473..984d708552f6f950d000a52ce5d1e9f225f2d728 100644 (file)
@@ -223,16 +223,16 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
        type_tmp = (char *) &types[1];
 
        /* Iterate through parent properties, looking for my-drc-index */
-       for (i = 0; i < indexes[0]; i++) {
+       for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
                if ((unsigned int) indexes[i + 1] == *my_index) {
                        if (drc_name)
                                *drc_name = name_tmp;
                        if (drc_type)
                                *drc_type = type_tmp;
                        if (drc_index)
-                               *drc_index = *my_index;
+                               *drc_index = be32_to_cpu(*my_index);
                        if (drc_power_domain)
-                               *drc_power_domain = domains[i+1];
+                               *drc_power_domain = be32_to_cpu(domains[i+1]);
                        return 0;
                }
                name_tmp += (strlen(name_tmp) + 1);
@@ -321,16 +321,19 @@ int rpaphp_add_slot(struct device_node *dn)
        /* register PCI devices */
        name = (char *) &names[1];
        type = (char *) &types[1];
-       for (i = 0; i < indexes[0]; i++) {
+       for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
+               int index;
 
-               slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]);
+               index = be32_to_cpu(indexes[i + 1]);
+               slot = alloc_slot_struct(dn, index, name,
+                                        be32_to_cpu(power_domains[i + 1]));
                if (!slot)
                        return -ENOMEM;
 
                slot->type = simple_strtoul(type, NULL, 10);
 
                dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
-                               indexes[i + 1], name, type);
+                               index, name, type);
 
                retval = rpaphp_enable_slot(slot);
                if (!retval)
index 8d2ce22151eb62001e0a2184e1f68da1a606dec5..d1332d2f8730cde2ffc8775f3a8ce46d2d7baaae 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
-#include <linux/init.h>
 #include <asm/pci_debug.h>
 #include <asm/sclp.h>
 
index 2bf69fe1926c6b503283c43b954779ceaf2ea1d7..18209ebc097961b4c5242f9c6c427dad1497f5bc 100644 (file)
@@ -34,7 +34,7 @@
 #include "../pci.h"
 #include "shpchp.h"
 
-int __ref shpchp_configure_device(struct slot *p_slot)
+int shpchp_configure_device(struct slot *p_slot)
 {
        struct pci_dev *dev;
        struct controller *ctrl = p_slot->ctrl;
index 955ab7990c5bd7045f2bf896e6d4c65989176089..275585c2dee29e4b1f01ed86fb830696fd684739 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/mm.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/init.h>
 #include <linux/export.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
@@ -544,22 +543,18 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
        if (!msi_attrs)
                return -ENOMEM;
        list_for_each_entry(entry, &pdev->msi_list, list) {
-               char *name = kmalloc(20, GFP_KERNEL);
-               if (!name)
-                       goto error_attrs;
-
                msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
-               if (!msi_dev_attr) {
-                       kfree(name);
+               if (!msi_dev_attr)
                        goto error_attrs;
-               }
+               msi_attrs[count] = &msi_dev_attr->attr;
 
-               sprintf(name, "%d", entry->irq);
                sysfs_attr_init(&msi_dev_attr->attr);
-               msi_dev_attr->attr.name = name;
+               msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d",
+                                                   entry->irq);
+               if (!msi_dev_attr->attr.name)
+                       goto error_attrs;
                msi_dev_attr->attr.mode = S_IRUGO;
                msi_dev_attr->show = msi_mode_show;
-               msi_attrs[count] = &msi_dev_attr->attr;
                ++count;
        }
 
index d911e0c1f359799ef4f110b59b2f68516868d153..ff236ed4f5cf4f6341a9fed1ea206bd865a93141 100644 (file)
@@ -107,7 +107,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
                subdevice=PCI_ANY_ID, class=0, class_mask=0;
        unsigned long driver_data=0;
        int fields=0;
-       int retval;
+       int retval = 0;
 
        fields = sscanf(buf, "%x %x %x %x %x %x %lx",
                        &vendor, &device, &subvendor, &subdevice,
@@ -115,6 +115,26 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
        if (fields < 2)
                return -EINVAL;
 
+       if (fields != 7) {
+               struct pci_dev *pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
+               if (!pdev)
+                       return -ENOMEM;
+
+               pdev->vendor = vendor;
+               pdev->device = device;
+               pdev->subsystem_vendor = subvendor;
+               pdev->subsystem_device = subdevice;
+               pdev->class = class;
+
+               if (pci_match_id(pdrv->id_table, pdev))
+                       retval = -EEXIST;
+
+               kfree(pdev);
+
+               if (retval)
+                       return retval;
+       }
+
        /* Only accept driver_data values that match an existing id_table
           entry */
        if (ids) {
@@ -1325,8 +1345,6 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
                return -ENODEV;
 
        pdev = to_pci_dev(dev);
-       if (!pdev)
-               return -ENODEV;
 
        if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
                return -ENOMEM;
@@ -1347,6 +1365,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
                           (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
                           (u8)(pdev->class)))
                return -ENOMEM;
+
        return 0;
 }
 
index 7325d43bf030ce65d5f386f6aeeeb3bfa4d5c482..033a9879438f51499a6f96a6afa2499ae01fcdc0 100644 (file)
@@ -3167,14 +3167,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
        return 0;
 }
 
-/**
- * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge.
- * @dev: Bridge device
- *
- * Use the bridge control register to assert reset on the secondary bus.
- * Devices on the secondary bus are left in power-on state.
- */
-void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
+void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
 {
        u16 ctrl;
 
@@ -3199,6 +3192,18 @@ void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
         */
        ssleep(1);
 }
+
+/**
+ * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge.
+ * @dev: Bridge device
+ *
+ * Use the bridge control register to assert reset on the secondary bus.
+ * Devices on the secondary bus are left in power-on state.
+ */
+void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
+{
+       pcibios_reset_secondary_bus(dev);
+}
 EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
 
 static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
@@ -4125,7 +4130,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
        u16 cmd;
        int rc;
 
-       WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
+       WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) && (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
 
        /* ARCH specific VGA enables */
        rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
index 6bd082299e3190b5676e49d781231f49e5eaa3fc..fe233a3099cf60fba08d894140ad5b25ace9d188 100644 (file)
@@ -201,11 +201,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                    struct resource *res, unsigned int reg);
 int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
 void pci_configure_ari(struct pci_dev *dev);
-void __ref __pci_bus_size_bridges(struct pci_bus *bus,
+void __pci_bus_size_bridges(struct pci_bus *bus,
                        struct list_head *realloc_head);
-void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-                                     struct list_head *realloc_head,
-                                     struct list_head *fail_head);
+void __pci_bus_assign_resources(const struct pci_bus *bus,
+                               struct list_head *realloc_head,
+                               struct list_head *fail_head);
 
 /**
  * pci_ari_enabled - query ARI forwarding status
index 986f8eadfd39397aff7d38c71452d86b3e6fa530..2f0ce668a775eda0ccc15ea6bbfeea133ac6c823 100644 (file)
@@ -99,7 +99,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
        for (i = 0; i < nr_entries; i++)
                msix_entries[i].entry = i;
 
-       status = pci_enable_msix(dev, msix_entries, nr_entries);
+       status = pci_enable_msix_exact(dev, msix_entries, nr_entries);
        if (status)
                goto Exit;
 
@@ -171,7 +171,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
                pci_disable_msix(dev);
 
                /* Now allocate the MSI-X vectors for real */
-               status = pci_enable_msix(dev, msix_entries, nvec);
+               status = pci_enable_msix_exact(dev, msix_entries, nvec);
                if (status)
                        goto Exit;
        }
@@ -379,10 +379,13 @@ int pcie_port_device_register(struct pci_dev *dev)
        /*
         * Initialize service irqs. Don't use service devices that
         * require interrupts if there is no way to generate them.
+        * However, some drivers may have a polling mode (e.g. pciehp_poll_mode)
+        * that can be used in the absence of irqs.  Allow them to determine
+        * if that is to be used.
         */
        status = init_service_irqs(dev, irqs, capabilities);
        if (status) {
-               capabilities &= PCIE_PORT_SERVICE_VC;
+               capabilities &= PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_HP;
                if (!capabilities)
                        goto error_disable;
        }
index ef09f5f2fe6c0bc7f0ba84ae06eaa9d46adea4e6..490031fd21084c98a2f194098f961080de261e1a 100644 (file)
@@ -719,7 +719,7 @@ add_dev:
        return child;
 }
 
-struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
        struct pci_bus *child;
 
@@ -1369,7 +1369,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        WARN_ON(ret < 0);
 }
 
-struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
+struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
 
@@ -1617,7 +1617,7 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
  */
 void pcie_bus_configure_settings(struct pci_bus *bus)
 {
-       u8 smpss;
+       u8 smpss = 0;
 
        if (!bus->self)
                return;
@@ -1958,7 +1958,7 @@ EXPORT_SYMBOL(pci_scan_bus);
  *
  * Returns the max number of subordinate bus discovered.
  */
-unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
+unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
 {
        unsigned int max;
        struct pci_bus *bus = bridge->subordinate;
@@ -1981,7 +1981,7 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
  *
  * Returns the max number of subordinate bus discovered.
  */
-unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+unsigned int pci_rescan_bus(struct pci_bus *bus)
 {
        unsigned int max;
 
index e7292065a1b13f3281eaebde605db8c2eb556145..9825ad01d812c40a1794601aa785cbbba88e1393 100644 (file)
@@ -2954,6 +2954,7 @@ static void disable_igfx_irq(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
 
 /*
  * PCI devices which are on Intel chips can skip the 10ms delay
@@ -3453,6 +3454,8 @@ static const u16 pci_quirk_intel_pch_acs_ids[] = {
        /* Wildcat PCH */
        0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97,
        0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
+       /* Patsburg (X79) PCH */
+       0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e,
 };
 
 static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
index 4a1b972efe7f2fbb76c33467de665a16004fda37..8e495bda678f2e0e9a927ac993c27da8f585e37a 100644 (file)
@@ -7,7 +7,6 @@
  *     Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
index 138bdd6393be87b2ebc63ba35b1b4edaa228b8ad..d219d44709b2fe68414fecd937e7a2f29be96d35 100644 (file)
@@ -1113,8 +1113,7 @@ handle_done:
        ;
 }
 
-void __ref __pci_bus_size_bridges(struct pci_bus *bus,
-                       struct list_head *realloc_head)
+void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask;
@@ -1178,15 +1177,15 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
        }
 }
 
-void __ref pci_bus_size_bridges(struct pci_bus *bus)
+void pci_bus_size_bridges(struct pci_bus *bus)
 {
        __pci_bus_size_bridges(bus, NULL);
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
-void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-                                     struct list_head *realloc_head,
-                                     struct list_head *fail_head)
+void __pci_bus_assign_resources(const struct pci_bus *bus,
+                               struct list_head *realloc_head,
+                               struct list_head *fail_head)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
@@ -1218,15 +1217,15 @@ void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
        }
 }
 
-void __ref pci_bus_assign_resources(const struct pci_bus *bus)
+void pci_bus_assign_resources(const struct pci_bus *bus)
 {
        __pci_bus_assign_resources(bus, NULL, NULL);
 }
 EXPORT_SYMBOL(pci_bus_assign_resources);
 
-static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
-                                        struct list_head *add_head,
-                                        struct list_head *fail_head)
+static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
+                                         struct list_head *add_head,
+                                         struct list_head *fail_head)
 {
        struct pci_bus *b;
 
@@ -1304,9 +1303,9 @@ enum release_type {
  * try to release pci bridge resources that is from leaf bridge,
  * so we can allocate big new one later
  */
-static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus,
-                                                  unsigned long type,
-                                                  enum release_type rel_type)
+static void pci_bus_release_bridge_resources(struct pci_bus *bus,
+                                            unsigned long type,
+                                            enum release_type rel_type)
 {
        struct pci_dev *dev;
        bool is_leaf_bridge = true;
index 9bd6864ec5d3fc3b6e18e2505f884a6dc8f94166..dbc4ffcf42decd31fbc2fd595cfc3bbbb08a9196 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/errno.h>
index 7eed671d55861c4ef890b33a68cfbaa2d7ef47e0..1e37c590a1833c8d2f77bb9fdac499da14e707fe 100644 (file)
@@ -16,7 +16,6 @@
  *          Resource sorting
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/pci.h>
index 92ed4b2e3c0716cf3f21580b49434fc6e9952fc6..c862f9c0e9ce4cb356222b496c40ca1ac26b0699 100644 (file)
@@ -64,7 +64,6 @@ struct as3722_pin_function {
 };
 
 struct as3722_gpio_pin_control {
-       bool enable_gpio_invert;
        unsigned mode_prop;
        int io_function;
 };
@@ -320,10 +319,8 @@ static int as3722_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev,
                return mode;
        }
 
-       if (as_pci->gpio_control[offset].enable_gpio_invert)
-               mode |= AS3722_GPIO_INV;
-
-       return as3722_write(as3722, AS3722_GPIOn_CONTROL_REG(offset), mode);
+       return as3722_update_bits(as3722, AS3722_GPIOn_CONTROL_REG(offset),
+                               AS3722_GPIO_MODE_MASK, mode);
 }
 
 static const struct pinmux_ops as3722_pinmux_ops = {
@@ -496,10 +493,18 @@ static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
 {
        struct as3722_pctrl_info *as_pci = to_as_pci(chip);
        struct as3722 *as3722 = as_pci->as3722;
-       int en_invert = as_pci->gpio_control[offset].enable_gpio_invert;
+       int en_invert;
        u32 val;
        int ret;
 
+       ret = as3722_read(as3722, AS3722_GPIOn_CONTROL_REG(offset), &val);
+       if (ret < 0) {
+               dev_err(as_pci->dev,
+                       "GPIO_CONTROL%d_REG read failed: %d\n", offset, ret);
+               return;
+       }
+       en_invert = !!(val & AS3722_GPIO_INV);
+
        if (value)
                val = (en_invert) ? 0 : AS3722_GPIOn_SIGNAL(offset);
        else
index 81075f2a1d3f87d9ac9d2cf4d62edf94e21bf75f..2960557bfed95c6d79f316c020ec98c426f38f83 100644 (file)
@@ -810,6 +810,7 @@ static const struct pinconf_ops pcs_pinconf_ops = {
 static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
                unsigned pin_pos)
 {
+       struct pcs_soc_data *pcs_soc = &pcs->socdata;
        struct pinctrl_pin_desc *pin;
        struct pcs_name *pn;
        int i;
@@ -821,6 +822,18 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
                return -ENOMEM;
        }
 
+       if (pcs_soc->irq_enable_mask) {
+               unsigned val;
+
+               val = pcs->read(pcs->base + offset);
+               if (val & pcs_soc->irq_enable_mask) {
+                       dev_dbg(pcs->dev, "irq enabled at boot for pin at %lx (%x), clearing\n",
+                               (unsigned long)pcs->res->start + offset, val);
+                       val &= ~pcs_soc->irq_enable_mask;
+                       pcs->write(val, pcs->base + offset);
+               }
+       }
+
        pin = &pcs->pins.pa[i];
        pn = &pcs->names[i];
        sprintf(pn->name, "%lx.%d",
index c5e0f6973a3b06c3e197eccbe7ba917a27d1c3ec..26ca6855f478d3018f79ab8aab87550e1eb52610 100644 (file)
@@ -629,9 +629,8 @@ static int tb10x_gpio_request_enable(struct pinctrl_dev *pctl,
         */
        for (i = 0; i < state->pinfuncgrpcnt; i++) {
                const struct tb10x_pinfuncgrp *pfg = &state->pingroups[i];
-               unsigned int port = pfg->port;
                unsigned int mode = pfg->mode;
-               int j;
+               int j, port = pfg->port;
 
                /*
                 * Skip pin groups which are always mapped and don't need
index 48093719167abd91e27f93eb869eab3f1edd5c51..f5cd3f9618083bacca6414489db5e83b3dc128d9 100644 (file)
@@ -4794,8 +4794,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
                FN_MSIOF0_SCK_B, 0,
                /* IP5_23_21 [3] */
                FN_WE1_N, FN_IERX, FN_CAN1_RX, FN_VI1_G4,
-               FN_VI1_G4_B, FN_VI2_R6, FN_SCIFA0_CTS_N_B,
-               FN_IERX_C, 0,
+               FN_VI1_G4_B, FN_VI2_R6, FN_SCIFA0_CTS_N_B, FN_IERX_C,
                /* IP5_20_18 [3] */
                FN_WE0_N, FN_IECLK, FN_CAN_CLK,
                FN_VI2_VSYNC_N, FN_SCIFA0_TXD_B, FN_VI2_VSYNC_N_B, 0, 0,
index 5186d70c49d43326bc0a3e1f0405332d512cb989..7868bf3a0f911dccfbe7b516c469ac63f6422e4c 100644 (file)
@@ -5288,7 +5288,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
                /* SEL_SCIF3 [2] */
                FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
                /* SEL_IEB [2] */
-               FN_SEL_IEB_0, FN_SEL_IEB_1, FN_SEL_IEB_2,
+               FN_SEL_IEB_0, FN_SEL_IEB_1, FN_SEL_IEB_2, 0,
                /* SEL_MMC [1] */
                FN_SEL_MMC_0, FN_SEL_MMC_1,
                /* SEL_SCIF5 [1] */
index 9f611cbbc294ea8c5ae84023e132e02152e36f85..c31aa07b3ba55541ff434adf45aed76adb0adee3 100644 (file)
@@ -83,8 +83,7 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
 {
        struct acpi_device *acpi_dev;
        acpi_handle handle;
-       struct acpi_buffer buffer;
-       int ret;
+       int ret = 0;
 
        pnp_dbg(&dev->dev, "set resources\n");
 
@@ -97,19 +96,26 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
        if (WARN_ON_ONCE(acpi_dev != dev->data))
                dev->data = acpi_dev;
 
-       ret = pnpacpi_build_resource_template(dev, &buffer);
-       if (ret)
-               return ret;
-       ret = pnpacpi_encode_resources(dev, &buffer);
-       if (ret) {
+       if (acpi_has_method(handle, METHOD_NAME__SRS)) {
+               struct acpi_buffer buffer;
+
+               ret = pnpacpi_build_resource_template(dev, &buffer);
+               if (ret)
+                       return ret;
+
+               ret = pnpacpi_encode_resources(dev, &buffer);
+               if (!ret) {
+                       acpi_status status;
+
+                       status = acpi_set_current_resources(handle, &buffer);
+                       if (ACPI_FAILURE(status))
+                               ret = -EIO;
+               }
                kfree(buffer.pointer);
-               return ret;
        }
-       if (ACPI_FAILURE(acpi_set_current_resources(handle, &buffer)))
-               ret = -EINVAL;
-       else if (acpi_bus_power_manageable(handle))
+       if (!ret && acpi_bus_power_manageable(handle))
                ret = acpi_bus_set_power(handle, ACPI_STATE_D0);
-       kfree(buffer.pointer);
+
        return ret;
 }
 
@@ -117,7 +123,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
 {
        struct acpi_device *acpi_dev;
        acpi_handle handle;
-       int ret;
+       acpi_status status;
 
        dev_dbg(&dev->dev, "disable resources\n");
 
@@ -128,13 +134,15 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
        }
 
        /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
-       ret = 0;
        if (acpi_bus_power_manageable(handle))
                acpi_bus_set_power(handle, ACPI_STATE_D3_COLD);
-               /* continue even if acpi_bus_set_power() fails */
-       if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL)))
-               ret = -ENODEV;
-       return ret;
+
+       /* continue even if acpi_bus_set_power() fails */
+       status = acpi_evaluate_object(handle, "_DIS", NULL, NULL);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+               return -ENODEV;
+
+       return 0;
 }
 
 #ifdef CONFIG_ACPI_SLEEP
index 3736bc408adba363f05e54da1762a69a00d3252b..ebf0d6710b5a0d4150627313a3edca99e50a8745 100644 (file)
@@ -335,7 +335,7 @@ static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
 }
 #endif
 
-#ifdef CONFIG_X86
+#ifdef CONFIG_PCI
 /* Device IDs of parts that have 32KB MCH space */
 static const unsigned int mch_quirk_devices[] = {
        0x0154, /* Ivy Bridge */
@@ -440,7 +440,7 @@ static struct pnp_fixup pnp_fixups[] = {
 #ifdef CONFIG_AMD_NB
        {"PNP0c01", quirk_amd_mmconfig_area},
 #endif
-#ifdef CONFIG_X86
+#ifdef CONFIG_PCI
        {"PNP0c02", quirk_intel_mch},
 #endif
        {""}
index 8fc9d6df87f682610187a7ca665c393ef30c6e1d..1685f63b9e5d03c1084bc1436fdf6cce740013ea 100644 (file)
 
 #include <linux/mfd/tps65090.h>
 
-#define TPS65090_REG_INTR_STS  0x00
-#define TPS65090_REG_INTR_MASK 0x02
-#define TPS65090_REG_CG_CTRL0  0x04
-#define TPS65090_REG_CG_CTRL1  0x05
-#define TPS65090_REG_CG_CTRL2  0x06
-#define TPS65090_REG_CG_CTRL3  0x07
-#define TPS65090_REG_CG_CTRL4  0x08
-#define TPS65090_REG_CG_CTRL5  0x09
-#define TPS65090_REG_CG_STATUS1        0x0a
-#define TPS65090_REG_CG_STATUS2        0x0b
-
 #define TPS65090_CHARGER_ENABLE        BIT(0)
 #define TPS65090_VACG          BIT(1)
 #define TPS65090_NOITERM       BIT(5)
index d9a0770b6c73d24b65ae35fce4bf3ac2a7f43343..b1cda6ffdbcc5f6bfc6aa5d3e4c42d44b038823b 100644 (file)
@@ -951,7 +951,9 @@ static const struct x86_cpu_id rapl_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
        { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
        { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
-       { X86_VENDOR_INTEL, 6, 0x45},/* Haswell */
+       { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */
+       { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */
+       { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */
        /* TODO: Add more CPU IDs after testing */
        {}
 };
@@ -1124,8 +1126,7 @@ err_cleanup_package:
 static int rapl_check_domain(int cpu, int domain)
 {
        unsigned msr;
-       u64 val1, val2 = 0;
-       int retry = 0;
+       u64 val = 0;
 
        switch (domain) {
        case RAPL_DOMAIN_PACKAGE:
@@ -1144,26 +1145,13 @@ static int rapl_check_domain(int cpu, int domain)
                pr_err("invalid domain id %d\n", domain);
                return -EINVAL;
        }
-       if (rdmsrl_safe_on_cpu(cpu, msr, &val1))
-               return -ENODEV;
-
-       /* PP1/uncore/graphics domain may not be active at the time of
-        * driver loading. So skip further checks.
+       /* make sure domain counters are available and contains non-zero
+        * values, otherwise skip it.
         */
-       if (domain == RAPL_DOMAIN_PP1)
-               return 0;
-       /* energy counters roll slowly on some domains */
-       while (++retry < 10) {
-               usleep_range(10000, 15000);
-               rdmsrl_safe_on_cpu(cpu, msr, &val2);
-               if ((val1 & ENERGY_STATUS_MASK) != (val2 & ENERGY_STATUS_MASK))
-                       return 0;
-       }
-       /* if energy counter does not change, report as bad domain */
-       pr_info("domain %s energy ctr %llu:%llu not working, skip\n",
-               rapl_domain_names[domain], val1, val2);
+       if (rdmsrl_safe_on_cpu(cpu, msr, &val) || !val)
+               return -ENODEV;
 
-       return -ENODEV;
+       return 0;
 }
 
 /* Detect active and valid domains for the given CPU, caller must
@@ -1180,6 +1168,9 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
                /* use physical package id to read counters */
                if (!rapl_check_domain(cpu, i))
                        rp->domain_map |= 1 << i;
+               else
+                       pr_warn("RAPL domain %s detection failed\n",
+                               rapl_domain_names[i]);
        }
        rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
        if (!rp->nr_domains) {
index e25d2bc898e5b6e4eb7b43e6df87129a2a19781e..296b0ec8744da915763f8444c2ae8e902376c33e 100644 (file)
@@ -142,7 +142,10 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
                delta = ktime_to_ns(kt);
                err = ops->adjtime(ops, delta);
        } else if (tx->modes & ADJ_FREQUENCY) {
-               err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq));
+               s32 ppb = scaled_ppm_to_ppb(tx->freq);
+               if (ppb > ops->max_adj || ppb < -ops->max_adj)
+                       return -ERANGE;
+               err = ops->adjfreq(ops, ppb);
                ptp->dialed_frequency = tx->freq;
        } else if (tx->modes == 0) {
                tx->freq = ptp->dialed_frequency;
index 903eb37f047a916d510685b7e203a4ecdb680cbd..b4f57a4dbc591db7a4e7409e462834b6c86b2b60 100644 (file)
@@ -139,6 +139,13 @@ config REGULATOR_AS3722
          AS3722 PMIC. This will enable support for all the software
          controllable DCDC/LDO regulators.
 
+config REGULATOR_AXP20X
+       tristate "X-POWERS AXP20X PMIC Regulators"
+       depends on MFD_AXP20X
+       help
+         This driver provides support for the voltage regulators on the
+         AXP20X PMIC.
+
 config REGULATOR_BCM590XX
        tristate "Broadcom BCM590xx PMU Regulators"
        depends on MFD_BCM590XX
@@ -266,11 +273,12 @@ config REGULATOR_LP8788
          This driver supports LP8788 voltage regulator chip.
 
 config REGULATOR_MAX14577
-       tristate "Maxim 14577 regulator"
+       tristate "Maxim 14577/77836 regulator"
        depends on MFD_MAX14577
        help
-         This driver controls a Maxim 14577 regulator via I2C bus.
-         The regulators include safeout LDO and current regulator 'CHARGER'.
+         This driver controls a Maxim MAX14577/77836 regulator via I2C bus.
+         The MAX14577 regulators include safeout LDO and charger current
+         regulator. The MAX77836 has two additional LDOs.
 
 config REGULATOR_MAX1586
        tristate "Maxim 1586/1587 voltage regulator"
index 12ef277a48b47c55bdceee69f8f637bc929522f8..c14696b290c0ccfd452e19eaabce47238c8bfce5 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
 obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
 obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
 obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
+obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
index b1033d30b504c70cd50364bd5dcbdbca198474f6..d3787e11f535155e6479bc52c54053bffded71aa 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 
@@ -178,6 +179,42 @@ static const struct regulator_init_data arizona_ldo1_default = {
        .num_consumer_supplies = 1,
 };
 
+static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
+                                    struct regulator_config *config)
+{
+       struct arizona_pdata *pdata = &arizona->pdata;
+       struct arizona_ldo1 *ldo1 = config->driver_data;
+       struct device_node *init_node, *dcvdd_node;
+       struct regulator_init_data *init_data;
+
+       pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true);
+
+       init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1");
+       dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0);
+
+       if (init_node) {
+               config->of_node = init_node;
+
+               init_data = of_get_regulator_init_data(arizona->dev, init_node);
+
+               if (init_data) {
+                       init_data->consumer_supplies = &ldo1->supply;
+                       init_data->num_consumer_supplies = 1;
+
+                       if (dcvdd_node && dcvdd_node != init_node)
+                               arizona->external_dcvdd = true;
+
+                       pdata->ldo1 = init_data;
+               }
+       } else if (dcvdd_node) {
+               arizona->external_dcvdd = true;
+       }
+
+       of_node_put(dcvdd_node);
+
+       return 0;
+}
+
 static int arizona_ldo1_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -186,6 +223,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
        struct arizona_ldo1 *ldo1;
        int ret;
 
+       arizona->external_dcvdd = false;
+
        ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
        if (!ldo1)
                return -ENOMEM;
@@ -216,6 +255,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
        config.dev = arizona->dev;
        config.driver_data = ldo1;
        config.regmap = arizona->regmap;
+
+       if (IS_ENABLED(CONFIG_OF)) {
+               if (!dev_get_platdata(arizona->dev)) {
+                       ret = arizona_ldo1_of_get_pdata(arizona, &config);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        config.ena_gpio = arizona->pdata.ldoena;
 
        if (arizona->pdata.ldo1)
@@ -223,6 +271,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
        else
                config.init_data = &ldo1->init_data;
 
+       /*
+        * LDO1 can only be used to supply DCVDD so if it has no
+        * consumers then DCVDD is supplied externally.
+        */
+       if (config.init_data->num_consumer_supplies == 0)
+               arizona->external_dcvdd = true;
+
        ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
        if (IS_ERR(ldo1->regulator)) {
                ret = PTR_ERR(ldo1->regulator);
@@ -231,6 +286,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
                return ret;
        }
 
+       of_node_put(config.of_node);
+
        platform_set_drvdata(pdev, ldo1);
 
        return 0;
index 6fdd9bf6927fcb39763156d34d2747c34ff2ebee..b80ebbe88bac558edcdebf94fc976fbbea192a60 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -195,6 +196,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
        .num_consumer_supplies = 1,
 };
 
+static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
+                                       struct regulator_config *config)
+{
+       struct arizona_pdata *pdata = &arizona->pdata;
+       struct arizona_micsupp *micsupp = config->driver_data;
+       struct device_node *np;
+       struct regulator_init_data *init_data;
+
+       np = of_get_child_by_name(arizona->dev->of_node, "micvdd");
+
+       if (np) {
+               config->of_node = np;
+
+               init_data = of_get_regulator_init_data(arizona->dev, np);
+
+               if (init_data) {
+                       init_data->consumer_supplies = &micsupp->supply;
+                       init_data->num_consumer_supplies = 1;
+
+                       pdata->micvdd = init_data;
+               }
+       }
+
+       return 0;
+}
+
 static int arizona_micsupp_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -234,6 +261,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
        config.driver_data = micsupp;
        config.regmap = arizona->regmap;
 
+       if (IS_ENABLED(CONFIG_OF)) {
+               if (!dev_get_platdata(arizona->dev)) {
+                       ret = arizona_micsupp_of_get_pdata(arizona, &config);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        if (arizona->pdata.micvdd)
                config.init_data = arizona->pdata.micvdd;
        else
@@ -253,6 +288,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
                return ret;
        }
 
+       of_node_put(config.of_node);
+
        platform_set_drvdata(pdev, micsupp);
 
        return 0;
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
new file mode 100644 (file)
index 0000000..78a29e6
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * AXP20x regulators driver.
+ *
+ * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define AXP20X_IO_ENABLED              0x03
+#define AXP20X_IO_DISABLED             0x07
+
+#define AXP20X_WORKMODE_DCDC2_MASK     BIT(2)
+#define AXP20X_WORKMODE_DCDC3_MASK     BIT(1)
+
+#define AXP20X_FREQ_DCDC_MASK          0x0f
+
+#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg,   \
+                      _emask, _enable_val, _disable_val)                       \
+       [AXP20X_##_id] = {                                                      \
+               .name           = #_id,                                         \
+               .supply_name    = (_supply),                                    \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP20X_##_id,                                 \
+               .n_voltages     = (((_max) - (_min)) / (_step) + 1),            \
+               .owner          = THIS_MODULE,                                  \
+               .min_uV         = (_min) * 1000,                                \
+               .uV_step        = (_step) * 1000,                               \
+               .vsel_reg       = (_vreg),                                      \
+               .vsel_mask      = (_vmask),                                     \
+               .enable_reg     = (_ereg),                                      \
+               .enable_mask    = (_emask),                                     \
+               .enable_val     = (_enable_val),                                \
+               .disable_val    = (_disable_val),                               \
+               .ops            = &axp20x_ops,                                  \
+       }
+
+#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg,     \
+                   _emask)                                                     \
+       [AXP20X_##_id] = {                                                      \
+               .name           = #_id,                                         \
+               .supply_name    = (_supply),                                    \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP20X_##_id,                                 \
+               .n_voltages     = (((_max) - (_min)) / (_step) + 1),            \
+               .owner          = THIS_MODULE,                                  \
+               .min_uV         = (_min) * 1000,                                \
+               .uV_step        = (_step) * 1000,                               \
+               .vsel_reg       = (_vreg),                                      \
+               .vsel_mask      = (_vmask),                                     \
+               .enable_reg     = (_ereg),                                      \
+               .enable_mask    = (_emask),                                     \
+               .ops            = &axp20x_ops,                                  \
+       }
+
+#define AXP20X_DESC_FIXED(_id, _supply, _volt)                                 \
+       [AXP20X_##_id] = {                                                      \
+               .name           = #_id,                                         \
+               .supply_name    = (_supply),                                    \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP20X_##_id,                                 \
+               .n_voltages     = 1,                                            \
+               .owner          = THIS_MODULE,                                  \
+               .min_uV         = (_volt) * 1000,                               \
+               .ops            = &axp20x_ops_fixed                             \
+       }
+
+#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask)  \
+       [AXP20X_##_id] = {                                                      \
+               .name           = #_id,                                         \
+               .supply_name    = (_supply),                                    \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP20X_##_id,                                 \
+               .n_voltages     = ARRAY_SIZE(_table),                           \
+               .owner          = THIS_MODULE,                                  \
+               .vsel_reg       = (_vreg),                                      \
+               .vsel_mask      = (_vmask),                                     \
+               .enable_reg     = (_ereg),                                      \
+               .enable_mask    = (_emask),                                     \
+               .volt_table     = (_table),                                     \
+               .ops            = &axp20x_ops_table,                            \
+       }
+
+static const int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000,
+                                       1700000, 1800000, 1900000, 2000000, 2500000,
+                                       2700000, 2800000, 3000000, 3100000, 3200000,
+                                       3300000 };
+
+static struct regulator_ops axp20x_ops_fixed = {
+       .list_voltage           = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops axp20x_ops_table = {
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .list_voltage           = regulator_list_voltage_table,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops axp20x_ops = {
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .list_voltage           = regulator_list_voltage_linear,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_desc axp20x_regulators[] = {
+       AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f,
+                   AXP20X_PWR_OUT_CTRL, 0x10),
+       AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f,
+                   AXP20X_PWR_OUT_CTRL, 0x02),
+       AXP20X_DESC_FIXED(LDO1, "acin", 1300),
+       AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0,
+                   AXP20X_PWR_OUT_CTRL, 0x04),
+       AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f,
+                   AXP20X_PWR_OUT_CTRL, 0x40),
+       AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f,
+                         AXP20X_PWR_OUT_CTRL, 0x08),
+       AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0,
+                      AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED,
+                      AXP20X_IO_DISABLED),
+};
+
+#define AXP_MATCH(_name, _id) \
+       [AXP20X_##_id] = { \
+               .name           = #_name, \
+               .driver_data    = (void *) &axp20x_regulators[AXP20X_##_id], \
+       }
+
+static struct of_regulator_match axp20x_matches[] = {
+       AXP_MATCH(dcdc2, DCDC2),
+       AXP_MATCH(dcdc3, DCDC3),
+       AXP_MATCH(ldo1, LDO1),
+       AXP_MATCH(ldo2, LDO2),
+       AXP_MATCH(ldo3, LDO3),
+       AXP_MATCH(ldo4, LDO4),
+       AXP_MATCH(ldo5, LDO5),
+};
+
+static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
+{
+       struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+
+       if (dcdcfreq < 750) {
+               dcdcfreq = 750;
+               dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n");
+       }
+
+       if (dcdcfreq > 1875) {
+               dcdcfreq = 1875;
+               dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n");
+       }
+
+       dcdcfreq = (dcdcfreq - 750) / 75;
+
+       return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
+                                 AXP20X_FREQ_DCDC_MASK, dcdcfreq);
+}
+
+static int axp20x_regulator_parse_dt(struct platform_device *pdev)
+{
+       struct device_node *np, *regulators;
+       int ret;
+       u32 dcdcfreq;
+
+       np = of_node_get(pdev->dev.parent->of_node);
+       if (!np)
+               return 0;
+
+       regulators = of_find_node_by_name(np, "regulators");
+       if (!regulators) {
+               dev_warn(&pdev->dev, "regulators node not found\n");
+       } else {
+               ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches,
+                                        ARRAY_SIZE(axp20x_matches));
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
+                       return ret;
+               }
+
+               dcdcfreq = 1500;
+               of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq);
+               ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret);
+                       return ret;
+               }
+
+               of_node_put(regulators);
+       }
+
+       return 0;
+}
+
+static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
+{
+       unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK;
+
+       if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
+               return -EINVAL;
+
+       if (id == AXP20X_DCDC3)
+               mask = AXP20X_WORKMODE_DCDC3_MASK;
+
+       workmode <<= ffs(mask) - 1;
+
+       return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
+}
+
+static int axp20x_regulator_probe(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev;
+       struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = { };
+       struct regulator_init_data *init_data;
+       int ret, i;
+       u32 workmode;
+
+       ret = axp20x_regulator_parse_dt(pdev);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
+               init_data = axp20x_matches[i].init_data;
+
+               config.dev = &pdev->dev;
+               config.init_data = init_data;
+               config.regmap = axp20x->regmap;
+               config.of_node = axp20x_matches[i].of_node;
+
+               rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "Failed to register %s\n",
+                               axp20x_regulators[i].name);
+
+                       return PTR_ERR(rdev);
+               }
+
+               ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode",
+                                          &workmode);
+               if (!ret) {
+                       if (axp20x_set_dcdc_workmode(rdev, i, workmode))
+                               dev_err(&pdev->dev, "Failed to set workmode on %s\n",
+                                       axp20x_regulators[i].name);
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver axp20x_regulator_driver = {
+       .probe  = axp20x_regulator_probe,
+       .driver = {
+               .name           = "axp20x-regulator",
+               .owner          = THIS_MODULE,
+       },
+};
+
+module_platform_driver(axp20x_regulator_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC");
index 9a09f3cdbabb85cec71e7afece30308e4ccead7b..b97ffd2365d3a78c29e01c1cd3dfab46eb302803 100644 (file)
@@ -3447,7 +3447,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        /* register with sysfs */
        rdev->dev.class = &regulator_class;
-       rdev->dev.of_node = config->of_node;
+       rdev->dev.of_node = of_node_get(config->of_node);
        rdev->dev.parent = dev;
        dev_set_name(&rdev->dev, "regulator.%d",
                     atomic_inc_return(&regulator_no) - 1);
@@ -3589,6 +3589,7 @@ void regulator_unregister(struct regulator_dev *rdev)
        list_del(&rdev->list);
        kfree(rdev->constraints);
        regulator_ena_gpio_free(rdev);
+       of_node_put(rdev->dev.of_node);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
 }
index ed60baaeceeca79cc9ba2b9c770973d5039da3fa..5d9c605cf534d9dea23b99885b1a5babffc65869 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * max14577.c - Regulator driver for the Maxim 14577
+ * max14577.c - Regulator driver for the Maxim 14577/77836
  *
  * Copyright (C) 2013,2014 Samsung Electronics
  * Krzysztof Kozlowski <k.kozlowski@samsung.com>
 #include <linux/mfd/max14577-private.h>
 #include <linux/regulator/of_regulator.h>
 
+/*
+ * Valid limits of current for max14577 and max77836 chargers.
+ * They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4
+ * register for given chipset.
+ */
+struct maxim_charger_current {
+       /* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */
+       unsigned int min;
+       /*
+        * Minimal current when high setting is active,
+        * set in CHGCTRL4/MBCICHWRCH, uA
+        */
+       unsigned int high_start;
+       /* Value of one step in high setting, uA */
+       unsigned int high_step;
+       /* Maximum current of high setting, uA */
+       unsigned int max;
+};
+
+/* Table of valid charger currents for different Maxim chipsets */
+static const struct maxim_charger_current maxim_charger_currents[] = {
+       [MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
+       [MAXIM_DEVICE_TYPE_MAX14577] = {
+               .min            = MAX14577_REGULATOR_CURRENT_LIMIT_MIN,
+               .high_start     = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START,
+               .high_step      = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
+               .max            = MAX14577_REGULATOR_CURRENT_LIMIT_MAX,
+       },
+       [MAXIM_DEVICE_TYPE_MAX77836] = {
+               .min            = MAX77836_REGULATOR_CURRENT_LIMIT_MIN,
+               .high_start     = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START,
+               .high_step      = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
+               .max            = MAX77836_REGULATOR_CURRENT_LIMIT_MAX,
+       },
+};
+
 static int max14577_reg_is_enabled(struct regulator_dev *rdev)
 {
        int rid = rdev_get_id(rdev);
@@ -47,6 +83,9 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
 {
        u8 reg_data;
        struct regmap *rmap = rdev->regmap;
+       struct max14577 *max14577 = rdev_get_drvdata(rdev);
+       const struct maxim_charger_current *limits =
+               &maxim_charger_currents[max14577->dev_type];
 
        if (rdev_get_id(rdev) != MAX14577_CHARGER)
                return -EINVAL;
@@ -54,12 +93,11 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
        max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
 
        if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
-               return MAX14577_REGULATOR_CURRENT_LIMIT_MIN;
+               return limits->min;
 
        reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >>
                        CHGCTRL4_MBCICHWRCH_SHIFT);
-       return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
-               reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP;
+       return limits->high_start + reg_data * limits->high_step;
 }
 
 static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
@@ -67,33 +105,39 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
 {
        int i, current_bits = 0xf;
        u8 reg_data;
+       struct max14577 *max14577 = rdev_get_drvdata(rdev);
+       const struct maxim_charger_current *limits =
+               &maxim_charger_currents[max14577->dev_type];
 
        if (rdev_get_id(rdev) != MAX14577_CHARGER)
                return -EINVAL;
 
-       if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX ||
-                       max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN)
+       if (min_uA > limits->max || max_uA < limits->min)
                return -EINVAL;
 
-       if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) {
-               /* Less than 200 mA, so set 90mA (turn only Low Bit off) */
+       if (max_uA < limits->high_start) {
+               /*
+                * Less than high_start,
+                * so set the minimal current (turn only Low Bit off)
+                */
                u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT;
                return max14577_update_reg(rdev->regmap,
                                MAX14577_CHG_REG_CHG_CTRL4,
                                CHGCTRL4_MBCICHWRCL_MASK, reg_data);
        }
 
-       /* max_uA is in range: <LIMIT_HIGH_START, inifinite>, so search for
-        * valid current starting from LIMIT_MAX. */
-       for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX;
-                       i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START;
-                       i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) {
+       /*
+        * max_uA is in range: <high_start, inifinite>, so search for
+        * valid current starting from maximum current.
+        */
+       for (i = limits->max; i >= limits->high_start; i -= limits->high_step) {
                if (i <= max_uA)
                        break;
                current_bits--;
        }
        BUG_ON(current_bits < 0); /* Cannot happen */
-       /* Turn Low Bit on (use range 200mA-950 mA) */
+
+       /* Turn Low Bit on (use range high_start-max)... */
        reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
        /* and set proper High Bits */
        reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;
@@ -118,7 +162,7 @@ static struct regulator_ops max14577_charger_ops = {
        .set_current_limit      = max14577_reg_set_current_limit,
 };
 
-static const struct regulator_desc supported_regulators[] = {
+static const struct regulator_desc max14577_supported_regulators[] = {
        [MAX14577_SAFEOUT] = {
                .name           = "SAFEOUT",
                .id             = MAX14577_SAFEOUT,
@@ -141,16 +185,88 @@ static const struct regulator_desc supported_regulators[] = {
        },
 };
 
+static struct regulator_ops max77836_ldo_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       /* TODO: add .set_suspend_mode */
+};
+
+static const struct regulator_desc max77836_supported_regulators[] = {
+       [MAX14577_SAFEOUT] = {
+               .name           = "SAFEOUT",
+               .id             = MAX14577_SAFEOUT,
+               .ops            = &max14577_safeout_ops,
+               .type           = REGULATOR_VOLTAGE,
+               .owner          = THIS_MODULE,
+               .n_voltages     = 1,
+               .min_uV         = MAX14577_REGULATOR_SAFEOUT_VOLTAGE,
+               .enable_reg     = MAX14577_REG_CONTROL2,
+               .enable_mask    = CTRL2_SFOUTORD_MASK,
+       },
+       [MAX14577_CHARGER] = {
+               .name           = "CHARGER",
+               .id             = MAX14577_CHARGER,
+               .ops            = &max14577_charger_ops,
+               .type           = REGULATOR_CURRENT,
+               .owner          = THIS_MODULE,
+               .enable_reg     = MAX14577_CHG_REG_CHG_CTRL2,
+               .enable_mask    = CHGCTRL2_MBCHOSTEN_MASK,
+       },
+       [MAX77836_LDO1] = {
+               .name           = "LDO1",
+               .id             = MAX77836_LDO1,
+               .ops            = &max77836_ldo_ops,
+               .type           = REGULATOR_VOLTAGE,
+               .owner          = THIS_MODULE,
+               .n_voltages     = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
+               .min_uV         = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
+               .uV_step        = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
+               .enable_reg     = MAX77836_LDO_REG_CNFG1_LDO1,
+               .enable_mask    = MAX77836_CNFG1_LDO_PWRMD_MASK,
+               .vsel_reg       = MAX77836_LDO_REG_CNFG1_LDO1,
+               .vsel_mask      = MAX77836_CNFG1_LDO_TV_MASK,
+       },
+       [MAX77836_LDO2] = {
+               .name           = "LDO2",
+               .id             = MAX77836_LDO2,
+               .ops            = &max77836_ldo_ops,
+               .type           = REGULATOR_VOLTAGE,
+               .owner          = THIS_MODULE,
+               .n_voltages     = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
+               .min_uV         = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
+               .uV_step        = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
+               .enable_reg     = MAX77836_LDO_REG_CNFG1_LDO2,
+               .enable_mask    = MAX77836_CNFG1_LDO_PWRMD_MASK,
+               .vsel_reg       = MAX77836_LDO_REG_CNFG1_LDO2,
+               .vsel_mask      = MAX77836_CNFG1_LDO_TV_MASK,
+       },
+};
+
 #ifdef CONFIG_OF
 static struct of_regulator_match max14577_regulator_matches[] = {
        { .name = "SAFEOUT", },
        { .name = "CHARGER", },
 };
 
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
+static struct of_regulator_match max77836_regulator_matches[] = {
+       { .name = "SAFEOUT", },
+       { .name = "CHARGER", },
+       { .name = "LDO1", },
+       { .name = "LDO2", },
+};
+
+static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
+               enum maxim_device_type dev_type)
 {
        int ret;
        struct device_node *np;
+       struct of_regulator_match *regulator_matches;
+       unsigned int regulator_matches_size;
 
        np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
        if (!np) {
@@ -158,8 +274,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
-                       MAX14577_REG_MAX);
+       switch (dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               regulator_matches = max77836_regulator_matches;
+               regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
+               break;
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               regulator_matches = max14577_regulator_matches;
+               regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
+       }
+
+       ret = of_regulator_match(&pdev->dev, np, regulator_matches,
+                       regulator_matches_size);
        if (ret < 0)
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
        else
@@ -170,31 +297,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
        return ret;
 }
 
-static inline struct regulator_init_data *match_init_data(int index)
+static inline struct regulator_init_data *match_init_data(int index,
+               enum maxim_device_type dev_type)
 {
-       return max14577_regulator_matches[index].init_data;
+       switch (dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               return max77836_regulator_matches[index].init_data;
+
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               return max14577_regulator_matches[index].init_data;
+       }
 }
 
-static inline struct device_node *match_of_node(int index)
+static inline struct device_node *match_of_node(int index,
+               enum maxim_device_type dev_type)
 {
-       return max14577_regulator_matches[index].of_node;
+       switch (dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               return max77836_regulator_matches[index].of_node;
+
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               return max14577_regulator_matches[index].of_node;
+       }
 }
 #else /* CONFIG_OF */
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
+static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
+               enum maxim_device_type dev_type)
 {
        return 0;
 }
-static inline struct regulator_init_data *match_init_data(int index)
+static inline struct regulator_init_data *match_init_data(int index,
+               enum maxim_device_type dev_type)
 {
        return NULL;
 }
 
-static inline struct device_node *match_of_node(int index)
+static inline struct device_node *match_of_node(int index,
+               enum maxim_device_type dev_type)
 {
        return NULL;
 }
 #endif /* CONFIG_OF */
 
+/**
+ * Registers for regulators of max77836 use different I2C slave addresses so
+ * different regmaps must be used for them.
+ *
+ * Returns proper regmap for accessing regulator passed by id.
+ */
+static struct regmap *max14577_get_regmap(struct max14577 *max14577,
+               int reg_id)
+{
+       switch (max14577->dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               switch (reg_id) {
+               case MAX77836_SAFEOUT ... MAX77836_CHARGER:
+                       return max14577->regmap;
+               default:
+                       /* MAX77836_LDO1 ... MAX77836_LDO2 */
+                       return max14577->regmap_pmic;
+               }
+
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               return max14577->regmap;
+       }
+}
 
 static int max14577_regulator_probe(struct platform_device *pdev)
 {
@@ -202,15 +372,29 @@ static int max14577_regulator_probe(struct platform_device *pdev)
        struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
        int i, ret;
        struct regulator_config config = {};
+       const struct regulator_desc *supported_regulators;
+       unsigned int supported_regulators_size;
+       enum maxim_device_type dev_type = max14577->dev_type;
 
-       ret = max14577_regulator_dt_parse_pdata(pdev);
+       ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
        if (ret)
                return ret;
 
+       switch (dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               supported_regulators = max77836_supported_regulators;
+               supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators);
+               break;
+       case MAXIM_DEVICE_TYPE_MAX14577:
+       default:
+               supported_regulators = max14577_supported_regulators;
+               supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
+       }
+
        config.dev = &pdev->dev;
-       config.regmap = max14577->regmap;
+       config.driver_data = max14577;
 
-       for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
+       for (i = 0; i < supported_regulators_size; i++) {
                struct regulator_dev *regulator;
                /*
                 * Index of supported_regulators[] is also the id and must
@@ -220,17 +404,19 @@ static int max14577_regulator_probe(struct platform_device *pdev)
                        config.init_data = pdata->regulators[i].initdata;
                        config.of_node = pdata->regulators[i].of_node;
                } else {
-                       config.init_data = match_init_data(i);
-                       config.of_node = match_of_node(i);
+                       config.init_data = match_init_data(i, dev_type);
+                       config.of_node = match_of_node(i, dev_type);
                }
+               config.regmap = max14577_get_regmap(max14577,
+                               supported_regulators[i].id);
 
                regulator = devm_regulator_register(&pdev->dev,
                                &supported_regulators[i], &config);
                if (IS_ERR(regulator)) {
                        ret = PTR_ERR(regulator);
                        dev_err(&pdev->dev,
-                                       "Regulator init failed for ID %d with error: %d\n",
-                                       i, ret);
+                                       "Regulator init failed for %d/%s with error: %d\n",
+                                       i, supported_regulators[i].name, ret);
                        return ret;
                }
        }
@@ -238,20 +424,41 @@ static int max14577_regulator_probe(struct platform_device *pdev)
        return ret;
 }
 
+static const struct platform_device_id max14577_regulator_id[] = {
+       { "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, },
+       { "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, max14577_regulator_id);
+
 static struct platform_driver max14577_regulator_driver = {
        .driver = {
                   .owner = THIS_MODULE,
                   .name = "max14577-regulator",
                   },
-       .probe  = max14577_regulator_probe,
+       .probe          = max14577_regulator_probe,
+       .id_table       = max14577_regulator_id,
 };
 
 static int __init max14577_regulator_init(void)
 {
+       /* Check for valid values for charger */
        BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
                        MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
                        MAX14577_REGULATOR_CURRENT_LIMIT_MAX);
-       BUILD_BUG_ON(ARRAY_SIZE(supported_regulators) != MAX14577_REG_MAX);
+       BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START +
+                       MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
+                       MAX77836_REGULATOR_CURRENT_LIMIT_MAX);
+       /* Valid charger current values must be provided for each chipset */
+       BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);
+
+       BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM);
+       BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM);
+
+       BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN +
+                       (MAX77836_REGULATOR_LDO_VOLTAGE_STEP *
+                         (MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) !=
+                       MAX77836_REGULATOR_LDO_VOLTAGE_MAX);
 
        return platform_driver_register(&max14577_regulator_driver);
 }
@@ -264,6 +471,6 @@ static void __exit max14577_regulator_exit(void)
 module_exit(max14577_regulator_exit);
 
 MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-MODULE_DESCRIPTION("MAXIM 14577 regulator driver");
+MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:max14577-regulator");
index ea4f36f2cbe2f1e5432e594711fdb5d4c2c677c6..4672cd2f4632a1bc43fb66bc9f035210287824c6 100644 (file)
@@ -106,6 +106,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
 
+struct devm_of_regulator_matches {
+       struct of_regulator_match *matches;
+       unsigned int num_matches;
+};
+
+static void devm_of_regulator_put_matches(struct device *dev, void *res)
+{
+       struct devm_of_regulator_matches *devm_matches = res;
+       int i;
+
+       for (i = 0; i < devm_matches->num_matches; i++)
+               of_node_put(devm_matches->matches[i].of_node);
+}
+
 /**
  * of_regulator_match - extract multiple regulator init data from device tree.
  * @dev: device requesting the data
@@ -119,7 +133,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
  * regulator. The data parsed from a child node will be matched to a regulator
  * based on either the deprecated property regulator-compatible if present,
  * or otherwise the child node's name. Note that the match table is modified
- * in place.
+ * in place and an additional of_node reference is taken for each matched
+ * regulator.
  *
  * Returns the number of matches found or a negative error code on failure.
  */
@@ -131,10 +146,22 @@ int of_regulator_match(struct device *dev, struct device_node *node,
        unsigned int i;
        const char *name;
        struct device_node *child;
+       struct devm_of_regulator_matches *devm_matches;
 
        if (!dev || !node)
                return -EINVAL;
 
+       devm_matches = devres_alloc(devm_of_regulator_put_matches,
+                                   sizeof(struct devm_of_regulator_matches),
+                                   GFP_KERNEL);
+       if (!devm_matches)
+               return -ENOMEM;
+
+       devm_matches->matches = matches;
+       devm_matches->num_matches = num_matches;
+
+       devres_add(dev, devm_matches);
+
        for (i = 0; i < num_matches; i++) {
                struct of_regulator_match *match = &matches[i];
                match->init_data = NULL;
@@ -162,7 +189,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,
                                        child->name);
                                return -EINVAL;
                        }
-                       match->of_node = child;
+                       match->of_node = of_node_get(child);
                        count++;
                        break;
                }
index 6d38be3d970ca72b48d0a44c950da341071edb53..708ddbb83e29f0578b422ba2dd1175f51fd31bb3 100644 (file)
@@ -49,33 +49,13 @@ static const unsigned int pbias_volt_table[] = {
        3000000
 };
 
-static int pbias_regulator_enable(struct regulator_dev *rdev)
-{
-       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
-       const struct pbias_reg_info *info = data->info;
-
-       return regmap_update_bits(data->syscon, rdev->desc->enable_reg,
-                                 info->enable_mask, info->enable);
-}
-
-static int pbias_regulator_is_enable(struct regulator_dev *rdev)
-{
-       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
-       const struct pbias_reg_info *info = data->info;
-       int value;
-
-       regmap_read(data->syscon, rdev->desc->enable_reg, &value);
-
-       return (value & info->enable_mask) == info->enable;
-}
-
 static struct regulator_ops pbias_regulator_voltage_ops = {
        .list_voltage = regulator_list_voltage_table,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
-       .enable = pbias_regulator_enable,
+       .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
-       .is_enabled = pbias_regulator_is_enable,
+       .is_enabled = regulator_is_enabled_regmap,
 };
 
 static const struct pbias_reg_info pbias_mmc_omap2430 = {
@@ -180,6 +160,7 @@ static int pbias_regulator_probe(struct platform_device *pdev)
                drvdata[data_idx].desc.vsel_mask = info->vmode;
                drvdata[data_idx].desc.enable_reg = res->start;
                drvdata[data_idx].desc.enable_mask = info->enable_mask;
+               drvdata[data_idx].desc.enable_val = info->enable;
 
                cfg.init_data = pbias_matches[idx].init_data;
                cfg.driver_data = &drvdata[data_idx];
index e713c162fbd41bd1e3ff7d52782a813d42e70986..1583d4eaf911f671a148aad68b9c96d7dc9c7a09 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
+#include <linux/of_gpio.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s2mps11.h>
 #include <linux/mfd/samsung/s2mps14.h>
@@ -44,6 +45,8 @@ struct s2mps11_info {
         * was enabled.
         */
        unsigned int s2mps14_suspend_state:30;
+       /* Array of size rdev_num with GPIO-s for external sleep control */
+       int *ext_control_gpio;
 };
 
 static int get_ramp_delay(int ramp_delay)
@@ -409,6 +412,8 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
 
        if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
                val = S2MPS14_ENABLE_SUSPEND;
+       else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
+               val = S2MPS14_ENABLE_EXT_CONTROL;
        else
                val = rdev->desc->enable_mask;
 
@@ -565,12 +570,61 @@ static const struct regulator_desc s2mps14_regulators[] = {
        regulator_desc_s2mps14_buck1235(5),
 };
 
+static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
+               struct regulator_dev *rdev)
+{
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                       rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL);
+}
+
+static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
+               struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
+{
+       int *gpio = s2mps11->ext_control_gpio;
+       unsigned int i;
+       unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
+               S2MPS14_LDO12 };
+
+       for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) {
+               unsigned int reg = valid_regulators[i];
+
+               if (!rdata[reg].init_data || !rdata[reg].of_node)
+                       continue;
+
+               gpio[reg] = of_get_named_gpio(rdata[reg].of_node,
+                               "samsung,ext-control-gpios", 0);
+               if (gpio_is_valid(gpio[reg]))
+                       dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n",
+                                       gpio[reg], reg, rdata[reg].name);
+       }
+}
+
+static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
+               struct of_regulator_match *rdata, struct s2mps11_info *s2mps11,
+               enum sec_device_type dev_type)
+{
+       struct device_node *reg_np;
+
+       reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
+       if (!reg_np) {
+               dev_err(&pdev->dev, "could not find regulators sub-node\n");
+               return -EINVAL;
+       }
+
+       of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+       if (dev_type == S2MPS14X)
+               s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11);
+
+       of_node_put(reg_np);
+
+       return 0;
+}
+
 static int s2mps11_pmic_probe(struct platform_device *pdev)
 {
        struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-       struct sec_platform_data *pdata = iodev->pdata;
+       struct sec_platform_data *pdata = NULL;
        struct of_regulator_match *rdata = NULL;
-       struct device_node *reg_np = NULL;
        struct regulator_config config = { };
        struct s2mps11_info *s2mps11;
        int i, ret = 0;
@@ -597,8 +651,21 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
                return -EINVAL;
        };
 
+       s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev,
+                       sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num,
+                       GFP_KERNEL);
+       if (!s2mps11->ext_control_gpio)
+               return -ENOMEM;
+       /*
+        * 0 is a valid GPIO so initialize all GPIO-s to negative value
+        * to indicate that external control won't be used for this regulator.
+        */
+       for (i = 0; i < s2mps11->rdev_num; i++)
+               s2mps11->ext_control_gpio[i] = -EINVAL;
+
        if (!iodev->dev->of_node) {
-               if (pdata) {
+               if (iodev->pdata) {
+                       pdata = iodev->pdata;
                        goto common_reg;
                } else {
                        dev_err(pdev->dev.parent,
@@ -614,15 +681,9 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
        for (i = 0; i < s2mps11->rdev_num; i++)
                rdata[i].name = regulators[i].name;
 
-       reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators");
-       if (!reg_np) {
-               dev_err(&pdev->dev, "could not find regulators sub-node\n");
-               ret = -EINVAL;
+       ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type);
+       if (ret)
                goto out;
-       }
-
-       of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
-       of_node_put(reg_np);
 
 common_reg:
        platform_set_drvdata(pdev, s2mps11);
@@ -630,16 +691,18 @@ common_reg:
        config.dev = &pdev->dev;
        config.regmap = iodev->regmap_pmic;
        config.driver_data = s2mps11;
+       config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
        for (i = 0; i < s2mps11->rdev_num; i++) {
                struct regulator_dev *regulator;
 
-               if (!reg_np) {
+               if (pdata) {
                        config.init_data = pdata->regulators[i].initdata;
                        config.of_node = pdata->regulators[i].reg_node;
                } else {
                        config.init_data = rdata[i].init_data;
                        config.of_node = rdata[i].of_node;
                }
+               config.ena_gpio = s2mps11->ext_control_gpio[i];
 
                regulator = devm_regulator_register(&pdev->dev,
                                                &regulators[i], &config);
@@ -649,6 +712,17 @@ common_reg:
                                i);
                        goto out;
                }
+
+               if (gpio_is_valid(s2mps11->ext_control_gpio[i])) {
+                       ret = s2mps14_pmic_enable_ext_control(s2mps11,
+                                       regulator);
+                       if (ret < 0) {
+                               dev_err(&pdev->dev,
+                                               "failed to enable GPIO control over %s: %d\n",
+                                               regulator->desc->name, ret);
+                               goto out;
+                       }
+               }
        }
 
 out:
index 92f19a005dc3f49d0b2ec5384af5e03fde72e155..c79af943a5c03ed06c0ef72ab216f3ca67789a8e 100644 (file)
@@ -28,7 +28,6 @@ struct s5m8767_info {
        struct device *dev;
        struct sec_pmic_dev *iodev;
        int num_regulators;
-       struct regulator_dev **rdev;
        struct sec_opmode_data *opmode;
 
        int ramp_delay;
@@ -529,16 +528,6 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
        return 0;
 }
 
-static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
-               struct sec_regulator_data *rdata,
-               struct device_node *reg_np)
-{
-       rdata->ext_control_gpio = of_get_named_gpio(reg_np,
-                       "s5m8767,pmic-ext-control-gpios", 0);
-       if (!gpio_is_valid(rdata->ext_control_gpio))
-               rdata->ext_control_gpio = 0;
-}
-
 static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                                        struct sec_platform_data *pdata)
 {
@@ -587,7 +576,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                        continue;
                }
 
-               s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
+               rdata->ext_control_gpio = of_get_named_gpio(reg_np,
+                       "s5m8767,pmic-ext-control-gpios", 0);
 
                rdata->id = i;
                rdata->initdata = of_get_regulator_init_data(
@@ -695,7 +685,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
        struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct sec_platform_data *pdata = iodev->pdata;
        struct regulator_config config = { };
-       struct regulator_dev **rdev;
        struct s5m8767_info *s5m8767;
        int i, ret, size, buck_init;
 
@@ -737,11 +726,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
-       s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!s5m8767->rdev)
-               return -ENOMEM;
 
-       rdev = s5m8767->rdev;
        s5m8767->dev = &pdev->dev;
        s5m8767->iodev = iodev;
        s5m8767->num_regulators = pdata->num_regulators;
@@ -938,6 +923,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                const struct sec_voltage_desc *desc;
                int id = pdata->regulators[i].id;
                int enable_reg, enable_val;
+               struct regulator_dev *rdev;
 
                desc = reg_voltage_map[id];
                if (desc) {
@@ -964,26 +950,27 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                config.driver_data = s5m8767;
                config.regmap = iodev->regmap_pmic;
                config.of_node = pdata->regulators[i].reg_node;
-               config.ena_gpio = config.ena_gpio_flags = 0;
-               if (pdata->regulators[i].ext_control_gpio)
+               config.ena_gpio = -EINVAL;
+               config.ena_gpio_flags = 0;
+               if (gpio_is_valid(pdata->regulators[i].ext_control_gpio))
                        s5m8767_regulator_config_ext_control(s5m8767,
                                        &pdata->regulators[i], &config);
 
-               rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
+               rdev = devm_regulator_register(&pdev->dev, &regulators[id],
                                                  &config);
-               if (IS_ERR(rdev[i])) {
-                       ret = PTR_ERR(rdev[i]);
+               if (IS_ERR(rdev)) {
+                       ret = PTR_ERR(rdev);
                        dev_err(s5m8767->dev, "regulator init failed for %d\n",
                                        id);
                        return ret;
                }
 
-               if (pdata->regulators[i].ext_control_gpio) {
-                       ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
+               if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) {
+                       ret = s5m8767_enable_ext_control(s5m8767, rdev);
                        if (ret < 0) {
                                dev_err(s5m8767->dev,
                                                "failed to enable gpio control over %s: %d\n",
-                                               rdev[i]->desc->name, ret);
+                                               rdev->desc->name, ret);
                                return ret;
                        }
                }
index 2e92ef68574da733e6fd81d3aed1760e627d5bc4..2064b3fd45f76c35013ae69a17d6726fc024cf79 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/mfd/tps65090.h>
 
+#define MAX_CTRL_READ_TRIES    5
+#define MAX_FET_ENABLE_TRIES   1000
+
+#define CTRL_EN_BIT            0 /* Regulator enable bit, active high */
+#define CTRL_WT_BIT            2 /* Regulator wait time 0 bit */
+#define CTRL_PG_BIT            4 /* Regulator power good bit, 1=good */
+#define CTRL_TO_BIT            7 /* Regulator timeout bit, 1=wait */
+
+#define MAX_OVERCURRENT_WAIT   3 /* Overcurrent wait must be <= this */
+
+/**
+ * struct tps65090_regulator - Per-regulator data for a tps65090 regulator
+ *
+ * @dev: Pointer to our device.
+ * @desc: The struct regulator_desc for the regulator.
+ * @rdev: The struct regulator_dev for the regulator.
+ * @overcurrent_wait_valid: True if overcurrent_wait is valid.
+ * @overcurrent_wait: For FETs, the value to put in the WTFET bitfield.
+ */
+
 struct tps65090_regulator {
        struct device           *dev;
        struct regulator_desc   *desc;
        struct regulator_dev    *rdev;
+       bool                    overcurrent_wait_valid;
+       int                     overcurrent_wait;
 };
 
 static struct regulator_ops tps65090_ext_control_ops = {
 };
 
-static struct regulator_ops tps65090_reg_contol_ops = {
+/**
+ * tps65090_reg_set_overcurrent_wait - Setup overcurrent wait
+ *
+ * This will set the overcurrent wait time based on what's in the regulator
+ * info.
+ *
+ * @ri:                Overall regulator data
+ * @rdev:      Regulator device
+ *
+ * Return: 0 if no error, non-zero if there was an error writing the register.
+ */
+static int tps65090_reg_set_overcurrent_wait(struct tps65090_regulator *ri,
+                                            struct regulator_dev *rdev)
+{
+       int ret;
+
+       ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                                MAX_OVERCURRENT_WAIT << CTRL_WT_BIT,
+                                ri->overcurrent_wait << CTRL_WT_BIT);
+       if (ret) {
+               dev_err(&rdev->dev, "Error updating overcurrent wait %#x\n",
+                       rdev->desc->enable_reg);
+       }
+
+       return ret;
+}
+
+/**
+ * tps65090_try_enable_fet - Try to enable a FET
+ *
+ * @rdev:      Regulator device
+ *
+ * Return: 0 if ok, -ENOTRECOVERABLE if the FET power good bit did not get
+ * set, or some other -ve value if another error occurred (e.g. i2c error)
+ */
+static int tps65090_try_enable_fet(struct regulator_dev *rdev)
+{
+       unsigned int control;
+       int ret, i;
+
+       ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                                rdev->desc->enable_mask,
+                                rdev->desc->enable_mask);
+       if (ret < 0) {
+               dev_err(&rdev->dev, "Error in updating reg %#x\n",
+                       rdev->desc->enable_reg);
+               return ret;
+       }
+
+       for (i = 0; i < MAX_CTRL_READ_TRIES; i++) {
+               ret = regmap_read(rdev->regmap, rdev->desc->enable_reg,
+                                 &control);
+               if (ret < 0)
+                       return ret;
+
+               if (!(control & BIT(CTRL_TO_BIT)))
+                       break;
+
+               usleep_range(1000, 1500);
+       }
+       if (!(control & BIT(CTRL_PG_BIT)))
+               return -ENOTRECOVERABLE;
+
+       return 0;
+}
+
+/**
+ * tps65090_fet_enable - Enable a FET, trying a few times if it fails
+ *
+ * Some versions of the tps65090 have issues when turning on the FETs.
+ * This function goes through several steps to ensure the best chance of the
+ * FET going on.  Specifically:
+ * - We'll make sure that we bump the "overcurrent wait" to the maximum, which
+ *   increases the chances that we'll turn on properly.
+ * - We'll retry turning the FET on multiple times (turning off in between).
+ *
+ * @rdev:      Regulator device
+ *
+ * Return: 0 if ok, non-zero if it fails.
+ */
+static int tps65090_fet_enable(struct regulator_dev *rdev)
+{
+       int ret, tries;
+
+       /*
+        * Try enabling multiple times until we succeed since sometimes the
+        * first try times out.
+        */
+       tries = 0;
+       while (true) {
+               ret = tps65090_try_enable_fet(rdev);
+               if (!ret)
+                       break;
+               if (ret != -ENOTRECOVERABLE || tries == MAX_FET_ENABLE_TRIES)
+                       goto err;
+
+               /* Try turning the FET off (and then on again) */
+               ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                                        rdev->desc->enable_mask, 0);
+               if (ret)
+                       goto err;
+
+               tries++;
+       }
+
+       if (tries)
+               dev_warn(&rdev->dev, "reg %#x enable ok after %d tries\n",
+                        rdev->desc->enable_reg, tries);
+
+       return 0;
+err:
+       dev_warn(&rdev->dev, "reg %#x enable failed\n", rdev->desc->enable_reg);
+       WARN_ON(1);
+
+       return ret;
+}
+
+static struct regulator_ops tps65090_reg_control_ops = {
        .enable         = regulator_enable_regmap,
        .disable        = regulator_disable_regmap,
        .is_enabled     = regulator_is_enabled_regmap,
 };
 
+static struct regulator_ops tps65090_fet_control_ops = {
+       .enable         = tps65090_fet_enable,
+       .disable        = regulator_disable_regmap,
+       .is_enabled     = regulator_is_enabled_regmap,
+};
+
 static struct regulator_ops tps65090_ldo_ops = {
 };
 
-#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops)  \
+#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _ops)        \
 {                                                      \
        .name = "TPS65090_RAILS"#_id,                   \
        .supply_name = _sname,                          \
        .id = TPS65090_REGULATOR_##_id,                 \
        .ops = &_ops,                                   \
        .enable_reg = _en_reg,                          \
-       .enable_mask = BIT(0),                          \
+       .enable_val = _en_bits,                         \
+       .enable_mask = _en_bits,                        \
        .type = REGULATOR_VOLTAGE,                      \
        .owner = THIS_MODULE,                           \
 }
 
 static struct regulator_desc tps65090_regulator_desc[] = {
-       tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(LDO1,  "vsys-l1", 0,    tps65090_ldo_ops),
-       tps65090_REG_DESC(LDO2,  "vsys-l2", 0,    tps65090_ldo_ops),
+       tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, BIT(CTRL_EN_BIT),
+                         tps65090_reg_control_ops),
+       tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, BIT(CTRL_EN_BIT),
+                         tps65090_reg_control_ops),
+       tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, BIT(CTRL_EN_BIT),
+                         tps65090_reg_control_ops),
+
+       tps65090_REG_DESC(FET1,  "infet1",  0x0F,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+       tps65090_REG_DESC(FET2,  "infet2",  0x10,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+       tps65090_REG_DESC(FET3,  "infet3",  0x11,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+       tps65090_REG_DESC(FET4,  "infet4",  0x12,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+       tps65090_REG_DESC(FET5,  "infet5",  0x13,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+       tps65090_REG_DESC(FET6,  "infet6",  0x14,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+       tps65090_REG_DESC(FET7,  "infet7",  0x15,
+                         BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+                         tps65090_fet_control_ops),
+
+       tps65090_REG_DESC(LDO1,  "vsys-l1", 0, 0,
+                         tps65090_ldo_ops),
+       tps65090_REG_DESC(LDO2,  "vsys-l2", 0, 0,
+                         tps65090_ldo_ops),
 };
 
 static inline bool is_dcdc(int id)
@@ -209,6 +377,11 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
                        rpdata->gpio = of_get_named_gpio(np,
                                        "dcdc-ext-control-gpios", 0);
 
+               if (of_property_read_u32(tps65090_matches[idx].of_node,
+                                        "ti,overcurrent-wait",
+                                        &rpdata->overcurrent_wait) == 0)
+                       rpdata->overcurrent_wait_valid = true;
+
                tps65090_pdata->reg_pdata[idx] = rpdata;
        }
        return tps65090_pdata;
@@ -258,6 +431,11 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
                ri = &pmic[num];
                ri->dev = &pdev->dev;
                ri->desc = &tps65090_regulator_desc[num];
+               if (tps_pdata) {
+                       ri->overcurrent_wait_valid =
+                               tps_pdata->overcurrent_wait_valid;
+                       ri->overcurrent_wait = tps_pdata->overcurrent_wait;
+               }
 
                /*
                 * TPS5090 DCDC support the control from external digital input.
@@ -299,6 +477,12 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
                }
                ri->rdev = rdev;
 
+               if (ri->overcurrent_wait_valid) {
+                       ret = tps65090_reg_set_overcurrent_wait(ri, rdev);
+                       if (ret < 0)
+                               return ret;
+               }
+
                /* Enable external control if it is require */
                if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&
                                tps_pdata->enable_ext_control) {
index 10b78d2b766aa3394b1ee51b2bf47e616f6f95d4..f7ed20a5a8b9a2907135abc52bfc5097e146adb6 100644 (file)
@@ -134,6 +134,7 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = tps65217_pmic_set_voltage_sel,
        .list_voltage           = regulator_list_voltage_table,
+       .map_voltage            = regulator_map_voltage_ascend,
 };
 
 static const struct regulator_desc regulators[] = {
@@ -257,9 +258,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
                                pdev->name);
                        return PTR_ERR(rdev);
                }
-
-               /* Save regulator for cleanup */
-               tps->rdev[i] = rdev;
        }
        return 0;
 }
index 4f60caf750ceb90e860e00d9ffed55cd74a4ec03..60fed3d7820b75fc0a0a8fd2157bb7a84918ff79 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
new file mode 100644 (file)
index 0000000..79c32ca
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2014 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * based on
+ * Allwinner SoCs Reset Controller driver
+ *
+ * Copyright 2013 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.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/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define NR_BANKS               4
+#define OFFSET_MODRST          0x10
+
+struct socfpga_reset_data {
+       spinlock_t                      lock;
+       void __iomem                    *membase;
+       struct reset_controller_dev     rcdev;
+};
+
+static int socfpga_reset_assert(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       struct socfpga_reset_data *data = container_of(rcdev,
+                                                    struct socfpga_reset_data,
+                                                    rcdev);
+       int bank = id / BITS_PER_LONG;
+       int offset = id % BITS_PER_LONG;
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&data->lock, flags);
+
+       reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS));
+       writel(reg | BIT(offset), data->membase + OFFSET_MODRST +
+                                (bank * NR_BANKS));
+       spin_unlock_irqrestore(&data->lock, flags);
+
+       return 0;
+}
+
+static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
+                                 unsigned long id)
+{
+       struct socfpga_reset_data *data = container_of(rcdev,
+                                                    struct socfpga_reset_data,
+                                                    rcdev);
+
+       int bank = id / BITS_PER_LONG;
+       int offset = id % BITS_PER_LONG;
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&data->lock, flags);
+
+       reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS));
+       writel(reg & ~BIT(offset), data->membase + OFFSET_MODRST +
+                                 (bank * NR_BANKS));
+
+       spin_unlock_irqrestore(&data->lock, flags);
+
+       return 0;
+}
+
+static struct reset_control_ops socfpga_reset_ops = {
+       .assert         = socfpga_reset_assert,
+       .deassert       = socfpga_reset_deassert,
+};
+
+static int socfpga_reset_probe(struct platform_device *pdev)
+{
+       struct socfpga_reset_data *data;
+       struct resource *res;
+
+       /*
+        * The binding was mainlined without the required property.
+        * Do not continue, when we encounter an old DT.
+        */
+       if (!of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) {
+               dev_err(&pdev->dev, "%s missing #reset-cells property\n",
+                       pdev->dev.of_node->full_name);
+               return -EINVAL;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->membase))
+               return PTR_ERR(data->membase);
+
+       spin_lock_init(&data->lock);
+
+       data->rcdev.owner = THIS_MODULE;
+       data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG;
+       data->rcdev.ops = &socfpga_reset_ops;
+       data->rcdev.of_node = pdev->dev.of_node;
+       reset_controller_register(&data->rcdev);
+
+       return 0;
+}
+
+static int socfpga_reset_remove(struct platform_device *pdev)
+{
+       struct socfpga_reset_data *data = platform_get_drvdata(pdev);
+
+       reset_controller_unregister(&data->rcdev);
+
+       return 0;
+}
+
+static const struct of_device_id socfpga_reset_dt_ids[] = {
+       { .compatible = "altr,rst-mgr", },
+       { /* sentinel */ },
+};
+
+static struct platform_driver socfpga_reset_driver = {
+       .probe  = socfpga_reset_probe,
+       .remove = socfpga_reset_remove,
+       .driver = {
+               .name           = "socfpga-reset",
+               .owner          = THIS_MODULE,
+               .of_match_table = socfpga_reset_dt_ids,
+       },
+};
+module_platform_driver(socfpga_reset_driver);
+
+MODULE_AUTHOR("Steffen Trumtrar <s.trumtrar@pengutronix.de");
+MODULE_DESCRIPTION("Socfpga Reset Controller Driver");
+MODULE_LICENSE("GPL");
index 476af93543f6efa24c9fbb8c6d28fa64de732fde..8ec2d6a1dbe1a8aedc326750399db6be1b5a7d15 100644 (file)
@@ -40,6 +40,7 @@
 
 struct s5m_rtc_info {
        struct device *dev;
+       struct i2c_client *i2c;
        struct sec_pmic_dev *s5m87xx;
        struct regmap *regmap;
        struct rtc_device *rtc_dev;
@@ -49,6 +50,20 @@ struct s5m_rtc_info {
        bool wtsr_smpl;
 };
 
+static const struct regmap_config s5m_rtc_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = SEC_RTC_REG_MAX,
+};
+
+static const struct regmap_config s2mps14_rtc_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S2MPS_RTC_REG_MAX,
+};
+
 static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm,
                               int rtc_24hr_mode)
 {
@@ -554,6 +569,7 @@ static int s5m_rtc_probe(struct platform_device *pdev)
        struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);
        struct sec_platform_data *pdata = s5m87xx->pdata;
        struct s5m_rtc_info *info;
+       const struct regmap_config *regmap_cfg;
        int ret;
 
        if (!pdata) {
@@ -565,9 +581,37 @@ static int s5m_rtc_probe(struct platform_device *pdev)
        if (!info)
                return -ENOMEM;
 
+       switch (pdata->device_type) {
+       case S2MPS14X:
+               regmap_cfg = &s2mps14_rtc_regmap_config;
+               break;
+       case S5M8763X:
+               regmap_cfg = &s5m_rtc_regmap_config;
+               break;
+       case S5M8767X:
+               regmap_cfg = &s5m_rtc_regmap_config;
+               break;
+       default:
+               dev_err(&pdev->dev, "Device type is not supported by RTC driver\n");
+               return -ENODEV;
+       }
+
+       info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR);
+       if (!info->i2c) {
+               dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n");
+               return -ENODEV;
+       }
+
+       info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg);
+       if (IS_ERR(info->regmap)) {
+               ret = PTR_ERR(info->regmap);
+               dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n",
+                               ret);
+               goto err;
+       }
+
        info->dev = &pdev->dev;
        info->s5m87xx = s5m87xx;
-       info->regmap = s5m87xx->regmap_rtc;
        info->device_type = s5m87xx->device_type;
        info->wtsr_smpl = s5m87xx->wtsr_smpl;
 
@@ -585,7 +629,7 @@ static int s5m_rtc_probe(struct platform_device *pdev)
        default:
                ret = -EINVAL;
                dev_err(&pdev->dev, "Unsupported device type: %d\n", ret);
-               return ret;
+               goto err;
        }
 
        platform_set_drvdata(pdev, info);
@@ -602,15 +646,24 @@ static int s5m_rtc_probe(struct platform_device *pdev)
        info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc",
                                                 &s5m_rtc_ops, THIS_MODULE);
 
-       if (IS_ERR(info->rtc_dev))
-               return PTR_ERR(info->rtc_dev);
+       if (IS_ERR(info->rtc_dev)) {
+               ret = PTR_ERR(info->rtc_dev);
+               goto err;
+       }
 
        ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
                                        s5m_rtc_alarm_irq, 0, "rtc-alarm0",
                                        info);
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
                        info->irq, ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       i2c_unregister_device(info->i2c);
 
        return ret;
 }
@@ -639,6 +692,17 @@ static void s5m_rtc_shutdown(struct platform_device *pdev)
        s5m_rtc_enable_smpl(info, false);
 }
 
+static int s5m_rtc_remove(struct platform_device *pdev)
+{
+       struct s5m_rtc_info *info = platform_get_drvdata(pdev);
+
+       /* Perform also all shutdown steps when removing */
+       s5m_rtc_shutdown(pdev);
+       i2c_unregister_device(info->i2c);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int s5m_rtc_resume(struct device *dev)
 {
@@ -676,6 +740,7 @@ static struct platform_driver s5m_rtc_driver = {
                .pm     = &s5m_rtc_pm_ops,
        },
        .probe          = s5m_rtc_probe,
+       .remove         = s5m_rtc_remove,
        .shutdown       = s5m_rtc_shutdown,
        .id_table       = s5m_rtc_id,
 };
index b69ab17f13fabef4afc6c44a62534d549505db12..629fcc275e923b172a51a13dd419b4365319b1de 100644 (file)
@@ -33,4 +33,4 @@ obj-$(CONFIG_MONWRITER) += monwriter.o
 obj-$(CONFIG_S390_VMUR) += vmur.o
 
 zcore_mod-objs := sclp_sdias.o zcore.o
-obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o
+obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
index 3d8e4d63f51418c876f9918e0be77be628d2afb3..1884653e4472423bbb9e95fc7aa1dfdffa085495 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/miscdevice.h>
 #include <linux/debugfs.h>
 #include <linux/module.h>
+#include <linux/memblock.h>
+
 #include <asm/asm-offsets.h>
 #include <asm/ipl.h>
 #include <asm/sclp.h>
@@ -411,33 +413,24 @@ static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        return simple_read_from_buffer(buf, count, ppos, filp->private_data,
-                                      MEMORY_CHUNKS * CHUNK_INFO_SIZE);
+                                      memblock.memory.cnt * CHUNK_INFO_SIZE);
 }
 
 static int zcore_memmap_open(struct inode *inode, struct file *filp)
 {
-       int i;
+       struct memblock_region *reg;
        char *buf;
-       struct mem_chunk *chunk_array;
+       int i = 0;
 
-       chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk),
-                             GFP_KERNEL);
-       if (!chunk_array)
-               return -ENOMEM;
-       detect_memory_layout(chunk_array, 0);
-       buf = kzalloc(MEMORY_CHUNKS * CHUNK_INFO_SIZE, GFP_KERNEL);
+       buf = kzalloc(memblock.memory.cnt * CHUNK_INFO_SIZE, GFP_KERNEL);
        if (!buf) {
-               kfree(chunk_array);
                return -ENOMEM;
        }
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               sprintf(buf + (i * CHUNK_INFO_SIZE), "%016llx %016llx ",
-                       (unsigned long long) chunk_array[i].addr,
-                       (unsigned long long) chunk_array[i].size);
-               if (chunk_array[i].size == 0)
-                       break;
+       for_each_memblock(memory, reg) {
+               sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ",
+                       (unsigned long long) reg->base,
+                       (unsigned long long) reg->size);
        }
-       kfree(chunk_array);
        filp->private_data = buf;
        return nonseekable_open(inode, filp);
 }
@@ -593,21 +586,12 @@ static int __init check_sdias(void)
 
 static int __init get_mem_info(unsigned long *mem, unsigned long *end)
 {
-       int i;
-       struct mem_chunk *chunk_array;
+       struct memblock_region *reg;
 
-       chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk),
-                             GFP_KERNEL);
-       if (!chunk_array)
-               return -ENOMEM;
-       detect_memory_layout(chunk_array, 0);
-       for (i = 0; i < MEMORY_CHUNKS; i++) {
-               if (chunk_array[i].size == 0)
-                       break;
-               *mem += chunk_array[i].size;
-               *end = max(*end, chunk_array[i].addr + chunk_array[i].size);
+       for_each_memblock(memory, reg) {
+               *mem += reg->size;
+               *end = max_t(unsigned long, *end, reg->base + reg->size);
        }
-       kfree(chunk_array);
        return 0;
 }
 
index 9f0ea6cb6922619dfe04803c284002431110e11f..e3bf885f4a6c29fd77f29b51c219a47c6a04ca7e 100644 (file)
@@ -541,18 +541,27 @@ static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
 
 static void chsc_process_event_information(struct chsc_sei *sei, u64 ntsm)
 {
-       do {
+       static int ntsm_unsupported;
+
+       while (true) {
                memset(sei, 0, sizeof(*sei));
                sei->request.length = 0x0010;
                sei->request.code = 0x000e;
-               sei->ntsm = ntsm;
+               if (!ntsm_unsupported)
+                       sei->ntsm = ntsm;
 
                if (chsc(sei))
                        break;
 
                if (sei->response.code != 0x0001) {
-                       CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
-                                     sei->response.code);
+                       CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x, ntsm=%llx)\n",
+                                     sei->response.code, sei->ntsm);
+
+                       if (sei->response.code == 3 && sei->ntsm) {
+                               /* Fallback for old firmware. */
+                               ntsm_unsupported = 1;
+                               continue;
+                       }
                        break;
                }
 
@@ -568,7 +577,10 @@ static void chsc_process_event_information(struct chsc_sei *sei, u64 ntsm)
                        CIO_CRW_EVENT(2, "chsc: unhandled nt: %d\n", sei->nt);
                        break;
                }
-       } while (sei->u.nt0_area.flags & 0x80);
+
+               if (!(sei->u.nt0_area.flags & 0x80))
+                       break;
+       }
 }
 
 /*
index 1e1fc671f89a4a431b4a04f59fea16e302ad3a30..d2c0b442bce5fb010fc43414a266c34ee245ca54 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/kvm_para.h>
+#include <linux/notifier.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/cio.h>
@@ -62,6 +63,7 @@ struct virtio_ccw_device {
        struct vq_config_block *config_block;
        bool is_thinint;
        bool going_away;
+       bool device_lost;
        void *airq_info;
 };
 
@@ -1010,11 +1012,14 @@ static void virtio_ccw_remove(struct ccw_device *cdev)
        unsigned long flags;
        struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
 
-       if (vcdev && cdev->online)
+       if (vcdev && cdev->online) {
+               if (vcdev->device_lost)
+                       virtio_break_device(&vcdev->vdev);
                unregister_virtio_device(&vcdev->vdev);
-       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       dev_set_drvdata(&cdev->dev, NULL);
-       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+               spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+               dev_set_drvdata(&cdev->dev, NULL);
+               spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+       }
        cdev->handler = NULL;
 }
 
@@ -1023,12 +1028,14 @@ static int virtio_ccw_offline(struct ccw_device *cdev)
        unsigned long flags;
        struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
 
-       if (vcdev) {
-               unregister_virtio_device(&vcdev->vdev);
-               spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-               dev_set_drvdata(&cdev->dev, NULL);
-               spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-       }
+       if (!vcdev)
+               return 0;
+       if (vcdev->device_lost)
+               virtio_break_device(&vcdev->vdev);
+       unregister_virtio_device(&vcdev->vdev);
+       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+       dev_set_drvdata(&cdev->dev, NULL);
+       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
        return 0;
 }
 
@@ -1096,8 +1103,26 @@ out_free:
 
 static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event)
 {
-       /* TODO: Check whether we need special handling here. */
-       return 0;
+       int rc;
+       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+
+       /*
+        * Make sure vcdev is set
+        * i.e. set_offline/remove callback not already running
+        */
+       if (!vcdev)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case CIO_GONE:
+               vcdev->device_lost = true;
+               rc = NOTIFY_DONE;
+               break;
+       default:
+               rc = NOTIFY_DONE;
+               break;
+       }
+       return rc;
 }
 
 static struct ccw_device_id virtio_ids[] = {
index fd7b3bd807896556d0743660069aff8a44c3e072..d837c3c5330fab5c2c77548f31996db3dacad763 100644 (file)
@@ -3348,7 +3348,7 @@ static int __init claw_init(void)
        }
        CLAW_DBF_TEXT(2, setup, "init_mod");
        claw_root_dev = root_device_register("claw");
-       ret = PTR_RET(claw_root_dev);
+       ret = PTR_ERR_OR_ZERO(claw_root_dev);
        if (ret)
                goto register_err;
        ret = ccw_driver_register(&claw_ccw_driver);
index 70b3a023100ef769180d8234f2ac39c3caa91232..03b6ad035577e28553da16fbf4481d9c249a9e6d 100644 (file)
@@ -1837,7 +1837,7 @@ static int __init ctcm_init(void)
        if (ret)
                goto out_err;
        ctcm_root_dev = root_device_register("ctcm");
-       ret = PTR_RET(ctcm_root_dev);
+       ret = PTR_ERR_OR_ZERO(ctcm_root_dev);
        if (ret)
                goto register_err;
        ret = ccw_driver_register(&ctcm_ccw_driver);
index c461f2aac610ea6a8580c504c9a2fbb9dcb92979..8d5d96969c39213a06124934182d938fd834ec7a 100644 (file)
@@ -2442,7 +2442,7 @@ __init lcs_init_module(void)
        if (rc)
                goto out_err;
        lcs_root_dev = root_device_register("lcs");
-       rc = PTR_RET(lcs_root_dev);
+       rc = PTR_ERR_OR_ZERO(lcs_root_dev);
        if (rc)
                goto register_err;
        rc = ccw_driver_register(&lcs_ccw_driver);
index 5333b2c018e781541905e855c7cf3ff0a5d84a9e..a2088af51cc5d809d7513f0c0cb628c0b81910b6 100644 (file)
@@ -268,10 +268,8 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
 #define QETH_NO_PRIO_QUEUEING 0
 #define QETH_PRIO_Q_ING_PREC  1
 #define QETH_PRIO_Q_ING_TOS   2
-#define IP_TOS_LOWDELAY 0x10
-#define IP_TOS_HIGHTHROUGHPUT 0x08
-#define IP_TOS_HIGHRELIABILITY 0x04
-#define IP_TOS_NOTIMPORTANT 0x02
+#define QETH_PRIO_Q_ING_SKB   3
+#define QETH_PRIO_Q_ING_VLAN  4
 
 /* Packing */
 #define QETH_LOW_WATERMARK_PACK  2
index 22470a3b182f0ba04c9a724d1fb26fc716bc19de..34993009a9e12d67df04ff06f10a46d5dd2cb58e 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kthread.h>
 #include <linux/slab.h>
 #include <net/iucv/af_iucv.h>
+#include <net/dsfield.h>
 
 #include <asm/ebcdic.h>
 #include <asm/io.h>
@@ -3670,42 +3671,56 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
 }
 EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);
 
+/**
+ * Note: Function assumes that we have 4 outbound queues.
+ */
 int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
                        int ipv, int cast_type)
 {
-       if (!ipv && (card->info.type == QETH_CARD_TYPE_OSD ||
-                    card->info.type == QETH_CARD_TYPE_OSX))
-               return card->qdio.default_out_queue;
-       switch (card->qdio.no_out_queues) {
-       case 4:
-               if (cast_type && card->info.is_multicast_different)
-                       return card->info.is_multicast_different &
-                               (card->qdio.no_out_queues - 1);
-               if (card->qdio.do_prio_queueing && (ipv == 4)) {
-                       const u8 tos = ip_hdr(skb)->tos;
-
-                       if (card->qdio.do_prio_queueing ==
-                               QETH_PRIO_Q_ING_TOS) {
-                               if (tos & IP_TOS_NOTIMPORTANT)
-                                       return 3;
-                               if (tos & IP_TOS_HIGHRELIABILITY)
-                                       return 2;
-                               if (tos & IP_TOS_HIGHTHROUGHPUT)
-                                       return 1;
-                               if (tos & IP_TOS_LOWDELAY)
-                                       return 0;
-                       }
-                       if (card->qdio.do_prio_queueing ==
-                               QETH_PRIO_Q_ING_PREC)
-                               return 3 - (tos >> 6);
-               } else if (card->qdio.do_prio_queueing && (ipv == 6)) {
-                       /* TODO: IPv6!!! */
+       __be16 *tci;
+       u8 tos;
+
+       if (cast_type && card->info.is_multicast_different)
+               return card->info.is_multicast_different &
+                       (card->qdio.no_out_queues - 1);
+
+       switch (card->qdio.do_prio_queueing) {
+       case QETH_PRIO_Q_ING_TOS:
+       case QETH_PRIO_Q_ING_PREC:
+               switch (ipv) {
+               case 4:
+                       tos = ipv4_get_dsfield(ip_hdr(skb));
+                       break;
+               case 6:
+                       tos = ipv6_get_dsfield(ipv6_hdr(skb));
+                       break;
+               default:
+                       return card->qdio.default_out_queue;
                }
-               return card->qdio.default_out_queue;
-       case 1: /* fallthrough for single-out-queue 1920-device */
+               if (card->qdio.do_prio_queueing == QETH_PRIO_Q_ING_PREC)
+                       return ~tos >> 6 & 3;
+               if (tos & IPTOS_MINCOST)
+                       return 3;
+               if (tos & IPTOS_RELIABILITY)
+                       return 2;
+               if (tos & IPTOS_THROUGHPUT)
+                       return 1;
+               if (tos & IPTOS_LOWDELAY)
+                       return 0;
+               break;
+       case QETH_PRIO_Q_ING_SKB:
+               if (skb->priority > 5)
+                       return 0;
+               return ~skb->priority >> 1 & 3;
+       case QETH_PRIO_Q_ING_VLAN:
+               tci = &((struct ethhdr *)skb->data)->h_proto;
+               if (*tci == ETH_P_8021Q)
+                       return ~*(tci + 1) >> (VLAN_PRIO_SHIFT + 1) & 3;
+               break;
        default:
-               return card->qdio.default_out_queue;
+               break;
        }
+       return card->qdio.default_out_queue;
 }
 EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
 
@@ -5824,7 +5839,7 @@ static int __init qeth_core_init(void)
        if (rc)
                goto out_err;
        qeth_core_root_dev = root_device_register("qeth");
-       rc = PTR_RET(qeth_core_root_dev);
+       rc = PTR_ERR_OR_ZERO(qeth_core_root_dev);
        if (rc)
                goto register_err;
        qeth_core_header_cache = kmem_cache_create("qeth_hdr",
index 425c0ecf1f3b9fd2ae3c2c55f61b1ad10f08c028..8a25a2be9890e7e09af1c9845c5b9b9773472f00 100644 (file)
@@ -217,6 +217,10 @@ static ssize_t qeth_dev_prioqing_show(struct device *dev,
                return sprintf(buf, "%s\n", "by precedence");
        case QETH_PRIO_Q_ING_TOS:
                return sprintf(buf, "%s\n", "by type of service");
+       case QETH_PRIO_Q_ING_SKB:
+               return sprintf(buf, "%s\n", "by skb-priority");
+       case QETH_PRIO_Q_ING_VLAN:
+               return sprintf(buf, "%s\n", "by VLAN headers");
        default:
                return sprintf(buf, "always queue %i\n",
                               card->qdio.default_out_queue);
@@ -250,11 +254,23 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
        }
 
        tmp = strsep((char **) &buf, "\n");
-       if (!strcmp(tmp, "prio_queueing_prec"))
+       if (!strcmp(tmp, "prio_queueing_prec")) {
                card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC;
-       else if (!strcmp(tmp, "prio_queueing_tos"))
+               card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
+       } else if (!strcmp(tmp, "prio_queueing_skb")) {
+               card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_SKB;
+               card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
+       } else if (!strcmp(tmp, "prio_queueing_tos")) {
                card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS;
-       else if (!strcmp(tmp, "no_prio_queueing:0")) {
+               card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
+       } else if (!strcmp(tmp, "prio_queueing_vlan")) {
+               if (!card->options.layer2) {
+                       rc = -ENOTSUPP;
+                       goto out;
+               }
+               card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_VLAN;
+               card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
+       } else if (!strcmp(tmp, "no_prio_queueing:0")) {
                card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
                card->qdio.default_out_queue = 0;
        } else if (!strcmp(tmp, "no_prio_queueing:1")) {
index 8dea3f12ccc1714defe7d4d65869817dd6b69135..e232ceca38fe25a9e984f6e8f195e7a208c3a11b 100644 (file)
@@ -725,15 +725,20 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int elements = 0;
        struct qeth_card *card = dev->ml_priv;
        struct sk_buff *new_skb = skb;
-       int ipv = qeth_get_ip_version(skb);
        int cast_type = qeth_l2_get_cast_type(card, skb);
-       struct qeth_qdio_out_q *queue = card->qdio.out_qs
-               [qeth_get_priority_queue(card, skb, ipv, cast_type)];
+       struct qeth_qdio_out_q *queue;
        int tx_bytes = skb->len;
        int data_offset = -1;
        int elements_needed = 0;
        int hd_len = 0;
 
+       if (card->qdio.do_prio_queueing || (cast_type &&
+                                       card->info.is_multicast_different))
+               queue = card->qdio.out_qs[qeth_get_priority_queue(card, skb,
+                                       qeth_get_ip_version(skb), cast_type)];
+       else
+               queue = card->qdio.out_qs[card->qdio.default_out_queue];
+
        if ((card->state != CARD_STATE_UP) || !card->lan_online) {
                card->stats.tx_carrier_errors++;
                goto tx_drop;
index 3524d34ff694c273afefc7d85bfa17b6bce38af9..c8d91d797ec8a9b571a70e95132f9ee4824e0ffe 100644 (file)
@@ -2926,8 +2926,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct sk_buff *new_skb = NULL;
        int ipv = qeth_get_ip_version(skb);
        int cast_type = qeth_l3_get_cast_type(card, skb);
-       struct qeth_qdio_out_q *queue = card->qdio.out_qs
-               [qeth_get_priority_queue(card, skb, ipv, cast_type)];
+       struct qeth_qdio_out_q *queue =
+               card->qdio.out_qs[card->qdio.do_prio_queueing
+                       || (cast_type && card->info.is_multicast_different) ?
+                       qeth_get_priority_queue(card, skb, ipv, cast_type) :
+                       card->qdio.default_out_queue];
        int tx_bytes = skb->len;
        bool large_send;
        int data_offset = -1;
index 4ccb5d869389e353113692d20f02f66d002046cd..a40ee1e37486bd9b05062074507fd2a64d472677 100644 (file)
@@ -207,7 +207,7 @@ static void jsfd_do_request(struct request_queue *q)
                        goto end;
                }
 
-               jsfd_read(req->buffer, jdp->dbase + offset, len);
+               jsfd_read(bio_data(req->bio), jdp->dbase + offset, len);
                err = 0;
        end:
                if (!__blk_end_request_cur(req, err))
index 7f0af4fcc0019127ab4d60fc0550ed6daa86ffb6..6fd7d40b2c4dea102e15a2e9c76fef3500c09435 100644 (file)
@@ -8293,7 +8293,6 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
 
        mpt2sas_base_free_resources(ioc);
        pci_save_state(pdev);
-       pci_disable_device(pdev);
        pci_set_power_state(pdev, device_state);
        return 0;
 }
index 9db097a28a74588c793c0521c7f80f8540820f61..a0c95cac91f0fe55681830af4477e9513ec19a32 100644 (file)
@@ -140,7 +140,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
        cmd->result = 0;
        spin_lock_irqsave(q->queue_lock, flags);
        blk_requeue_request(q, cmd->request);
-       kblockd_schedule_work(q, &device->requeue_work);
+       kblockd_schedule_work(&device->requeue_work);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -1019,8 +1019,6 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
                return BLKPREP_DEFER;
        }
 
-       req->buffer = NULL;
-
        /* 
         * Next, walk the list, and fill in the addresses and sizes of
         * each segment.
@@ -1158,7 +1156,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
                BUG_ON(blk_rq_bytes(req));
 
                memset(&cmd->sdb, 0, sizeof(cmd->sdb));
-               req->buffer = NULL;
        }
 
        cmd->cmd_len = req->cmd_len;
index fe30ea94ffe67ef4e5d355fdc9cdcb71eee9e0d7..109802f776ed71cea6857eda9ae6ccc3e0b41f80 100644 (file)
@@ -77,7 +77,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
                        goto next_msg;
                }
 
-               if (!capable(CAP_SYS_ADMIN)) {
+               if (!netlink_capable(skb, CAP_SYS_ADMIN)) {
                        err = -EPERM;
                        goto next_msg;
                }
index efcbcd182863318f296936bc7fa16c96bc58efe5..96af195224f2b9dae866ea109afb1d894c142c80 100644 (file)
@@ -737,16 +737,14 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
                goto out;
        }
 
+       rq->completion_data = page;
        blk_add_request_payload(rq, page, len);
        ret = scsi_setup_blk_pc_cmnd(sdp, rq);
-       rq->buffer = page_address(page);
        rq->__data_len = nr_bytes;
 
 out:
-       if (ret != BLKPREP_OK) {
+       if (ret != BLKPREP_OK)
                __free_page(page);
-               rq->buffer = NULL;
-       }
        return ret;
 }
 
@@ -842,10 +840,9 @@ static void sd_unprep_fn(struct request_queue *q, struct request *rq)
 {
        struct scsi_cmnd *SCpnt = rq->special;
 
-       if (rq->cmd_flags & REQ_DISCARD) {
-               free_page((unsigned long)rq->buffer);
-               rq->buffer = NULL;
-       }
+       if (rq->cmd_flags & REQ_DISCARD)
+               __free_page(rq->completion_data);
+
        if (SCpnt->cmnd != rq->cmd) {
                mempool_free(SCpnt->cmnd, sd_cdb_pool);
                SCpnt->cmnd = NULL;
index 16bfd50cd3fe65644c5443698d3aa3e96dfd5925..db3b494e5926a423866e0ad3a18b15b6378d3cca 100644 (file)
@@ -750,8 +750,12 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
 
                vscsi->affinity_hint_set = true;
        } else {
-               for (i = 0; i < vscsi->num_queues; i++)
+               for (i = 0; i < vscsi->num_queues; i++) {
+                       if (!vscsi->req_vqs[i].vq)
+                               continue;
+
                        virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
+               }
 
                vscsi->affinity_hint_set = false;
        }
index 74727851820df42e5b6471a0799357ad66e850e1..be56b22ca941a0ccb005429a0bc920e953a63b24 100644 (file)
@@ -196,17 +196,11 @@ int clk_rate_table_find(struct clk *clk,
                        struct cpufreq_frequency_table *freq_table,
                        unsigned long rate)
 {
-       int i;
-
-       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               unsigned long freq = freq_table[i].frequency;
+       struct cpufreq_frequency_table *pos;
 
-               if (freq == CPUFREQ_ENTRY_INVALID)
-                       continue;
-
-               if (freq == rate)
-                       return i;
-       }
+       cpufreq_for_each_valid_entry(pos, freq_table)
+               if (pos->frequency == rate)
+                       return pos - freq_table;
 
        return -ENOENT;
 }
@@ -575,11 +569,7 @@ long clk_round_parent(struct clk *clk, unsigned long target,
                return abs(target - *best_freq);
        }
 
-       for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
-            freq++) {
-               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
-
+       cpufreq_for_each_valid_entry(freq, parent->freq_table) {
                if (unlikely(freq->frequency / target <= div_min - 1)) {
                        unsigned long freq_max;
 
index e2b482045158dedb9101f6939b1c4d5dbe071f7d..017d2f8379b78ca86f7e30ed0e85855684c7b6ec 100644 (file)
@@ -107,7 +107,7 @@ static int ad2s1200_probe(struct spi_device *spi)
        int pn, ret = 0;
        unsigned short *pins = spi->dev.platform_data;
 
-       for (pn = 0; pn < AD2S1200_PN; pn++)
+       for (pn = 0; pn < AD2S1200_PN; pn++) {
                ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT,
                                            DRV_NAME);
                if (ret) {
@@ -115,6 +115,7 @@ static int ad2s1200_probe(struct spi_device *spi)
                                                        pins[pn]);
                        return ret;
                }
+       }
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
        if (!indio_dev)
                return -ENOMEM;
index 827209ea6bd0e9685344b845f44b7560fdf5e1fe..386a36c00f572f871bd668f1fa5873a098714e73 100644 (file)
@@ -82,16 +82,7 @@ struct ccc_io {
        /**
         * I/O vector information to or from which read/write is going.
         */
-       struct iovec *cui_iov;
-       unsigned long cui_nrsegs;
-       /**
-        * Total iov count for left IO.
-        */
-       unsigned long cui_tot_nrsegs;
-       /**
-        * Old length for iov that was truncated partially.
-        */
-       size_t cui_iov_olen;
+       struct iov_iter *cui_iter;
        /**
         * Total size for the left IO.
         */
index 6907a16dbbd1dc39ca9e10445978eb8560348088..a07d5156bc50c017f8d942b090c7ce901735bb94 100644 (file)
@@ -721,31 +721,12 @@ int ccc_io_one_lock_index(const struct lu_env *env, struct cl_io *io,
 void ccc_io_update_iov(const struct lu_env *env,
                       struct ccc_io *cio, struct cl_io *io)
 {
-       int i;
        size_t size = io->u.ci_rw.crw_count;
 
-       cio->cui_iov_olen = 0;
-       if (!cl_is_normalio(env, io) || cio->cui_tot_nrsegs == 0)
+       if (!cl_is_normalio(env, io) || cio->cui_iter == NULL)
                return;
 
-       for (i = 0; i < cio->cui_tot_nrsegs; i++) {
-               struct iovec *iv = &cio->cui_iov[i];
-
-               if (iv->iov_len < size)
-                       size -= iv->iov_len;
-               else {
-                       if (iv->iov_len > size) {
-                               cio->cui_iov_olen = iv->iov_len;
-                               iv->iov_len = size;
-                       }
-                       break;
-               }
-       }
-
-       cio->cui_nrsegs = i + 1;
-       LASSERTF(cio->cui_tot_nrsegs >= cio->cui_nrsegs,
-                "tot_nrsegs: %lu, nrsegs: %lu\n",
-                cio->cui_tot_nrsegs, cio->cui_nrsegs);
+       iov_iter_truncate(cio->cui_iter, size);
 }
 
 int ccc_io_one_lock(const struct lu_env *env, struct cl_io *io,
@@ -776,30 +757,7 @@ void ccc_io_advance(const struct lu_env *env,
        if (!cl_is_normalio(env, io))
                return;
 
-       LASSERT(cio->cui_tot_nrsegs >= cio->cui_nrsegs);
-       LASSERT(cio->cui_tot_count  >= nob);
-
-       cio->cui_iov    += cio->cui_nrsegs;
-       cio->cui_tot_nrsegs -= cio->cui_nrsegs;
-       cio->cui_tot_count  -= nob;
-
-       /* update the iov */
-       if (cio->cui_iov_olen > 0) {
-               struct iovec *iv;
-
-               cio->cui_iov--;
-               cio->cui_tot_nrsegs++;
-               iv = &cio->cui_iov[0];
-               if (io->ci_continue) {
-                       iv->iov_base += iv->iov_len;
-                       LASSERT(cio->cui_iov_olen > iv->iov_len);
-                       iv->iov_len = cio->cui_iov_olen - iv->iov_len;
-               } else {
-                       /* restore the iov_len, in case of restart io. */
-                       iv->iov_len = cio->cui_iov_olen;
-               }
-               cio->cui_iov_olen = 0;
-       }
+       iov_iter_reexpand(cio->cui_iter, cio->cui_tot_count  -= nob);
 }
 
 /**
index 8e844a6371e0600c76ae814e080df1cfd1d3099d..3cb3a889cace9b747e339fb7836d3e44bf280415 100644 (file)
@@ -1105,9 +1105,7 @@ restart:
 
                switch (vio->cui_io_subtype) {
                case IO_NORMAL:
-                       cio->cui_iov = args->u.normal.via_iov;
-                       cio->cui_nrsegs = args->u.normal.via_nrsegs;
-                       cio->cui_tot_nrsegs = cio->cui_nrsegs;
+                       cio->cui_iter = args->u.normal.via_iter;
                        cio->cui_iocb = args->u.normal.via_iocb;
                        if ((iot == CIT_WRITE) &&
                            !(cio->cui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
@@ -1171,58 +1169,23 @@ out:
        return result;
 }
 
-static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos)
+static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct lu_env      *env;
        struct vvp_io_args *args;
-       size_t        count = 0;
        ssize_t      result;
        int              refcheck;
 
-       result = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
-       if (result)
-               return result;
-
        env = cl_env_get(&refcheck);
        if (IS_ERR(env))
                return PTR_ERR(env);
 
        args = vvp_env_args(env, IO_NORMAL);
-       args->u.normal.via_iov = (struct iovec *)iov;
-       args->u.normal.via_nrsegs = nr_segs;
+       args->u.normal.via_iter = to;
        args->u.normal.via_iocb = iocb;
 
        result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
-                                   &iocb->ki_pos, count);
-       cl_env_put(env, &refcheck);
-       return result;
-}
-
-static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
-                           loff_t *ppos)
-{
-       struct lu_env *env;
-       struct iovec  *local_iov;
-       struct kiocb  *kiocb;
-       ssize_t result;
-       int         refcheck;
-
-       env = cl_env_get(&refcheck);
-       if (IS_ERR(env))
-               return PTR_ERR(env);
-
-       local_iov = &vvp_env_info(env)->vti_local_iov;
-       kiocb = &vvp_env_info(env)->vti_kiocb;
-       local_iov->iov_base = (void __user *)buf;
-       local_iov->iov_len = count;
-       init_sync_kiocb(kiocb, file);
-       kiocb->ki_pos = *ppos;
-       kiocb->ki_nbytes = count;
-
-       result = ll_file_aio_read(kiocb, local_iov, 1, kiocb->ki_pos);
-       *ppos = kiocb->ki_pos;
-
+                                   &iocb->ki_pos, iov_iter_count(to));
        cl_env_put(env, &refcheck);
        return result;
 }
@@ -1230,64 +1193,27 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
 /*
  * Write to a file (through the page cache).
  */
-static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                                unsigned long nr_segs, loff_t pos)
+static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct lu_env      *env;
        struct vvp_io_args *args;
-       size_t        count = 0;
        ssize_t      result;
        int              refcheck;
 
-       result = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
-       if (result)
-               return result;
-
        env = cl_env_get(&refcheck);
        if (IS_ERR(env))
                return PTR_ERR(env);
 
        args = vvp_env_args(env, IO_NORMAL);
-       args->u.normal.via_iov = (struct iovec *)iov;
-       args->u.normal.via_nrsegs = nr_segs;
+       args->u.normal.via_iter = from;
        args->u.normal.via_iocb = iocb;
 
        result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
-                                 &iocb->ki_pos, count);
+                                 &iocb->ki_pos, iov_iter_count(from));
        cl_env_put(env, &refcheck);
        return result;
 }
 
-static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
-                            loff_t *ppos)
-{
-       struct lu_env *env;
-       struct iovec  *local_iov;
-       struct kiocb  *kiocb;
-       ssize_t result;
-       int         refcheck;
-
-       env = cl_env_get(&refcheck);
-       if (IS_ERR(env))
-               return PTR_ERR(env);
-
-       local_iov = &vvp_env_info(env)->vti_local_iov;
-       kiocb = &vvp_env_info(env)->vti_kiocb;
-       local_iov->iov_base = (void __user *)buf;
-       local_iov->iov_len = count;
-       init_sync_kiocb(kiocb, file);
-       kiocb->ki_pos = *ppos;
-       kiocb->ki_nbytes = count;
-
-       result = ll_file_aio_write(kiocb, local_iov, 1, kiocb->ki_pos);
-       *ppos = kiocb->ki_pos;
-
-       cl_env_put(env, &refcheck);
-       return result;
-}
-
-
-
 /*
  * Send file content (through pagecache) somewhere with helper
  */
@@ -2691,20 +2617,15 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
 
        ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK, 1);
 
-       if (file_lock->fl_flags & FL_FLOCK) {
+       if (file_lock->fl_flags & FL_FLOCK)
                LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK));
-               /* flocks are whole-file locks */
-               flock.l_flock.end = OFFSET_MAX;
-               /* For flocks owner is determined by the local file descriptor*/
-               flock.l_flock.owner = (unsigned long)file_lock->fl_file;
-       } else if (file_lock->fl_flags & FL_POSIX) {
-               flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
-               flock.l_flock.start = file_lock->fl_start;
-               flock.l_flock.end = file_lock->fl_end;
-       } else {
+       else if (!(file_lock->fl_flags & FL_POSIX))
                return -EINVAL;
-       }
+
+       flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
        flock.l_flock.pid = file_lock->fl_pid;
+       flock.l_flock.start = file_lock->fl_start;
+       flock.l_flock.end = file_lock->fl_end;
 
        /* Somewhat ugly workaround for svc lockd.
         * lockd installs custom fl_lmops->lm_compare_owner that checks
@@ -3139,10 +3060,10 @@ int ll_inode_permission(struct inode *inode, int mask)
 
 /* -o localflock - only provides locally consistent flock locks */
 struct file_operations ll_file_operations = {
-       .read      = ll_file_read,
-       .aio_read = ll_file_aio_read,
-       .write    = ll_file_write,
-       .aio_write = ll_file_aio_write,
+       .read      = new_sync_read,
+       .read_iter = ll_file_read_iter,
+       .write    = new_sync_write,
+       .write_iter = ll_file_write_iter,
        .unlocked_ioctl = ll_file_ioctl,
        .open      = ll_file_open,
        .release        = ll_file_release,
@@ -3154,10 +3075,10 @@ struct file_operations ll_file_operations = {
 };
 
 struct file_operations ll_file_operations_flock = {
-       .read      = ll_file_read,
-       .aio_read    = ll_file_aio_read,
-       .write    = ll_file_write,
-       .aio_write   = ll_file_aio_write,
+       .read      = new_sync_read,
+       .read_iter    = ll_file_read_iter,
+       .write    = new_sync_write,
+       .write_iter   = ll_file_write_iter,
        .unlocked_ioctl = ll_file_ioctl,
        .open      = ll_file_open,
        .release        = ll_file_release,
@@ -3172,10 +3093,10 @@ struct file_operations ll_file_operations_flock = {
 
 /* These are for -o noflock - to return ENOSYS on flock calls */
 struct file_operations ll_file_operations_noflock = {
-       .read      = ll_file_read,
-       .aio_read    = ll_file_aio_read,
-       .write    = ll_file_write,
-       .aio_write   = ll_file_aio_write,
+       .read      = new_sync_read,
+       .read_iter    = ll_file_read_iter,
+       .write    = new_sync_write,
+       .write_iter   = ll_file_write_iter,
        .unlocked_ioctl = ll_file_ioctl,
        .open      = ll_file_open,
        .release        = ll_file_release,
index 69aba0afca41b2eafd481991c269770d4697c42a..fbb8650ead346885c4f0dd14b5e3bdc7ead493b7 100644 (file)
@@ -974,8 +974,7 @@ struct vvp_io_args {
        union {
                struct {
                        struct kiocb      *via_iocb;
-                       struct iovec      *via_iov;
-                       unsigned long      via_nrsegs;
+                       struct iov_iter   *via_iter;
                } normal;
                struct {
                        struct pipe_inode_info  *via_pipe;
index 416f7a094a6d2fc81f9cc5f2ab5291bc6e733daf..b345dfa599f3d864145f34e2d57426cf4fd75bdd 100644 (file)
@@ -157,8 +157,7 @@ static struct ll_cl_context *ll_cl_init(struct file *file,
                result = cl_io_rw_init(env, io, CIT_WRITE, pos, PAGE_CACHE_SIZE);
                if (result == 0) {
                        cio->cui_fd = LUSTRE_FPRIVATE(file);
-                       cio->cui_iov = NULL;
-                       cio->cui_nrsegs = 0;
+                       cio->cui_iter = NULL;
                        result = cl_io_iter_init(env, io);
                        if (result == 0) {
                                result = cl_io_lock(env, io);
index 7e3e0967993b5f6fecc7bfa965ef9a444cd0037f..6b5994577b6b9f61bbb704341c72f0fa088183b7 100644 (file)
@@ -218,14 +218,11 @@ static void ll_free_user_pages(struct page **pages, int npages, int do_dirty)
        int i;
 
        for (i = 0; i < npages; i++) {
-               if (pages[i] == NULL)
-                       break;
                if (do_dirty)
                        set_page_dirty_lock(pages[i]);
                page_cache_release(pages[i]);
        }
-
-       OBD_FREE_LARGE(pages, npages * sizeof(*pages));
+       kvfree(pages);
 }
 
 ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io,
@@ -363,18 +360,16 @@ static ssize_t ll_direct_IO_26_seg(const struct lu_env *env, struct cl_io *io,
 #define MAX_DIO_SIZE ((MAX_MALLOC / sizeof(struct brw_page) * PAGE_CACHE_SIZE) & \
                      ~(DT_MAX_BRW_SIZE - 1))
 static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb,
-                              const struct iovec *iov, loff_t file_offset,
-                              unsigned long nr_segs)
+                              struct iov_iter *iter, loff_t file_offset)
 {
        struct lu_env *env;
        struct cl_io *io;
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        struct ccc_object *obj = cl_inode2ccc(inode);
-       long count = iov_length(iov, nr_segs);
-       long tot_bytes = 0, result = 0;
+       ssize_t count = iov_iter_count(iter);
+       ssize_t tot_bytes = 0, result = 0;
        struct ll_inode_info *lli = ll_i2info(inode);
-       unsigned long seg = 0;
        long size = MAX_DIO_SIZE;
        int refcheck;
 
@@ -392,11 +387,8 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb,
               MAX_DIO_SIZE >> PAGE_CACHE_SHIFT);
 
        /* Check that all user buffers are aligned as well */
-       for (seg = 0; seg < nr_segs; seg++) {
-               if (((unsigned long)iov[seg].iov_base & ~CFS_PAGE_MASK) ||
-                   (iov[seg].iov_len & ~CFS_PAGE_MASK))
-                       return -EINVAL;
-       }
+       if (iov_iter_alignment(iter) & ~CFS_PAGE_MASK)
+               return -EINVAL;
 
        env = cl_env_get(&refcheck);
        LASSERT(!IS_ERR(env));
@@ -411,63 +403,49 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb,
                mutex_lock(&inode->i_mutex);
 
        LASSERT(obj->cob_transient_pages == 0);
-       for (seg = 0; seg < nr_segs; seg++) {
-               long iov_left = iov[seg].iov_len;
-               unsigned long user_addr = (unsigned long)iov[seg].iov_base;
+       while (iov_iter_count(iter)) {
+               struct page **pages;
+               size_t offs;
 
+               count = min_t(size_t, iov_iter_count(iter), size);
                if (rw == READ) {
                        if (file_offset >= i_size_read(inode))
                                break;
-                       if (file_offset + iov_left > i_size_read(inode))
-                               iov_left = i_size_read(inode) - file_offset;
+                       if (file_offset + count > i_size_read(inode))
+                               count = i_size_read(inode) - file_offset;
                }
 
-               while (iov_left > 0) {
-                       struct page **pages;
-                       int page_count, max_pages = 0;
-                       long bytes;
-
-                       bytes = min(size, iov_left);
-                       page_count = ll_get_user_pages(rw, user_addr, bytes,
-                                                      &pages, &max_pages);
-                       if (likely(page_count > 0)) {
-                               if (unlikely(page_count <  max_pages))
-                                       bytes = page_count << PAGE_CACHE_SHIFT;
-                               result = ll_direct_IO_26_seg(env, io, rw, inode,
-                                                            file->f_mapping,
-                                                            bytes, file_offset,
-                                                            pages, page_count);
-                               ll_free_user_pages(pages, max_pages, rw==READ);
-                       } else if (page_count == 0) {
-                               GOTO(out, result = -EFAULT);
-                       } else {
-                               result = page_count;
-                       }
-                       if (unlikely(result <= 0)) {
-                               /* If we can't allocate a large enough buffer
-                                * for the request, shrink it to a smaller
-                                * PAGE_SIZE multiple and try again.
-                                * We should always be able to kmalloc for a
-                                * page worth of page pointers = 4MB on i386. */
-                               if (result == -ENOMEM &&
-                                   size > (PAGE_CACHE_SIZE / sizeof(*pages)) *
-                                          PAGE_CACHE_SIZE) {
-                                       size = ((((size / 2) - 1) |
-                                                ~CFS_PAGE_MASK) + 1) &
-                                               CFS_PAGE_MASK;
-                                       CDEBUG(D_VFSTRACE,"DIO size now %lu\n",
-                                              size);
-                                       continue;
-                               }
-
-                               GOTO(out, result);
+               result = iov_iter_get_pages_alloc(iter, &pages, count, &offs);
+               if (likely(result > 0)) {
+                       int n = (result + offs + PAGE_SIZE - 1) / PAGE_SIZE;
+                       result = ll_direct_IO_26_seg(env, io, rw, inode,
+                                                    file->f_mapping,
+                                                    result, file_offset,
+                                                    pages, n);
+                       ll_free_user_pages(pages, n, rw==READ);
+               }
+               if (unlikely(result <= 0)) {
+                       /* If we can't allocate a large enough buffer
+                        * for the request, shrink it to a smaller
+                        * PAGE_SIZE multiple and try again.
+                        * We should always be able to kmalloc for a
+                        * page worth of page pointers = 4MB on i386. */
+                       if (result == -ENOMEM &&
+                           size > (PAGE_CACHE_SIZE / sizeof(*pages)) *
+                                  PAGE_CACHE_SIZE) {
+                               size = ((((size / 2) - 1) |
+                                        ~CFS_PAGE_MASK) + 1) &
+                                       CFS_PAGE_MASK;
+                               CDEBUG(D_VFSTRACE,"DIO size now %lu\n",
+                                      size);
+                               continue;
                        }
 
-                       tot_bytes += result;
-                       file_offset += result;
-                       iov_left -= result;
-                       user_addr += result;
+                       GOTO(out, result);
                }
+               iov_iter_advance(iter, result);
+               tot_bytes += result;
+               file_offset += result;
        }
 out:
        LASSERT(obj->cob_transient_pages == 0);
index c7d70091246ea2a09c8377eadd00bcb92bd734f7..cfe8c625ae6403c72a6fa7513e7cce79fe8c8570 100644 (file)
@@ -211,27 +211,26 @@ static int vvp_mmap_locks(const struct lu_env *env,
        struct cl_lock_descr   *descr = &cti->cti_descr;
        ldlm_policy_data_t      policy;
        unsigned long      addr;
-       unsigned long      seg;
        ssize_t          count;
        int                  result;
+       struct iov_iter i;
+       struct iovec iov;
 
        LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
 
        if (!cl_is_normalio(env, io))
                return 0;
 
-       if (vio->cui_iov == NULL) /* nfs or loop back device write */
+       if (vio->cui_iter == NULL) /* nfs or loop back device write */
                return 0;
 
        /* No MM (e.g. NFS)? No vmas too. */
        if (mm == NULL)
                return 0;
 
-       for (seg = 0; seg < vio->cui_nrsegs; seg++) {
-               const struct iovec *iv = &vio->cui_iov[seg];
-
-               addr = (unsigned long)iv->iov_base;
-               count = iv->iov_len;
+       iov_for_each(iov, i, *(vio->cui_iter)) {
+               addr = (unsigned long)iov.iov_base;
+               count = iov.iov_len;
                if (count == 0)
                        continue;
 
@@ -527,9 +526,7 @@ static int vvp_io_read_start(const struct lu_env *env,
        switch (vio->cui_io_subtype) {
        case IO_NORMAL:
                LASSERT(cio->cui_iocb->ki_pos == pos);
-               result = generic_file_aio_read(cio->cui_iocb,
-                                              cio->cui_iov, cio->cui_nrsegs,
-                                              cio->cui_iocb->ki_pos);
+               result = generic_file_read_iter(cio->cui_iocb, cio->cui_iter);
                break;
        case IO_SPLICE:
                result = generic_file_splice_read(file, &pos,
@@ -595,12 +592,11 @@ static int vvp_io_write_start(const struct lu_env *env,
 
        CDEBUG(D_VFSTRACE, "write: [%lli, %lli)\n", pos, pos + (long long)cnt);
 
-       if (cio->cui_iov == NULL) /* from a temp io in ll_cl_init(). */
+       if (cio->cui_iter == NULL) /* from a temp io in ll_cl_init(). */
                result = 0;
        else
-               result = generic_file_aio_write(cio->cui_iocb,
-                                               cio->cui_iov, cio->cui_nrsegs,
-                                               cio->cui_iocb->ki_pos);
+               result = generic_file_write_iter(cio->cui_iocb, cio->cui_iter);
+
        if (result > 0) {
                if (result < cnt)
                        io->ci_continue = 0;
@@ -1162,10 +1158,9 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj,
                 *  results."  -- Single Unix Spec */
                if (count == 0)
                        result = 1;
-               else {
+               else
                        cio->cui_tot_count = count;
-                       cio->cui_tot_nrsegs = 0;
-               }
+
                /* for read/write, we store the jobid in the inode, and
                 * it'll be fetched by osc when building RPC.
                 *
index 8c101cbbee97646d2b06166865381bf9144df2cb..acc8184c46cde0d85ebeccd41c000b67ae9da429 100644 (file)
@@ -1247,9 +1247,18 @@ static int vpfe_stop_streaming(struct vb2_queue *vq)
        struct vpfe_fh *fh = vb2_get_drv_priv(vq);
        struct vpfe_video_device *video = fh->video;
 
-       if (!vb2_is_streaming(vq))
-               return 0;
        /* release all active buffers */
+       if (video->cur_frm == video->next_frm) {
+               vb2_buffer_done(&video->cur_frm->vb, VB2_BUF_STATE_ERROR);
+       } else {
+               if (video->cur_frm != NULL)
+                       vb2_buffer_done(&video->cur_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+               if (video->next_frm != NULL)
+                       vb2_buffer_done(&video->next_frm->vb,
+                                       VB2_BUF_STATE_ERROR);
+       }
+
        while (!list_empty(&video->dma_queue)) {
                video->next_frm = list_entry(video->dma_queue.next,
                                                struct vpfe_cap_buffer, list);
index b3d2cc729657df34e57bc300033bafc1baf2bdd6..4ba569258498b9d6248de4d58d13c63750c68561 100644 (file)
@@ -48,10 +48,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
        { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
-#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
index ff3139b6da656f2f985b2c1498fa16508c2030b2..63ae2d1997d3c19fb1bd38c97ac4d39bd1c7cf52 100644 (file)
@@ -1414,23 +1414,15 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
  * before switch channel or power save, or tx buffer packet
  * maybe send after offchannel or rf sleep, this may cause
  * dis-association by AP */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
-static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+static void rtl_op_flush(struct ieee80211_hw *hw,
+                        struct ieee80211_vif *vif,
+                        u32 queues, bool drop)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
        if (rtlpriv->intf_ops->flush)
                rtlpriv->intf_ops->flush(hw, queues, drop);
 }
-#else
-static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       if (rtlpriv->intf_ops->flush)
-               rtlpriv->intf_ops->flush(hw, drop);
-}
-#endif
 
 const struct ieee80211_ops rtl_ops = {
        .start = rtl_op_start,
index 4246262c4bd249f5ee0d3cec5f3712d1fdd9bbc6..84a75f89bf74d07786989cd643b1cf327224c2ff 100644 (file)
@@ -144,11 +144,11 @@ static int get_property(unsigned int cpu, unsigned long input,
                        unsigned int *output,
                        enum cpufreq_cooling_property property)
 {
-       int i, j;
+       int i;
        unsigned long max_level = 0, level = 0;
        unsigned int freq = CPUFREQ_ENTRY_INVALID;
        int descend = -1;
-       struct cpufreq_frequency_table *table =
+       struct cpufreq_frequency_table *pos, *table =
                                        cpufreq_frequency_get_table(cpu);
 
        if (!output)
@@ -157,20 +157,16 @@ static int get_property(unsigned int cpu, unsigned long input,
        if (!table)
                return -EINVAL;
 
-       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               /* ignore invalid entries */
-               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
-
+       cpufreq_for_each_valid_entry(pos, table) {
                /* ignore duplicate entry */
-               if (freq == table[i].frequency)
+               if (freq == pos->frequency)
                        continue;
 
                /* get the frequency order */
                if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
-                       descend = !!(freq > table[i].frequency);
+                       descend = freq > pos->frequency;
 
-               freq = table[i].frequency;
+               freq = pos->frequency;
                max_level++;
        }
 
@@ -190,29 +186,26 @@ static int get_property(unsigned int cpu, unsigned long input,
        if (property == GET_FREQ)
                level = descend ? input : (max_level - input);
 
-       for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               /* ignore invalid entry */
-               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
-
+       i = 0;
+       cpufreq_for_each_valid_entry(pos, table) {
                /* ignore duplicate entry */
-               if (freq == table[i].frequency)
+               if (freq == pos->frequency)
                        continue;
 
                /* now we have a valid frequency entry */
-               freq = table[i].frequency;
+               freq = pos->frequency;
 
                if (property == GET_LEVEL && (unsigned int)input == freq) {
                        /* get level by frequency */
-                       *output = descend ? j : (max_level - j);
+                       *output = descend ? i : (max_level - i);
                        return 0;
                }
-               if (property == GET_FREQ && level == j) {
+               if (property == GET_FREQ && level == i) {
                        /* get frequency by level */
                        *output = freq;
                        return 0;
                }
-               j++;
+               i++;
        }
 
        return -EINVAL;
index 94f9e3a38412f3071d63b4964925b375abec4283..0ff7fda0742f4326113cf82f8a72cb355c840319 100644 (file)
@@ -190,7 +190,7 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index)
        return hvc_driver;
 }
 
-static int __init hvc_console_setup(struct console *co, char *options)
+static int hvc_console_setup(struct console *co, char *options)
 {      
        if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
                return -ENODEV;
index 41fe8a047d373cf84b14a9a2f5d8f41e07fd3b5f..fe9d129c87351b47392320a626dedb89e2f0bf55 100644 (file)
@@ -2353,8 +2353,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                        if (tty->ops->flush_chars)
                                tty->ops->flush_chars(tty);
                } else {
+                       struct n_tty_data *ldata = tty->disc_data;
+
                        while (nr > 0) {
+                               mutex_lock(&ldata->output_lock);
                                c = tty->ops->write(tty, b, nr);
+                               mutex_unlock(&ldata->output_lock);
                                if (c < 0) {
                                        retval = c;
                                        goto break_out;
index 0e1bf88584311352767e646faedc2b39183932ce..2d4bd3929e507376f7d4b25f788fbba3b61af1a4 100644 (file)
@@ -555,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
         */
        if ((p->port.type == PORT_XR17V35X) ||
           (p->port.type == PORT_XR17D15X)) {
-               serial_out(p, UART_EXAR_SLEEP, 0xff);
+               serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
                return;
        }
 
index f1d30f6945af2cf8fece1a5a1b40d59aa46cd5e0..cf78d1985cd851fb2b6615054bfabf5a8e3b2b13 100644 (file)
@@ -255,16 +255,15 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
        if (change || left < size) {
                /* This is the slow path - looking for new buffers to use */
                if ((n = tty_buffer_alloc(port, size)) != NULL) {
-                       unsigned long iflags;
-
                        n->flags = flags;
                        buf->tail = n;
-
-                       spin_lock_irqsave(&buf->flush_lock, iflags);
                        b->commit = b->used;
+                       /* paired w/ barrier in flush_to_ldisc(); ensures the
+                        * latest commit value can be read before the head is
+                        * advanced to the next buffer
+                        */
+                       smp_wmb();
                        b->next = n;
-                       spin_unlock_irqrestore(&buf->flush_lock, iflags);
-
                } else if (change)
                        size = 0;
                else
@@ -448,27 +447,28 @@ static void flush_to_ldisc(struct work_struct *work)
        mutex_lock(&buf->lock);
 
        while (1) {
-               unsigned long flags;
                struct tty_buffer *head = buf->head;
+               struct tty_buffer *next;
                int count;
 
                /* Ldisc or user is trying to gain exclusive access */
                if (atomic_read(&buf->priority))
                        break;
 
-               spin_lock_irqsave(&buf->flush_lock, flags);
+               next = head->next;
+               /* paired w/ barrier in __tty_buffer_request_room();
+                * ensures commit value read is not stale if the head
+                * is advancing to the next buffer
+                */
+               smp_rmb();
                count = head->commit - head->read;
                if (!count) {
-                       if (head->next == NULL) {
-                               spin_unlock_irqrestore(&buf->flush_lock, flags);
+                       if (next == NULL)
                                break;
-                       }
-                       buf->head = head->next;
-                       spin_unlock_irqrestore(&buf->flush_lock, flags);
+                       buf->head = next;
                        tty_buffer_free(port, head);
                        continue;
                }
-               spin_unlock_irqrestore(&buf->flush_lock, flags);
 
                count = receive_buf(tty, head, count);
                if (!count)
@@ -523,7 +523,6 @@ void tty_buffer_init(struct tty_port *port)
        struct tty_bufhead *buf = &port->buf;
 
        mutex_init(&buf->lock);
-       spin_lock_init(&buf->flush_lock);
        tty_buffer_reset(&buf->sentinel, 0);
        buf->head = &buf->sentinel;
        buf->tail = &buf->sentinel;
index f605ad8c1902fc775cffc39dcd53be8d65fe3a8f..cfd18bcca723ef700d727fa1f8f8a39405eba13f 100644 (file)
@@ -1709,16 +1709,6 @@ static int at91udc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       if (pdev->num_resources != 2) {
-               DBG("invalid num_resources\n");
-               return -ENODEV;
-       }
-       if ((pdev->resource[0].flags != IORESOURCE_MEM)
-                       || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
-               DBG("invalid resource type\n");
-               return -ENODEV;
-       }
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                return -ENXIO;
index ec20a1f50c2d702e56f6e6a79f03485607a36189..a8898df131ed5b4abdf37adb8784645e88840381 100644 (file)
@@ -220,11 +220,11 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
         * If we can't read the file, it's no good.
         * If we can't write the file, use it read-only.
         */
-       if (!(filp->f_op->read || filp->f_op->aio_read)) {
+       if (!(filp->f_mode & FMODE_CAN_READ)) {
                LINFO(curlun, "file not readable: %s\n", filename);
                goto out;
        }
-       if (!(filp->f_op->write || filp->f_op->aio_write))
+       if (!(filp->f_mode & FMODE_CAN_WRITE))
                ro = 1;
 
        size = i_size_read(inode->i_mapping->host);
index 6f2c8d3899d2cfb00f14fe641341f68944943213..cf2734b532a7ab288d24dd13fd79db364490a748 100644 (file)
@@ -248,7 +248,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                break;
        }
 
-       if (pdata->have_sysif_regs && pdata->controller_ver &&
+       if (pdata->have_sysif_regs &&
+           pdata->controller_ver > FSL_USB_VER_1_6 &&
            (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) &
index c81c8721cc5a9e3d07e20c29d9d40e540136409e..cd871b89501325407af3ab3ebf0eb56ab0814a79 100644 (file)
@@ -90,6 +90,24 @@ __acquires(ohci->lock)
        dl_done_list (ohci);
        finish_unlinks (ohci, ohci_frame_no(ohci));
 
+       /*
+        * Some controllers don't handle "global" suspend properly if
+        * there are unsuspended ports.  For these controllers, put all
+        * the enabled ports into suspend before suspending the root hub.
+        */
+       if (ohci->flags & OHCI_QUIRK_GLOBAL_SUSPEND) {
+               __hc32 __iomem  *portstat = ohci->regs->roothub.portstatus;
+               int             i;
+               unsigned        temp;
+
+               for (i = 0; i < ohci->num_ports; (++i, ++portstat)) {
+                       temp = ohci_readl(ohci, portstat);
+                       if ((temp & (RH_PS_PES | RH_PS_PSS)) ==
+                                       RH_PS_PES)
+                               ohci_writel(ohci, RH_PS_PSS, portstat);
+               }
+       }
+
        /* maybe resume can wake root hub */
        if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {
                ohci->hc_control |= OHCI_CTRL_RWE;
index 90879e9ccbec302e8c5272d45e4847009b3730c4..bb1509675727b374586d61917920578cc7631a45 100644 (file)
@@ -160,6 +160,7 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
                ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
        }
 
+       ohci->flags |= OHCI_QUIRK_GLOBAL_SUSPEND;
        return 0;
 }
 
index 9250cada13f0b3e9a22711de3345b67de1627e01..4550ce05af7fa1d1b96c03dc2590c5c0cc943615 100644 (file)
@@ -405,6 +405,8 @@ struct ohci_hcd {
 #define        OHCI_QUIRK_HUB_POWER    0x100                   /* distrust firmware power/oc setup */
 #define        OHCI_QUIRK_AMD_PLL      0x200                   /* AMD PLL quirk*/
 #define        OHCI_QUIRK_AMD_PREFETCH 0x400                   /* pre-fetch for ISO transfer */
+#define        OHCI_QUIRK_GLOBAL_SUSPEND       0x800           /* must suspend ports */
+
        // there are also chip quirks/bugs in init logic
 
        struct work_struct      nec_work;       /* Worker for NEC quirk */
index c47e5a6edde28a1d35d64d6f375df401a8519709..d03fadd2629f1419b00a60ef9d842913c5ae6183 100644 (file)
@@ -303,17 +303,18 @@ int otg_statemachine(struct otg_fsm *fsm)
                        otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
                break;
        case OTG_STATE_A_WAIT_VRISE:
-               if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld ||
-                               fsm->a_wait_vrise_tmout) {
+               if (fsm->a_vbus_vld)
                        otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
-               }
+               else if (fsm->id || fsm->a_bus_drop ||
+                               fsm->a_wait_vrise_tmout)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
                break;
        case OTG_STATE_A_WAIT_BCON:
                if (!fsm->a_vbus_vld)
                        otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
                else if (fsm->b_conn)
                        otg_set_state(fsm, OTG_STATE_A_HOST);
-               else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout)
+               else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout)
                        otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
                break;
        case OTG_STATE_A_HOST:
index 7ed681a714a58864921bbd96edbfb1f02b92446c..6c0a542e8ec1820d60d03f5a7896843d4a6b96f6 100644 (file)
@@ -151,6 +151,21 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 0)},       /* Netgear AirCard 340U Device Management */
        {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 2)},       /* Netgear AirCard 340U NMEA */
        {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 3)},       /* Netgear AirCard 340U Modem */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a2, 0)},       /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card Device Management */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a2, 2)},       /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card NMEA */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a2, 3)},       /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card Modem */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a3, 0)},       /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card Device Management */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a3, 2)},       /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card NMEA */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a3, 3)},       /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card Modem */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a4, 0)},       /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card Device Management */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a4, 2)},       /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card NMEA */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a4, 3)},       /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card Modem */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a8, 0)},       /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card Device Management */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a8, 2)},       /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card NMEA */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a8, 3)},       /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card Modem */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a9, 0)},       /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card Device Management */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a9, 2)},       /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card NMEA */
+       {USB_DEVICE_INTERFACE_NUMBER(0x413c, 0x81a9, 3)},       /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card Modem */
 
        { }                             /* Terminating entry */
 };
index 4ef2a80728f74521d103dc8d33b1fed8735b1947..008d805c3d21cde7458058a6a2a5b0803da92bcf 100644 (file)
@@ -1851,7 +1851,7 @@ static int usbat_probe(struct usb_interface *intf,
        us->transport_name = "Shuttle USBAT";
        us->transport = usbat_flash_transport;
        us->transport_reset = usb_stor_CB_reset;
-       us->max_lun = 1;
+       us->max_lun = 0;
 
        result = usb_stor_probe2(us);
        return result;
index f4a82291894ab2964754ac6eb06b1c7dfb4b3978..174a447868cd6924fd81f39ea0da8666b88e2110 100644 (file)
@@ -234,6 +234,20 @@ UNUSUAL_DEV(  0x0421, 0x0495, 0x0370, 0x0370,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_MAX_SECTORS_64 ),
 
+/* Reported by Daniele Forsi <dforsi@gmail.com> */
+UNUSUAL_DEV(  0x0421, 0x04b9, 0x0350, 0x0350,
+               "Nokia",
+               "5300",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64 ),
+
+/* Patch submitted by Victor A. Santos <victoraur.santos@gmail.com> */
+UNUSUAL_DEV(  0x0421, 0x05af, 0x0742, 0x0742,
+               "Nokia",
+               "305",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64),
+
 /* Patch submitted by Mikhail Zolotaryov <lebon@lebon.org.ua> */
 UNUSUAL_DEV(  0x0421, 0x06aa, 0x1110, 0x1110,
                "Nokia",
index e1f47272fdea0da739d7123af256435b105c5cc9..c7ce485dfd1bc3330640d069d2a1c1544c887262 100644 (file)
@@ -1993,7 +1993,7 @@ config FB_SH_MOBILE_HDMI
 
 config FB_TMIO
        tristate "Toshiba Mobile IO FrameBuffer support"
-       depends on FB && MFD_CORE
+       depends on FB && (MFD_TMIO || COMPILE_TEST)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index c204ebe6187e9f021740e38dcb082a1f07a8caf5..5b0e313849bd225d7df251ce40634e8563f6591a 100644 (file)
@@ -1012,13 +1012,20 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
        while (pos < edid[2]) {
                u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
                pr_debug("Data block %u of %u bytes\n", type, len);
-               if (type == 2)
+               if (type == 2) {
                        for (i = pos; i < pos + len; i++) {
                                u8 idx = edid[pos + i] & 0x7f;
                                svd[svd_n++] = idx;
                                pr_debug("N%sative mode #%d\n",
                                         edid[pos + i] & 0x80 ? "" : "on-n", idx);
                        }
+               } else if (type == 3 && len >= 3) {
+                       /* Check Vendor Specific Data Block.  For HDMI,
+                          it is always 00-0C-03 for HDMI Licensing, LLC. */
+                       if (edid[pos + 1] == 3 && edid[pos + 2] == 0xc &&
+                           edid[pos + 3] == 0)
+                               specs->misc |= FB_MISC_HDMI;
+               }
                pos += len + 1;
        }
 
index 6b23508ff0a5f539b2adc5513c36b25245faef2c..a8484f768d04e17f395db1a845b6bb4145ac118f 100644 (file)
@@ -242,6 +242,20 @@ static struct fb_videomode known_lcd_panels[] = {
                .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
                .flag           = 0,
        },
+       [3] = {
+               /* Densitron 84-0023-001T */
+               .name           = "Densitron_84-0023-001T",
+               .xres           = 320,
+               .yres           = 240,
+               .pixclock       = KHZ2PICOS(6400),
+               .left_margin    = 0,
+               .right_margin   = 0,
+               .upper_margin   = 0,
+               .lower_margin   = 0,
+               .hsync_len      = 30,
+               .vsync_len      = 3,
+               .sync           = 0,
+       },
 };
 
 static bool da8xx_fb_is_raster_enabled(void)
index 3ec65a878ac8cfb94598970f380fa2b3354b7fa7..4aa56ba78f321e912f5f4e9b99a5d291fa344af7 100644 (file)
@@ -1068,7 +1068,7 @@ static struct fb_ops gbefb_ops = {
 
 static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size);
+       return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size);
 }
 
 static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
index d4a4ffc24749e18b0509b8886471130a038de6f7..f56a7e2e8136adef77664805d1b711615a216b6b 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig MMP_DISP
         tristate "Marvell MMP Display Subsystem support"
-        depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+        depends on CPU_PXA910 || CPU_MMP2
         help
          Marvell Display Subsystem support.
 
index 7ab31eb76a8c3530e119589550afff1fde69e580..910fcc6ececeed29ff120efaec21b72076d22246 100644 (file)
@@ -554,8 +554,8 @@ static void fb_info_clear(struct fb_info *info)
 static int mmpfb_probe(struct platform_device *pdev)
 {
        struct mmp_buffer_driver_mach_info *mi;
-       struct fb_info *info = 0;
-       struct mmpfb_info *fbi = 0;
+       struct fb_info *info;
+       struct mmpfb_info *fbi;
        int ret, modes_num;
 
        mi = pdev->dev.platform_data;
@@ -569,10 +569,6 @@ static int mmpfb_probe(struct platform_device *pdev)
        if (info == NULL)
                return -ENOMEM;
        fbi = info->par;
-       if (!fbi) {
-               ret = -EINVAL;
-               goto failed;
-       }
 
        /* init fb */
        fbi->fb_info = info;
@@ -667,7 +663,6 @@ failed_free_buff:
                fbi->fb_start_dma);
 failed_destroy_mutex:
        mutex_destroy(&fbi->access_ok);
-failed:
        dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
 
        framebuffer_release(info);
index 02f109a20cd0103963b6c546ec53aaa3275250de..c735d133895c5dc29f80e1940ffbec2c2aa208dc 100644 (file)
@@ -2,12 +2,12 @@ if MMP_DISP
 
 config MMP_DISP_CONTROLLER
        bool "mmp display controller hw support"
-       depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+       depends on CPU_PXA910 || CPU_MMP2
        default n
        help
                Marvell MMP display hw controller support
-               this controller is used on Marvell PXA910,
-               MMP2, MMP3, PXA988 chips
+               this controller is used on Marvell PXA910 and
+               MMP2 chips
 
 config MMP_DISP_SPI
        bool "mmp display controller spi port"
index 53301cfdb1aeb62e3100feb6a21787d4641de241..56fdeab3435583cbe507aa68897bc0987cc1faeb 100644 (file)
@@ -167,11 +167,7 @@ struct lcd_regs {
                                PN2_IOPAD_CONTROL) : LCD_TOP_CTRL)
 
 /* dither configure */
-#ifdef CONFIG_CPU_PXA988
-#define LCD_DITHER_CTRL                                (0x01EC)
-#else
 #define LCD_DITHER_CTRL                                (0x00A0)
-#endif
 
 #define DITHER_TBL_INDEX_SEL(s)                ((s) << 16)
 #define DITHER_MODE2(m)                                ((m) << 12)
@@ -186,15 +182,6 @@ struct lcd_regs {
 #define DITHER_EN1                                     (1)
 
 /* dither table data was fixed by video bpp of input and output*/
-#ifdef CONFIG_CPU_PXA988
-#define DITHER_TB_4X4_INDEX0           (0x6e4ca280)
-#define DITHER_TB_4X4_INDEX1           (0x5d7f91b3)
-#define DITHER_TB_4X8_INDEX0           (0xb391a280)
-#define DITHER_TB_4X8_INDEX1           (0x7f5d6e4c)
-#define DITHER_TB_4X8_INDEX2           (0x80a291b3)
-#define DITHER_TB_4X8_INDEX3           (0x4c6e5d7f)
-#define LCD_DITHER_TBL_DATA            (0x01F0)
-#else
 #define DITHER_TB_4X4_INDEX0           (0x3b19f7d5)
 #define DITHER_TB_4X4_INDEX1           (0x082ac4e6)
 #define DITHER_TB_4X8_INDEX0           (0xf7d508e6)
@@ -202,7 +189,6 @@ struct lcd_regs {
 #define DITHER_TB_4X8_INDEX2           (0xc4e6d5f7)
 #define DITHER_TB_4X8_INDEX3           (0x082a193b)
 #define LCD_DITHER_TBL_DATA            (0x00A4)
-#endif
 
 /* Video Frame 0&1 start address registers */
 #define        LCD_SPU_DMA_START_ADDR_Y0       0x00C0
@@ -933,16 +919,9 @@ struct lcd_regs {
 #define LCD_PN2_SQULN2_CTRL                    (0x02F0)
 #define ALL_LAYER_ALPHA_SEL                    (0x02F4)
 
-/* pxa988 has different MASTER_CTRL from MMP3/MMP2 */
-#ifdef CONFIG_CPU_PXA988
-#define TIMING_MASTER_CONTROL                  (0x01F4)
-#define MASTER_ENH(id)                         (1 << ((id) + 5))
-#define MASTER_ENV(id)                         (1 << ((id) + 6))
-#else
 #define TIMING_MASTER_CONTROL                  (0x02F8)
 #define MASTER_ENH(id)                         (1 << (id))
 #define MASTER_ENV(id)                         (1 << ((id) + 4))
-#endif
 
 #define DSI_START_SEL_SHIFT(id)                (((id) << 1) + 8)
 #define timing_master_config(path, dsi_id, lcd_id) \
@@ -1312,19 +1291,8 @@ struct dsi_regs {
 #define        DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_MASK         (0xff)
 #define        DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_SHIFT        0
 
-/*
- * DSI timings
- * PXA988 has diffrent ESC CLK with MMP2/MMP3
- * it will be used in dsi_set_dphy() in pxa688_phy.c
- * as low power mode clock.
- */
-#ifdef CONFIG_CPU_PXA988
-#define DSI_ESC_CLK                            52  /* Unit: Mhz */
-#define DSI_ESC_CLK_T                          19  /* Unit: ns */
-#else
 #define DSI_ESC_CLK                            66  /* Unit: Mhz */
 #define DSI_ESC_CLK_T                          15  /* Unit: ns */
-#endif
 
 /* LVDS */
 /* LVDS_PHY_CTRL */
index 417f9a27eb7d3ba6bdb0651c216e13a54b6e245b..4df3657fe22114d90a99fb8f8b18a50063e81b3f 100644 (file)
@@ -612,11 +612,9 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
 
        /* handle IO resources */
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->mmio_base = devm_request_and_ioremap(dev, r);
-       if (IS_ERR(priv->mmio_base)) {
-               dev_err(dev, "failed to map I/O memory\n");
+       priv->mmio_base = devm_ioremap_resource(dev, r);
+       if (IS_ERR(priv->mmio_base))
                return PTR_ERR(priv->mmio_base);
-       }
 
        /* enable the clock */
        priv->clk = devm_clk_get(dev, NULL);
index 537d199612af2b88d9442549c5ba8b1e82599c6e..d2fafbbcd7f814825f64f6070b54ce8fdf51a86c 100644 (file)
@@ -162,7 +162,7 @@ static ssize_t contrast_show(struct device *dev,
        struct fb_info *info = dev_get_drvdata(dev);
        struct wm8505fb_info *fbi = to_wm8505fb_info(info);
 
-       return sprintf(buf, "%d\n", fbi->contrast);
+       return sprintf(buf, "%u\n", fbi->contrast);
 }
 
 static ssize_t contrast_store(struct device *dev,
index 1e443629f76d725f7223e4d9234b0cf47e942b0e..4d08f45a9c29aeba18fe4c174bce0a644a090d57 100644 (file)
@@ -865,4 +865,19 @@ bool virtqueue_is_broken(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_is_broken);
 
+/*
+ * This should prevent the device from being used, allowing drivers to
+ * recover.  You may need to grab appropriate locks to flush.
+ */
+void virtio_break_device(struct virtio_device *dev)
+{
+       struct virtqueue *_vq;
+
+       list_for_each_entry(_vq, &dev->vqs, list) {
+               struct vring_virtqueue *vq = to_vvq(_vq);
+               vq->broken = true;
+       }
+}
+EXPORT_SYMBOL_GPL(virtio_break_device);
+
 MODULE_LICENSE("GPL");
index c71e88602ff49a5836a0698a033e3042bdf95f9c..cc1cfae726b38fdc645fc7af79b4879371727b0a 100644 (file)
@@ -259,8 +259,7 @@ static int v9fs_launder_page(struct page *page)
  *
  */
 static ssize_t
-v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
-              loff_t pos, unsigned long nr_segs)
+v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos)
 {
        /*
         * FIXME
@@ -269,7 +268,7 @@ v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
         */
        p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) off/no(%lld/%lu) EINVAL\n",
                 iocb->ki_filp->f_path.dentry->d_name.name,
-                (long long)pos, nr_segs);
+                (long long)pos, iter->nr_segs);
 
        return -EINVAL;
 }
index d8223209d4b1d58710dccf7f3eda0b429655fbb4..0b5568f3fb75e6f3391f518a591018d4021f7538 100644 (file)
@@ -352,9 +352,6 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
                invalidate_mapping_pages(&inode->i_data, 0, -1);
        }
        /* Convert flock to posix lock */
-       fl->fl_owner = (fl_owner_t)filp;
-       fl->fl_start = 0;
-       fl->fl_end = OFFSET_MAX;
        fl->fl_flags |= FL_POSIX;
        fl->fl_flags ^= FL_FLOCK;
 
@@ -695,7 +692,7 @@ v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
 {
        if (filp->f_flags & O_DIRECT)
                return v9fs_direct_read(filp, data, count, offset);
-       return do_sync_read(filp, data, count, offset);
+       return new_sync_read(filp, data, count, offset);
 }
 
 /**
@@ -763,7 +760,7 @@ err_out:
 
 buff_write:
        mutex_unlock(&inode->i_mutex);
-       return do_sync_write(filp, data, count, offsetp);
+       return new_sync_write(filp, data, count, offsetp);
 }
 
 /**
@@ -781,7 +778,7 @@ v9fs_cached_file_write(struct file *filp, const char __user * data,
 
        if (filp->f_flags & O_DIRECT)
                return v9fs_direct_write(filp, data, count, offset);
-       return do_sync_write(filp, data, count, offset);
+       return new_sync_write(filp, data, count, offset);
 }
 
 
@@ -850,8 +847,8 @@ const struct file_operations v9fs_cached_file_operations = {
        .llseek = generic_file_llseek,
        .read = v9fs_cached_file_read,
        .write = v9fs_cached_file_write,
-       .aio_read = generic_file_aio_read,
-       .aio_write = generic_file_aio_write,
+       .read_iter = generic_file_read_iter,
+       .write_iter = generic_file_write_iter,
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
        .lock = v9fs_file_lock,
@@ -863,8 +860,8 @@ const struct file_operations v9fs_cached_file_operations_dotl = {
        .llseek = generic_file_llseek,
        .read = v9fs_cached_file_read,
        .write = v9fs_cached_file_write,
-       .aio_read = generic_file_aio_read,
-       .aio_write = generic_file_aio_write,
+       .read_iter = generic_file_read_iter,
+       .write_iter = generic_file_write_iter,
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
        .lock = v9fs_file_lock_dotl,
index a36da5382b40dc9c09ab6aa59762d9c1a7808b72..07c9edce5aa768ddeb7ae203c8c9cab489ea8417 100644 (file)
 
 const struct file_operations adfs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
        .mmap           = generic_file_mmap,
        .fsync          = generic_file_fsync,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .splice_read    = generic_file_splice_read,
 };
 
index 8669b6ecddee4cc030e21f39358ce2cf5058bddb..9df23175e28b910e5cec924dd87249956d4051a7 100644 (file)
@@ -27,10 +27,10 @@ static int affs_file_release(struct inode *inode, struct file *filp);
 
 const struct file_operations affs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .open           = affs_file_open,
        .release        = affs_file_release,
index 66d50fe2ee459a887511381e8e375db72d2bf1f3..932ce07948b387d7aa75dffb3a9de1e21f1f50b8 100644 (file)
@@ -31,10 +31,10 @@ const struct file_operations afs_file_operations = {
        .open           = afs_open,
        .release        = afs_release,
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = afs_file_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = afs_file_write,
        .mmap           = generic_file_readonly_mmap,
        .splice_read    = generic_file_splice_read,
        .fsync          = afs_fsync,
index a8cf2cff836c337fa64f22009c7cc15e4aa8b6bf..4baf1d2b39e410ffb501c2aba457fdceadcc2cdb 100644 (file)
@@ -555,10 +555,6 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl)
                return -ENOLCK;
 
        /* we're simulating flock() locks using posix locks on the server */
-       fl->fl_owner = (fl_owner_t) file;
-       fl->fl_start = 0;
-       fl->fl_end = OFFSET_MAX;
-
        if (fl->fl_type == F_UNLCK)
                return afs_do_unlk(file, fl);
        return afs_do_setlk(file, fl);
index be75b500005d0d4f68b2d6e3855e71660016353d..d2f91bd615a9304f905d8712fda5d284268ba5be 100644 (file)
@@ -747,8 +747,7 @@ extern int afs_write_end(struct file *file, struct address_space *mapping,
 extern int afs_writepage(struct page *, struct writeback_control *);
 extern int afs_writepages(struct address_space *, struct writeback_control *);
 extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
-extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
-                             unsigned long, loff_t);
+extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);
 extern int afs_writeback_all(struct afs_vnode *);
 extern int afs_fsync(struct file *, loff_t, loff_t, int);
 
index a890db4b9898fc1d888c5e7285da55db85e4da54..ab6adfd525168800524349791c061512a47a7d81 100644 (file)
@@ -625,15 +625,14 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
 /*
  * write to an AFS file
  */
-ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
-                      unsigned long nr_segs, loff_t pos)
+ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct afs_vnode *vnode = AFS_FS_I(file_inode(iocb->ki_filp));
        ssize_t result;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(from);
 
-       _enter("{%x.%u},{%zu},%lu,",
-              vnode->fid.vid, vnode->fid.vnode, count, nr_segs);
+       _enter("{%x.%u},{%zu},",
+              vnode->fid.vid, vnode->fid.vnode, count);
 
        if (IS_SWAPFILE(&vnode->vfs_inode)) {
                printk(KERN_INFO
@@ -644,7 +643,7 @@ ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
        if (!count)
                return 0;
 
-       result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+       result = generic_file_write_iter(iocb, from);
        if (IS_ERR_VALUE(result)) {
                _leave(" = %zd", result);
                return result;
index 12a3de0ee6dacbdea873ec9ea28bdd88d1ea999d..56b28607c32d14704f5aa37066e57b12e4fff79b 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -112,6 +112,11 @@ struct kioctx {
 
        struct work_struct      free_work;
 
+       /*
+        * signals when all in-flight requests are done
+        */
+       struct completion *requests_done;
+
        struct {
                /*
                 * This counts the number of available slots in the ringbuffer,
@@ -508,6 +513,10 @@ static void free_ioctx_reqs(struct percpu_ref *ref)
 {
        struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
 
+       /* At this point we know that there are no any in-flight requests */
+       if (ctx->requests_done)
+               complete(ctx->requests_done);
+
        INIT_WORK(&ctx->free_work, free_ioctx);
        schedule_work(&ctx->free_work);
 }
@@ -718,7 +727,8 @@ err:
  *     when the processes owning a context have all exited to encourage
  *     the rapid destruction of the kioctx.
  */
-static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx)
+static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
+               struct completion *requests_done)
 {
        if (!atomic_xchg(&ctx->dead, 1)) {
                struct kioctx_table *table;
@@ -747,7 +757,11 @@ static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx)
                if (ctx->mmap_size)
                        vm_munmap(ctx->mmap_base, ctx->mmap_size);
 
+               ctx->requests_done = requests_done;
                percpu_ref_kill(&ctx->users);
+       } else {
+               if (requests_done)
+                       complete(requests_done);
        }
 }
 
@@ -809,7 +823,7 @@ void exit_aio(struct mm_struct *mm)
                 */
                ctx->mmap_size = 0;
 
-               kill_ioctx(mm, ctx);
+               kill_ioctx(mm, ctx, NULL);
        }
 }
 
@@ -1185,7 +1199,7 @@ 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(current->mm, ioctx);
+                       kill_ioctx(current->mm, ioctx, NULL);
                percpu_ref_put(&ioctx->users);
        }
 
@@ -1203,8 +1217,22 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
 {
        struct kioctx *ioctx = lookup_ioctx(ctx);
        if (likely(NULL != ioctx)) {
-               kill_ioctx(current->mm, ioctx);
+               struct completion requests_done =
+                       COMPLETION_INITIALIZER_ONSTACK(requests_done);
+
+               /* Pass requests_done to kill_ioctx() where it can be set
+                * in a thread-safe way. If we try to set it here then we have
+                * a race condition if two io_destroy() called simultaneously.
+                */
+               kill_ioctx(current->mm, ioctx, &requests_done);
                percpu_ref_put(&ioctx->users);
+
+               /* Wait until all IO for the context are done. Otherwise kernel
+                * keep using user-space buffers even if user thinks the context
+                * is destroyed.
+                */
+               wait_for_completion(&requests_done);
+
                return 0;
        }
        pr_debug("EINVAL: io_destroy: invalid context id\n");
@@ -1213,6 +1241,7 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
 
 typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *,
                            unsigned long, loff_t);
+typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *);
 
 static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
                                     int rw, char __user *buf,
@@ -1270,7 +1299,9 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
        int rw;
        fmode_t mode;
        aio_rw_op *rw_op;
+       rw_iter_op *iter_op;
        struct iovec inline_vec, *iovec = &inline_vec;
+       struct iov_iter iter;
 
        switch (opcode) {
        case IOCB_CMD_PREAD:
@@ -1278,6 +1309,7 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
                mode    = FMODE_READ;
                rw      = READ;
                rw_op   = file->f_op->aio_read;
+               iter_op = file->f_op->read_iter;
                goto rw_common;
 
        case IOCB_CMD_PWRITE:
@@ -1285,12 +1317,13 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
                mode    = FMODE_WRITE;
                rw      = WRITE;
                rw_op   = file->f_op->aio_write;
+               iter_op = file->f_op->write_iter;
                goto rw_common;
 rw_common:
                if (unlikely(!(file->f_mode & mode)))
                        return -EBADF;
 
-               if (!rw_op)
+               if (!rw_op && !iter_op)
                        return -EINVAL;
 
                ret = (opcode == IOCB_CMD_PREADV ||
@@ -1299,10 +1332,8 @@ rw_common:
                                                &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)
+                       ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes);
                if (ret < 0) {
                        if (iovec != &inline_vec)
                                kfree(iovec);
@@ -1321,7 +1352,12 @@ rw_common:
                if (rw == WRITE)
                        file_start_write(file);
 
-               ret = rw_op(req, iovec, nr_segs, req->ki_pos);
+               if (iter_op) {
+                       iov_iter_init(&iter, rw, iovec, nr_segs, req->ki_nbytes);
+                       ret = iter_op(req, &iter);
+               } else {
+                       ret = rw_op(req, iovec, nr_segs, req->ki_pos);
+               }
 
                if (rw == WRITE)
                        file_end_write(file);
index ae28922183357d4c0e4d491a452919e125ba8bc3..e7f88ace1a2508d260ea8feae3addc5e2752980c 100644 (file)
 
 const struct file_operations bfs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .splice_read    = generic_file_splice_read,
 };
index 1c2ce0c8771133194ecb9d91517a7dd67c571765..9e241063a616f2c4ad023a08c8b6b06d676adb56 100644 (file)
@@ -617,7 +617,7 @@ int bioset_integrity_create(struct bio_set *bs, int pool_size)
        if (!bs->bio_integrity_pool)
                return -1;
 
-       bs->bvec_integrity_pool = biovec_create_pool(bs, pool_size);
+       bs->bvec_integrity_pool = biovec_create_pool(pool_size);
        if (!bs->bvec_integrity_pool) {
                mempool_destroy(bs->bio_integrity_pool);
                return -1;
index 6f0362b77806c61909aa37433a9e77eb77476cff..96d28eee8a1eeb425f0025f4c0ccaa61e184f8ab 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -305,6 +305,8 @@ static void bio_chain_endio(struct bio *bio, int error)
 
 /**
  * bio_chain - chain bio completions
+ * @bio: the target bio
+ * @parent: the @bio's parent bio
  *
  * The caller won't have a bi_end_io called when @bio completes - instead,
  * @parent's bi_end_io won't be called until both @parent and @bio have
@@ -1011,8 +1013,7 @@ static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio,
        bio->bi_private = bmd;
 }
 
-static struct bio_map_data *bio_alloc_map_data(int nr_segs,
-                                              unsigned int iov_count,
+static struct bio_map_data *bio_alloc_map_data(unsigned int iov_count,
                                               gfp_t gfp_mask)
 {
        if (iov_count > UIO_MAXIOV)
@@ -1154,7 +1155,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
        if (offset)
                nr_pages++;
 
-       bmd = bio_alloc_map_data(nr_pages, iov_count, gfp_mask);
+       bmd = bio_alloc_map_data(iov_count, gfp_mask);
        if (!bmd)
                return ERR_PTR(-ENOMEM);
 
@@ -1859,7 +1860,7 @@ EXPORT_SYMBOL_GPL(bio_trim);
  * create memory pools for biovec's in a bio_set.
  * use the global biovec slabs created for general use.
  */
-mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries)
+mempool_t *biovec_create_pool(int pool_entries)
 {
        struct biovec_slab *bp = bvec_slabs + BIOVEC_MAX_IDX;
 
@@ -1922,7 +1923,7 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
        if (!bs->bio_pool)
                goto bad;
 
-       bs->bvec_pool = biovec_create_pool(bs, pool_size);
+       bs->bvec_pool = biovec_create_pool(pool_size);
        if (!bs->bvec_pool)
                goto bad;
 
index 552a8d13bc321f4d1cf64fb9b3171893e28e73e9..e68e150b1b163c15da172cfa60ed832d14841495 100644 (file)
@@ -165,14 +165,15 @@ blkdev_get_block(struct inode *inode, sector_t iblock,
 }
 
 static ssize_t
-blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
-                       loff_t offset, unsigned long nr_segs)
+blkdev_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
+                       loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
 
-       return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
-                                   nr_segs, blkdev_get_block, NULL, NULL, 0);
+       return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iter,
+                                   offset, blkdev_get_block,
+                                   NULL, NULL, 0);
 }
 
 int __sync_blockdev(struct block_device *bdev, int wait)
@@ -1508,43 +1509,38 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
  * Does not take i_mutex for the write and thus is not for general purpose
  * use.
  */
-ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                        unsigned long nr_segs, loff_t pos)
+ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct blk_plug plug;
        ssize_t ret;
 
-       BUG_ON(iocb->ki_pos != pos);
-
        blk_start_plug(&plug);
-       ret = __generic_file_aio_write(iocb, iov, nr_segs);
+       ret = __generic_file_write_iter(iocb, from);
        if (ret > 0) {
                ssize_t err;
-
-               err = generic_write_sync(file, pos, ret);
+               err = generic_write_sync(file, iocb->ki_pos - ret, ret);
                if (err < 0)
                        ret = err;
        }
        blk_finish_plug(&plug);
        return ret;
 }
-EXPORT_SYMBOL_GPL(blkdev_aio_write);
+EXPORT_SYMBOL_GPL(blkdev_write_iter);
 
-static ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
-                        unsigned long nr_segs, loff_t pos)
+static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct file *file = iocb->ki_filp;
        struct inode *bd_inode = file->f_mapping->host;
        loff_t size = i_size_read(bd_inode);
+       loff_t pos = iocb->ki_pos;
 
        if (pos >= size)
                return 0;
 
        size -= pos;
-       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);
+       iov_iter_truncate(to, size);
+       return generic_file_read_iter(iocb, to);
 }
 
 /*
@@ -1576,10 +1572,10 @@ const struct file_operations def_blk_fops = {
        .open           = blkdev_open,
        .release        = blkdev_close,
        .llseek         = block_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = blkdev_aio_read,
-       .aio_write      = blkdev_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = blkdev_read_iter,
+       .write_iter     = blkdev_write_iter,
        .mmap           = generic_file_mmap,
        .fsync          = blkdev_fsync,
        .unlocked_ioctl = block_ioctl,
@@ -1587,7 +1583,7 @@ const struct file_operations def_blk_fops = {
        .compat_ioctl   = compat_blkdev_ioctl,
 #endif
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
 };
 
 int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
index ae6af072b635e195e26f3199c3aabd427964881f..17e7393c50f0a97484ec9ce7898c9b6cf7aacdfa 100644 (file)
@@ -447,7 +447,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
                write_bytes -= copied;
                total_copied += copied;
 
-               /* Return to btrfs_file_aio_write to fault page */
+               /* Return to btrfs_file_write_iter to fault page */
                if (unlikely(copied == 0))
                        break;
 
@@ -1658,27 +1658,22 @@ again:
 }
 
 static ssize_t __btrfs_direct_write(struct kiocb *iocb,
-                                   const struct iovec *iov,
-                                   unsigned long nr_segs, loff_t pos,
-                                   size_t count, size_t ocount)
+                                   struct iov_iter *from,
+                                   loff_t pos)
 {
        struct file *file = iocb->ki_filp;
-       struct iov_iter i;
        ssize_t written;
        ssize_t written_buffered;
        loff_t endbyte;
        int err;
 
-       written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
-                                           count, ocount);
+       written = generic_file_direct_write(iocb, from, pos);
 
-       if (written < 0 || written == count)
+       if (written < 0 || !iov_iter_count(from))
                return written;
 
        pos += written;
-       count -= written;
-       iov_iter_init(&i, iov, nr_segs, count, written);
-       written_buffered = __btrfs_buffered_write(file, &i, pos);
+       written_buffered = __btrfs_buffered_write(file, from, pos);
        if (written_buffered < 0) {
                err = written_buffered;
                goto out;
@@ -1713,9 +1708,8 @@ static void update_time_for_write(struct inode *inode)
                inode_inc_iversion(inode);
 }
 
-static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
-                                   const struct iovec *iov,
-                                   unsigned long nr_segs, loff_t pos)
+static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
+                                   struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
@@ -1724,18 +1718,12 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        u64 end_pos;
        ssize_t num_written = 0;
        ssize_t err = 0;
-       size_t count, ocount;
+       size_t count = iov_iter_count(from);
        bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host);
+       loff_t pos = iocb->ki_pos;
 
        mutex_lock(&inode->i_mutex);
 
-       err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
-       if (err) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
-       }
-       count = ocount;
-
        current->backing_dev_info = inode->i_mapping->backing_dev_info;
        err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
        if (err) {
@@ -1748,6 +1736,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                goto out;
        }
 
+       iov_iter_truncate(from, count);
+
        err = file_remove_suid(file);
        if (err) {
                mutex_unlock(&inode->i_mutex);
@@ -1789,14 +1779,9 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                atomic_inc(&BTRFS_I(inode)->sync_writers);
 
        if (unlikely(file->f_flags & O_DIRECT)) {
-               num_written = __btrfs_direct_write(iocb, iov, nr_segs,
-                                                  pos, count, ocount);
+               num_written = __btrfs_direct_write(iocb, from, pos);
        } else {
-               struct iov_iter i;
-
-               iov_iter_init(&i, iov, nr_segs, count, num_written);
-
-               num_written = __btrfs_buffered_write(file, &i, pos);
+               num_written = __btrfs_buffered_write(file, from, pos);
                if (num_written > 0)
                        iocb->ki_pos = pos + num_written;
        }
@@ -2633,11 +2618,11 @@ out:
 
 const struct file_operations btrfs_file_operations = {
        .llseek         = btrfs_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
        .splice_read    = generic_file_splice_read,
-       .aio_write      = btrfs_file_aio_write,
+       .write_iter     = btrfs_file_write_iter,
        .mmap           = btrfs_file_mmap,
        .open           = generic_file_open,
        .release        = btrfs_release_file,
index 5f805bc944fad00127cf812a922e54ccd9f7b396..c8386f1961f001586f5f1824e7e02d1b63bf4470 100644 (file)
@@ -7391,39 +7391,30 @@ free_ordered:
 }
 
 static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb,
-                       const struct iovec *iov, loff_t offset,
-                       unsigned long nr_segs)
+                       const struct iov_iter *iter, loff_t offset)
 {
        int seg;
        int i;
-       size_t size;
-       unsigned long addr;
        unsigned blocksize_mask = root->sectorsize - 1;
        ssize_t retval = -EINVAL;
-       loff_t end = offset;
 
        if (offset & blocksize_mask)
                goto out;
 
-       /* Check the memory alignment.  Blocks cannot straddle pages */
-       for (seg = 0; seg < nr_segs; seg++) {
-               addr = (unsigned long)iov[seg].iov_base;
-               size = iov[seg].iov_len;
-               end += size;
-               if ((addr & blocksize_mask) || (size & blocksize_mask))
-                       goto out;
-
-               /* If this is a write we don't need to check anymore */
-               if (rw & WRITE)
-                       continue;
+       if (iov_iter_alignment(iter) & blocksize_mask)
+               goto out;
 
-               /*
-                * Check to make sure we don't have duplicate iov_base's in this
-                * iovec, if so return EINVAL, otherwise we'll get csum errors
-                * when reading back.
-                */
-               for (i = seg + 1; i < nr_segs; i++) {
-                       if (iov[seg].iov_base == iov[i].iov_base)
+       /* If this is a write we don't need to check anymore */
+       if (rw & WRITE)
+               return 0;
+       /*
+        * Check to make sure we don't have duplicate iov_base's in this
+        * iovec, if so return EINVAL, otherwise we'll get csum errors
+        * when reading back.
+        */
+       for (seg = 0; seg < iter->nr_segs; seg++) {
+               for (i = seg + 1; i < iter->nr_segs; i++) {
+                       if (iter->iov[seg].iov_base == iter->iov[i].iov_base)
                                goto out;
                }
        }
@@ -7433,8 +7424,7 @@ out:
 }
 
 static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
-                       const struct iovec *iov, loff_t offset,
-                       unsigned long nr_segs)
+                       struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
@@ -7444,8 +7434,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
        bool relock = false;
        ssize_t ret;
 
-       if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov,
-                           offset, nr_segs))
+       if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iter, offset))
                return 0;
 
        atomic_inc(&inode->i_dio_count);
@@ -7457,7 +7446,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
         * we need to flush the dirty pages again to make absolutely sure
         * that any outstanding dirty pages are on disk.
         */
-       count = iov_length(iov, nr_segs);
+       count = iov_iter_count(iter);
        if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
                     &BTRFS_I(inode)->runtime_flags))
                filemap_fdatawrite_range(inode->i_mapping, offset, count);
@@ -7484,7 +7473,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
 
        ret = __blockdev_direct_IO(rw, iocb, inode,
                        BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev,
-                       iov, offset, nr_segs, btrfs_get_blocks_direct, NULL,
+                       iter, offset, btrfs_get_blocks_direct, NULL,
                        btrfs_submit_direct, flags);
        if (rw & WRITE) {
                if (ret < 0 && ret != -EIOCBQUEUED)
index b53278c9fd9718509e96d91d3ea1027581714214..342ca5e423f9bb22ecbd1974778eb99c99d5ae6b 100644 (file)
@@ -1187,8 +1187,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
  * never get called.
  */
 static ssize_t ceph_direct_io(int rw, struct kiocb *iocb,
-                             const struct iovec *iov,
-                             loff_t pos, unsigned long nr_segs)
+                             struct iov_iter *iter,
+                             loff_t pos)
 {
        WARN_ON(1);
        return -EINVAL;
index 2e5e648eb5c3dc3bd82bea5ce8dead051864cf75..c561b628ebce519d111d159f541b9df88242a5b1 100644 (file)
@@ -3261,7 +3261,7 @@ int ceph_encode_inode_release(void **p, struct inode *inode,
                        rel->seq = cpu_to_le32(cap->seq);
                        rel->issue_seq = cpu_to_le32(cap->issue_seq),
                        rel->mseq = cpu_to_le32(cap->mseq);
-                       rel->caps = cpu_to_le32(cap->issued);
+                       rel->caps = cpu_to_le32(cap->implemented);
                        rel->wanted = cpu_to_le32(cap->mds_wanted);
                        rel->dname_len = 0;
                        rel->dname_seq = 0;
index 766410a12c2cb209a224fcfd97f63a055fd20801..c29d6ae6887489c29902bec33c4118d4d807e9dc 100644 (file)
@@ -141,7 +141,7 @@ static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
 
        /* start at beginning? */
        if (ctx->pos == 2 || last == NULL ||
-           ctx->pos < ceph_dentry(last)->offset) {
+           fpos_cmp(ctx->pos, ceph_dentry(last)->offset) < 0) {
                if (list_empty(&parent->d_subdirs))
                        goto out_unlock;
                p = parent->d_subdirs.prev;
@@ -182,9 +182,16 @@ more:
        spin_unlock(&dentry->d_lock);
        spin_unlock(&parent->d_lock);
 
+       /* make sure a dentry wasn't dropped while we didn't have parent lock */
+       if (!ceph_dir_is_complete(dir)) {
+               dout(" lost dir complete on %p; falling back to mds\n", dir);
+               dput(dentry);
+               err = -EAGAIN;
+               goto out;
+       }
+
        dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, ctx->pos,
             dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
-       ctx->pos = di->offset;
        if (!dir_emit(ctx, dentry->d_name.name,
                      dentry->d_name.len,
                      ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
@@ -198,19 +205,12 @@ more:
                return 0;
        }
 
+       ctx->pos = di->offset + 1;
+
        if (last)
                dput(last);
        last = dentry;
 
-       ctx->pos++;
-
-       /* make sure a dentry wasn't dropped while we didn't have parent lock */
-       if (!ceph_dir_is_complete(dir)) {
-               dout(" lost dir complete on %p; falling back to mds\n", dir);
-               err = -EAGAIN;
-               goto out;
-       }
-
        spin_lock(&parent->d_lock);
        p = p->prev;    /* advance to next dentry */
        goto more;
@@ -296,6 +296,8 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
                err = __dcache_readdir(file, ctx, shared_gen);
                if (err != -EAGAIN)
                        return err;
+               frag = fpos_frag(ctx->pos);
+               off = fpos_off(ctx->pos);
        } else {
                spin_unlock(&ci->i_ceph_lock);
        }
@@ -446,7 +448,6 @@ more:
        if (atomic_read(&ci->i_release_count) == fi->dir_release_count) {
                dout(" marking %p complete\n", inode);
                __ceph_dir_set_complete(ci, fi->dir_release_count);
-               ci->i_max_offset = ctx->pos;
        }
        spin_unlock(&ci->i_ceph_lock);
 
@@ -935,14 +936,16 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
                 * to do it here.
                 */
 
-               /* d_move screws up d_subdirs order */
-               ceph_dir_clear_complete(new_dir);
-
                d_move(old_dentry, new_dentry);
 
                /* ensure target dentry is invalidated, despite
                   rehashing bug in vfs_rename_dir */
                ceph_invalidate_dentry_lease(new_dentry);
+
+               /* d_move screws up sibling dentries' offsets */
+               ceph_dir_clear_complete(old_dir);
+               ceph_dir_clear_complete(new_dir);
+
        }
        ceph_mdsc_put_request(req);
        return err;
index 88a6df4cbe6d8a52bd083a756ac452b798c33708..302085100c28af1a2ed67269e955b3d0839539be 100644 (file)
@@ -418,7 +418,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
        struct page **pages;
        u64 off = iocb->ki_pos;
        int num_pages, ret;
-       size_t len = i->count;
+       size_t len = iov_iter_count(i);
 
        dout("sync_read on file %p %llu~%u %s\n", file, off,
             (unsigned)len,
@@ -436,25 +436,26 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
 
        if (file->f_flags & O_DIRECT) {
                while (iov_iter_count(i)) {
-                       void __user *data = i->iov[0].iov_base + i->iov_offset;
-                       size_t len = i->iov[0].iov_len - i->iov_offset;
+                       size_t start;
+                       ssize_t n;
 
-                       num_pages = calc_pages_for((unsigned long)data, len);
-                       pages = ceph_get_direct_page_vector(data,
-                                                           num_pages, true);
-                       if (IS_ERR(pages))
-                               return PTR_ERR(pages);
+                       n = iov_iter_get_pages_alloc(i, &pages, INT_MAX, &start);
+                       if (n < 0)
+                               return n;
 
-                       ret = striped_read(inode, off, len,
+                       num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
+
+                       ret = striped_read(inode, off, n,
                                           pages, num_pages, checkeof,
-                                          1, (unsigned long)data & ~PAGE_MASK);
+                                          1, start);
+
                        ceph_put_page_vector(pages, num_pages, true);
 
                        if (ret <= 0)
                                break;
                        off += ret;
                        iov_iter_advance(i, ret);
-                       if (ret < len)
+                       if (ret < n)
                                break;
                }
        } else {
@@ -466,25 +467,14 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
                                        num_pages, checkeof, 0, 0);
                if (ret > 0) {
                        int l, k = 0;
-                       size_t left = len = ret;
+                       size_t left = ret;
 
                        while (left) {
-                               void __user *data = i->iov[0].iov_base
-                                                       + i->iov_offset;
-                               l = min(i->iov[0].iov_len - i->iov_offset,
-                                       left);
-
-                               ret = ceph_copy_page_vector_to_user(&pages[k],
-                                                                   data, off,
-                                                                   l);
-                               if (ret > 0) {
-                                       iov_iter_advance(i, ret);
-                                       left -= ret;
-                                       off += ret;
-                                       k = calc_pages_for(iocb->ki_pos,
-                                                          len - left + 1) - 1;
-                                       BUG_ON(k >= num_pages && left);
-                               } else
+                               int copy = min_t(size_t, PAGE_SIZE, left);
+                               l = copy_page_to_iter(pages[k++], 0, copy, i);
+                               off += l;
+                               left -= l;
+                               if (l < copy)
                                        break;
                        }
                }
@@ -541,8 +531,7 @@ static void ceph_sync_write_unsafe(struct ceph_osd_request *req, bool unsafe)
  * objects, rollback on failure, etc.)
  */
 static ssize_t
-ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
-                      unsigned long nr_segs, size_t count)
+ceph_sync_direct_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
@@ -556,11 +545,10 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
        int written = 0;
        int flags;
        int check_caps = 0;
-       int page_align;
        int ret;
        struct timespec mtime = CURRENT_TIME;
        loff_t pos = iocb->ki_pos;
-       struct iov_iter i;
+       size_t count = iov_iter_count(from);
 
        if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
                return -EROFS;
@@ -582,13 +570,10 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
                CEPH_OSD_FLAG_ONDISK |
                CEPH_OSD_FLAG_WRITE;
 
-       iov_iter_init(&i, iov, nr_segs, count, 0);
-
-       while (iov_iter_count(&i) > 0) {
-               void __user *data = i.iov->iov_base + i.iov_offset;
-               u64 len = i.iov->iov_len - i.iov_offset;
-
-               page_align = (unsigned long)data & ~PAGE_MASK;
+       while (iov_iter_count(from) > 0) {
+               u64 len = iov_iter_single_seg_count(from);
+               size_t start;
+               ssize_t n;
 
                snapc = ci->i_snap_realm->cached_context;
                vino = ceph_vino(inode);
@@ -604,20 +589,21 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
                        break;
                }
 
-               num_pages = calc_pages_for(page_align, len);
-               pages = ceph_get_direct_page_vector(data, num_pages, false);
-               if (IS_ERR(pages)) {
-                       ret = PTR_ERR(pages);
-                       goto out;
+               n = iov_iter_get_pages_alloc(from, &pages, len, &start);
+               if (unlikely(n < 0)) {
+                       ret = n;
+                       ceph_osdc_put_request(req);
+                       break;
                }
 
+               num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
                /*
                 * throw out any page cache pages in this range. this
                 * may block.
                 */
                truncate_inode_pages_range(inode->i_mapping, pos,
-                                  (pos+len) | (PAGE_CACHE_SIZE-1));
-               osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align,
+                                  (pos+n) | (PAGE_CACHE_SIZE-1));
+               osd_req_op_extent_osd_data_pages(req, 0, pages, n, start,
                                                false, false);
 
                /* BUG_ON(vino.snap != CEPH_NOSNAP); */
@@ -629,22 +615,20 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
 
                ceph_put_page_vector(pages, num_pages, false);
 
-out:
                ceph_osdc_put_request(req);
-               if (ret == 0) {
-                       pos += len;
-                       written += len;
-                       iov_iter_advance(&i, (size_t)len);
-
-                       if (pos > i_size_read(inode)) {
-                               check_caps = ceph_inode_set_size(inode, pos);
-                               if (check_caps)
-                                       ceph_check_caps(ceph_inode(inode),
-                                                       CHECK_CAPS_AUTHONLY,
-                                                       NULL);
-                       }
-               } else
+               if (ret)
                        break;
+               pos += n;
+               written += n;
+               iov_iter_advance(from, n);
+
+               if (pos > i_size_read(inode)) {
+                       check_caps = ceph_inode_set_size(inode, pos);
+                       if (check_caps)
+                               ceph_check_caps(ceph_inode(inode),
+                                               CHECK_CAPS_AUTHONLY,
+                                               NULL);
+               }
        }
 
        if (ret != -EOLDSNAPC && written > 0) {
@@ -662,8 +646,7 @@ out:
  * correct atomic write, we should e.g. take write locks on all
  * objects, rollback on failure, etc.)
  */
-static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
-                              unsigned long nr_segs, size_t count)
+static ssize_t ceph_sync_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
@@ -681,7 +664,7 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
        int ret;
        struct timespec mtime = CURRENT_TIME;
        loff_t pos = iocb->ki_pos;
-       struct iov_iter i;
+       size_t count = iov_iter_count(from);
 
        if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
                return -EROFS;
@@ -703,9 +686,7 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
                CEPH_OSD_FLAG_WRITE |
                CEPH_OSD_FLAG_ACK;
 
-       iov_iter_init(&i, iov, nr_segs, count, 0);
-
-       while ((len = iov_iter_count(&i)) > 0) {
+       while ((len = iov_iter_count(from)) > 0) {
                size_t left;
                int n;
 
@@ -737,13 +718,12 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
                left = len;
                for (n = 0; n < num_pages; n++) {
                        size_t plen = min_t(size_t, left, PAGE_SIZE);
-                       ret = iov_iter_copy_from_user(pages[n], &i, 0, plen);
+                       ret = copy_page_from_iter(pages[n], 0, plen, from);
                        if (ret != plen) {
                                ret = -EFAULT;
                                break;
                        }
                        left -= ret;
-                       iov_iter_advance(&i, ret);
                }
 
                if (ret < 0) {
@@ -796,8 +776,7 @@ out:
  *
  * Hmm, the sync read case isn't actually async... should it be?
  */
-static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
-                            unsigned long nr_segs, loff_t pos)
+static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct file *filp = iocb->ki_filp;
        struct ceph_file_info *fi = filp->private_data;
@@ -823,40 +802,20 @@ again:
        if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
            (iocb->ki_filp->f_flags & O_DIRECT) ||
            (fi->flags & CEPH_F_SYNC)) {
-               struct iov_iter i;
 
                dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n",
                     inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,
                     ceph_cap_string(got));
 
-               if (!read) {
-                       ret = generic_segment_checks(iov, &nr_segs,
-                                                       &len, VERIFY_WRITE);
-                       if (ret)
-                               goto out;
-               }
-
-               iov_iter_init(&i, iov, nr_segs, len, read);
-
                /* hmm, this isn't really async... */
-               ret = ceph_sync_read(iocb, &i, &checkeof);
+               ret = ceph_sync_read(iocb, to, &checkeof);
        } else {
-               /*
-                * We can't modify the content of iov,
-                * so we only read from beginning.
-                */
-               if (read) {
-                       iocb->ki_pos = pos;
-                       len = iocb->ki_nbytes;
-                       read = 0;
-               }
                dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
-                    inode, ceph_vinop(inode), pos, (unsigned)len,
+                    inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,
                     ceph_cap_string(got));
 
-               ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+               ret = generic_file_read_iter(iocb, to);
        }
-out:
        dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
             inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
        ceph_put_cap_refs(ci, got);
@@ -872,6 +831,7 @@ out:
                             ", reading more\n", iocb->ki_pos,
                             inode->i_size);
 
+                       iov_iter_advance(to, ret);
                        read += ret;
                        len -= ret;
                        checkeof = 0;
@@ -895,8 +855,7 @@ out:
  *
  * If we are near ENOSPC, write synchronously.
  */
-static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                      unsigned long nr_segs, loff_t pos)
+static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct ceph_file_info *fi = file->private_data;
@@ -904,18 +863,15 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_osd_client *osdc =
                &ceph_sb_to_client(inode->i_sb)->client->osdc;
-       ssize_t count, written = 0;
+       ssize_t count = iov_iter_count(from), written = 0;
        int err, want, got;
+       loff_t pos = iocb->ki_pos;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
 
        mutex_lock(&inode->i_mutex);
 
-       err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
-       if (err)
-               goto out;
-
        /* We can write back this queue in page reclaim */
        current->backing_dev_info = file->f_mapping->backing_dev_info;
 
@@ -925,6 +881,7 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
 
        if (count == 0)
                goto out;
+       iov_iter_truncate(from, count);
 
        err = file_remove_suid(file);
        if (err)
@@ -956,23 +913,26 @@ retry_snap:
 
        if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
            (file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) {
+               struct iov_iter data;
                mutex_unlock(&inode->i_mutex);
+               /* we might need to revert back to that point */
+               data = *from;
                if (file->f_flags & O_DIRECT)
-                       written = ceph_sync_direct_write(iocb, iov,
-                                                        nr_segs, count);
+                       written = ceph_sync_direct_write(iocb, &data);
                else
-                       written = ceph_sync_write(iocb, iov, nr_segs, count);
+                       written = ceph_sync_write(iocb, &data);
                if (written == -EOLDSNAPC) {
                        dout("aio_write %p %llx.%llx %llu~%u"
                                "got EOLDSNAPC, retrying\n",
                                inode, ceph_vinop(inode),
-                               pos, (unsigned)iov->iov_len);
+                               pos, (unsigned)count);
                        mutex_lock(&inode->i_mutex);
                        goto retry_snap;
                }
+               if (written > 0)
+                       iov_iter_advance(from, written);
        } else {
                loff_t old_size = inode->i_size;
-               struct iov_iter from;
                /*
                 * No need to acquire the i_truncate_mutex. Because
                 * the MDS revokes Fwb caps before sending truncate
@@ -980,8 +940,7 @@ retry_snap:
                 * are pending vmtruncate. So write and vmtruncate
                 * can not run at the same time
                 */
-               iov_iter_init(&from, iov, nr_segs, count, 0);
-               written = generic_perform_write(file, &from, pos);
+               written = generic_perform_write(file, from, pos);
                if (likely(written >= 0))
                        iocb->ki_pos = pos + written;
                if (inode->i_size > old_size)
@@ -999,7 +958,7 @@ retry_snap:
        }
 
        dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s\n",
-            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+            inode, ceph_vinop(inode), pos, (unsigned)count,
             ceph_cap_string(got));
        ceph_put_cap_refs(ci, got);
 
@@ -1276,16 +1235,16 @@ const struct file_operations ceph_file_fops = {
        .open = ceph_open,
        .release = ceph_release,
        .llseek = ceph_llseek,
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = ceph_aio_read,
-       .aio_write = ceph_aio_write,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = ceph_read_iter,
+       .write_iter = ceph_write_iter,
        .mmap = ceph_mmap,
        .fsync = ceph_fsync,
        .lock = ceph_lock,
        .flock = ceph_flock,
        .splice_read = generic_file_splice_read,
-       .splice_write = generic_file_splice_write,
+       .splice_write = iter_file_splice_write,
        .unlocked_ioctl = ceph_ioctl,
        .compat_ioctl   = ceph_ioctl,
        .fallocate      = ceph_fallocate,
index 0b0728e5be2d7cba589a935159b88f9d26f0b2e9..233c6f96910abc78d2b120e4e30a44ba0009b88a 100644 (file)
@@ -744,7 +744,6 @@ static int fill_inode(struct inode *inode,
            !__ceph_dir_is_complete(ci)) {
                dout(" marking %p complete (empty)\n", inode);
                __ceph_dir_set_complete(ci, atomic_read(&ci->i_release_count));
-               ci->i_max_offset = 2;
        }
 no_change:
        /* only update max_size on auth cap */
@@ -889,41 +888,6 @@ out_unlock:
        return;
 }
 
-/*
- * Set dentry's directory position based on the current dir's max, and
- * order it in d_subdirs, so that dcache_readdir behaves.
- *
- * Always called under directory's i_mutex.
- */
-static void ceph_set_dentry_offset(struct dentry *dn)
-{
-       struct dentry *dir = dn->d_parent;
-       struct inode *inode = dir->d_inode;
-       struct ceph_inode_info *ci;
-       struct ceph_dentry_info *di;
-
-       BUG_ON(!inode);
-
-       ci = ceph_inode(inode);
-       di = ceph_dentry(dn);
-
-       spin_lock(&ci->i_ceph_lock);
-       if (!__ceph_dir_is_complete(ci)) {
-               spin_unlock(&ci->i_ceph_lock);
-               return;
-       }
-       di->offset = ceph_inode(inode)->i_max_offset++;
-       spin_unlock(&ci->i_ceph_lock);
-
-       spin_lock(&dir->d_lock);
-       spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
-       list_move(&dn->d_u.d_child, &dir->d_subdirs);
-       dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
-            dn->d_u.d_child.prev, dn->d_u.d_child.next);
-       spin_unlock(&dn->d_lock);
-       spin_unlock(&dir->d_lock);
-}
-
 /*
  * splice a dentry to an inode.
  * caller must hold directory i_mutex for this to be safe.
@@ -933,7 +897,7 @@ static void ceph_set_dentry_offset(struct dentry *dn)
  * the caller) if we fail.
  */
 static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
-                                   bool *prehash, bool set_offset)
+                                   bool *prehash)
 {
        struct dentry *realdn;
 
@@ -965,8 +929,6 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
        }
        if ((!prehash || *prehash) && d_unhashed(dn))
                d_rehash(dn);
-       if (set_offset)
-               ceph_set_dentry_offset(dn);
 out:
        return dn;
 }
@@ -987,7 +949,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
 {
        struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
        struct inode *in = NULL;
-       struct ceph_mds_reply_inode *ininfo;
        struct ceph_vino vino;
        struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
        int err = 0;
@@ -1161,6 +1122,9 @@ retry_lookup:
 
                /* rename? */
                if (req->r_old_dentry && req->r_op == CEPH_MDS_OP_RENAME) {
+                       struct inode *olddir = req->r_old_dentry_dir;
+                       BUG_ON(!olddir);
+
                        dout(" src %p '%.*s' dst %p '%.*s'\n",
                             req->r_old_dentry,
                             req->r_old_dentry->d_name.len,
@@ -1180,13 +1144,10 @@ retry_lookup:
                           rehashing bug in vfs_rename_dir */
                        ceph_invalidate_dentry_lease(dn);
 
-                       /*
-                        * d_move() puts the renamed dentry at the end of
-                        * d_subdirs.  We need to assign it an appropriate
-                        * directory offset so we can behave when dir is
-                        * complete.
-                        */
-                       ceph_set_dentry_offset(req->r_old_dentry);
+                       /* d_move screws up sibling dentries' offsets */
+                       ceph_dir_clear_complete(dir);
+                       ceph_dir_clear_complete(olddir);
+
                        dout("dn %p gets new offset %lld\n", req->r_old_dentry,
                             ceph_dentry(req->r_old_dentry)->offset);
 
@@ -1213,8 +1174,9 @@ retry_lookup:
 
                /* attach proper inode */
                if (!dn->d_inode) {
+                       ceph_dir_clear_complete(dir);
                        ihold(in);
-                       dn = splice_dentry(dn, in, &have_lease, true);
+                       dn = splice_dentry(dn, in, &have_lease);
                        if (IS_ERR(dn)) {
                                err = PTR_ERR(dn);
                                goto done;
@@ -1235,17 +1197,16 @@ retry_lookup:
                   (req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
                    req->r_op == CEPH_MDS_OP_MKSNAP)) {
                struct dentry *dn = req->r_dentry;
+               struct inode *dir = req->r_locked_dir;
 
                /* fill out a snapdir LOOKUPSNAP dentry */
                BUG_ON(!dn);
-               BUG_ON(!req->r_locked_dir);
-               BUG_ON(ceph_snap(req->r_locked_dir) != CEPH_SNAPDIR);
-               ininfo = rinfo->targeti.in;
-               vino.ino = le64_to_cpu(ininfo->ino);
-               vino.snap = le64_to_cpu(ininfo->snapid);
+               BUG_ON(!dir);
+               BUG_ON(ceph_snap(dir) != CEPH_SNAPDIR);
                dout(" linking snapped dir %p to dn %p\n", in, dn);
+               ceph_dir_clear_complete(dir);
                ihold(in);
-               dn = splice_dentry(dn, in, NULL, true);
+               dn = splice_dentry(dn, in, NULL);
                if (IS_ERR(dn)) {
                        err = PTR_ERR(dn);
                        goto done;
@@ -1407,7 +1368,7 @@ retry_lookup:
                }
 
                if (!dn->d_inode) {
-                       dn = splice_dentry(dn, in, NULL, false);
+                       dn = splice_dentry(dn, in, NULL);
                        if (IS_ERR(dn)) {
                                err = PTR_ERR(dn);
                                dn = NULL;
index fdf941b44ff103a2590a3804aa850e468ec980d6..a822a6e58290bbedfb0e363bf3bbb601075891fb 100644 (file)
@@ -109,6 +109,8 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
                return PTR_ERR(req);
        req->r_inode = inode;
        ihold(inode);
+       req->r_num_caps = 1;
+
        req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
 
        req->r_args.setlayout.layout.fl_stripe_unit =
@@ -153,6 +155,7 @@ static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
                return PTR_ERR(req);
        req->r_inode = inode;
        ihold(inode);
+       req->r_num_caps = 1;
 
        req->r_args.setlayout.layout.fl_stripe_unit =
                        cpu_to_le32(l.stripe_unit);
index d94ba0df9f4d195cabf677fcdcd41cc01096c7e7..fbc39c47bacd17150581e2741531c610e5e89f56 100644 (file)
@@ -45,6 +45,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
                return PTR_ERR(req);
        req->r_inode = inode;
        ihold(inode);
+       req->r_num_caps = 1;
 
        /* mds requires start and length rather than start and end */
        if (LLONG_MAX == fl->fl_end)
@@ -52,10 +53,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        else
                length = fl->fl_end - fl->fl_start + 1;
 
-       if (lock_type == CEPH_LOCK_FCNTL)
-               owner = secure_addr(fl->fl_owner);
-       else
-               owner = secure_addr(fl->fl_file);
+       owner = secure_addr(fl->fl_owner);
 
        dout("ceph_lock_message: rule: %d, op: %d, owner: %llx, pid: %llu, "
             "start: %llu, length: %llu, wait: %d, type: %d", (int)lock_type,
@@ -313,10 +311,7 @@ int lock_to_ceph_filelock(struct file_lock *lock,
        cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
        cephlock->client = cpu_to_le64(0);
        cephlock->pid = cpu_to_le64((u64)lock->fl_pid);
-       if (lock->fl_flags & FL_POSIX)
-               cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner));
-       else
-               cephlock->owner = cpu_to_le64(secure_addr(lock->fl_file));
+       cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner));
 
        switch (lock->fl_type) {
        case F_RDLCK:
index 7866cd05a6bbee4afd2478f3737d0ccd8ac28975..ead05cc1f447562271578131ab25769257080915 100644 (file)
@@ -266,7 +266,6 @@ struct ceph_inode_info {
        struct timespec i_rctime;
        u64 i_rbytes, i_rfiles, i_rsubdirs;
        u64 i_files, i_subdirs;
-       u64 i_max_offset;  /* largest readdir offset, set with complete dir */
 
        struct rb_root i_fragtree;
        struct mutex i_fragtree_mutex;
index 5be1f997ecdeffe74f4d4e6e6fb3903a73f6c13d..496b520934e01adafd7a9a1d2ae90549ca008433 100644 (file)
@@ -733,8 +733,7 @@ out_nls:
        goto out;
 }
 
-static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                                  unsigned long nr_segs, loff_t pos)
+static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        struct cifsInodeInfo *cinode = CIFS_I(inode);
@@ -745,14 +744,14 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (written)
                return written;
 
-       written = generic_file_aio_write(iocb, iov, nr_segs, pos);
+       written = generic_file_write_iter(iocb, from);
 
        if (CIFS_CACHE_WRITE(CIFS_I(inode)))
                goto out;
 
        rc = filemap_fdatawrite(inode->i_mapping);
        if (rc)
-               cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n",
+               cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n",
                         rc, inode);
 
 out:
@@ -888,10 +887,10 @@ const struct inode_operations cifs_symlink_inode_ops = {
 };
 
 const struct file_operations cifs_file_ops = {
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = generic_file_aio_read,
-       .aio_write = cifs_file_aio_write,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = generic_file_read_iter,
+       .write_iter = cifs_file_write_iter,
        .open = cifs_open,
        .release = cifs_close,
        .lock = cifs_lock,
@@ -907,10 +906,10 @@ const struct file_operations cifs_file_ops = {
 };
 
 const struct file_operations cifs_file_strict_ops = {
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = cifs_strict_readv,
-       .aio_write = cifs_strict_writev,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = cifs_strict_readv,
+       .write_iter = cifs_strict_writev,
        .open = cifs_open,
        .release = cifs_close,
        .lock = cifs_lock,
@@ -927,10 +926,10 @@ const struct file_operations cifs_file_strict_ops = {
 
 const struct file_operations cifs_file_direct_ops = {
        /* BB reevaluate whether they can be done with directio, no cache */
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = cifs_user_readv,
-       .aio_write = cifs_user_writev,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = cifs_user_readv,
+       .write_iter = cifs_user_writev,
        .open = cifs_open,
        .release = cifs_close,
        .lock = cifs_lock,
@@ -946,10 +945,10 @@ const struct file_operations cifs_file_direct_ops = {
 };
 
 const struct file_operations cifs_file_nobrl_ops = {
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = generic_file_aio_read,
-       .aio_write = cifs_file_aio_write,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = generic_file_read_iter,
+       .write_iter = cifs_file_write_iter,
        .open = cifs_open,
        .release = cifs_close,
        .fsync = cifs_fsync,
@@ -964,10 +963,10 @@ const struct file_operations cifs_file_nobrl_ops = {
 };
 
 const struct file_operations cifs_file_strict_nobrl_ops = {
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = cifs_strict_readv,
-       .aio_write = cifs_strict_writev,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = cifs_strict_readv,
+       .write_iter = cifs_strict_writev,
        .open = cifs_open,
        .release = cifs_close,
        .fsync = cifs_strict_fsync,
@@ -983,10 +982,10 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
 
 const struct file_operations cifs_file_direct_nobrl_ops = {
        /* BB reevaluate whether they can be done with directio, no cache */
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = cifs_user_readv,
-       .aio_write = cifs_user_writev,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = cifs_user_readv,
+       .write_iter = cifs_user_writev,
        .open = cifs_open,
        .release = cifs_close,
        .fsync = cifs_fsync,
index 26a754f49ba1933259c0711d1e37ece069b3030c..c9e91886f0cfd08d108662d60d3d38fdf26c11f9 100644 (file)
@@ -85,14 +85,10 @@ extern const struct file_operations cifs_file_strict_nobrl_ops;
 extern int cifs_open(struct inode *inode, struct file *file);
 extern int cifs_close(struct inode *inode, struct file *file);
 extern int cifs_closedir(struct inode *inode, struct file *file);
-extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t pos);
-extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
-                                unsigned long nr_segs, loff_t pos);
-extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos);
-extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
-                                 unsigned long nr_segs, loff_t pos);
+extern ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to);
+extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
+extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
+extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
 extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, loff_t, loff_t, int);
 extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int);
index 5ed03e0b8b40e28b10aa46630d973b47e229c194..60e9b5fa22128fc7a127a5859f0c6070aae09c36 100644 (file)
@@ -2385,14 +2385,12 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
 }
 
 static ssize_t
-cifs_iovec_write(struct file *file, const struct iovec *iov,
-                unsigned long nr_segs, loff_t *poffset)
+cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset)
 {
        unsigned long nr_pages, i;
        size_t bytes, copied, len, cur_len;
        ssize_t total_written = 0;
        loff_t offset;
-       struct iov_iter it;
        struct cifsFileInfo *open_file;
        struct cifs_tcon *tcon;
        struct cifs_sb_info *cifs_sb;
@@ -2401,14 +2399,16 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
        int rc;
        pid_t pid;
 
-       len = iov_length(iov, nr_segs);
-       if (!len)
-               return 0;
-
+       len = iov_iter_count(from);
        rc = generic_write_checks(file, poffset, &len, 0);
        if (rc)
                return rc;
 
+       if (!len)
+               return 0;
+
+       iov_iter_truncate(from, len);
+
        INIT_LIST_HEAD(&wdata_list);
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        open_file = file->private_data;
@@ -2424,7 +2424,6 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
        else
                pid = current->tgid;
 
-       iov_iter_init(&it, iov, nr_segs, len, 0);
        do {
                size_t save_len;
 
@@ -2444,11 +2443,10 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
 
                save_len = cur_len;
                for (i = 0; i < nr_pages; i++) {
-                       bytes = min_t(const size_t, cur_len, PAGE_SIZE);
-                       copied = iov_iter_copy_from_user(wdata->pages[i], &it,
-                                                        0, bytes);
+                       bytes = min_t(size_t, cur_len, PAGE_SIZE);
+                       copied = copy_page_from_iter(wdata->pages[i], 0, bytes,
+                                                    from);
                        cur_len -= copied;
-                       iov_iter_advance(&it, copied);
                        /*
                         * If we didn't copy as much as we expected, then that
                         * may mean we trod into an unmapped area. Stop copying
@@ -2546,11 +2544,11 @@ restart_loop:
        return total_written ? total_written : (ssize_t)rc;
 }
 
-ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos)
+ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from)
 {
        ssize_t written;
        struct inode *inode;
+       loff_t pos = iocb->ki_pos;
 
        inode = file_inode(iocb->ki_filp);
 
@@ -2560,7 +2558,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
         * write request.
         */
 
-       written = cifs_iovec_write(iocb->ki_filp, iov, nr_segs, &pos);
+       written = cifs_iovec_write(iocb->ki_filp, from, &pos);
        if (written > 0) {
                CIFS_I(inode)->invalid_mapping = true;
                iocb->ki_pos = pos;
@@ -2570,8 +2568,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
 }
 
 static ssize_t
-cifs_writev(struct kiocb *iocb, const struct iovec *iov,
-           unsigned long nr_segs, loff_t pos)
+cifs_writev(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
@@ -2589,10 +2586,10 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
        mutex_lock(&inode->i_mutex);
        if (file->f_flags & O_APPEND)
                lock_pos = i_size_read(inode);
-       if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
+       if (!cifs_find_lock_conflict(cfile, lock_pos, iov_iter_count(from),
                                     server->vals->exclusive_lock_type, NULL,
                                     CIFS_WRITE_OP)) {
-               rc = __generic_file_aio_write(iocb, iov, nr_segs);
+               rc = __generic_file_write_iter(iocb, from);
                mutex_unlock(&inode->i_mutex);
 
                if (rc > 0) {
@@ -2610,8 +2607,7 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
 }
 
 ssize_t
-cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
-                  unsigned long nr_segs, loff_t pos)
+cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        struct cifsInodeInfo *cinode = CIFS_I(inode);
@@ -2629,11 +2625,10 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
                if (cap_unix(tcon->ses) &&
                (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
                  && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) {
-                       written = generic_file_aio_write(
-                                       iocb, iov, nr_segs, pos);
+                       written = generic_file_write_iter(iocb, from);
                        goto out;
                }
-               written = cifs_writev(iocb, iov, nr_segs, pos);
+               written = cifs_writev(iocb, from);
                goto out;
        }
        /*
@@ -2642,7 +2637,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
         * affected pages because it may cause a error with mandatory locks on
         * these pages but not on the region from pos to ppos+len-1.
         */
-       written = cifs_user_writev(iocb, iov, nr_segs, pos);
+       written = cifs_user_writev(iocb, from);
        if (written > 0 && CIFS_CACHE_READ(cinode)) {
                /*
                 * Windows 7 server can delay breaking level2 oplock if a write
@@ -2831,32 +2826,25 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
        return total_read > 0 ? total_read : result;
 }
 
-ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t pos)
+ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to)
 {
        struct file *file = iocb->ki_filp;
        ssize_t rc;
        size_t len, cur_len;
        ssize_t total_read = 0;
-       loff_t offset = pos;
+       loff_t offset = iocb->ki_pos;
        unsigned int npages;
        struct cifs_sb_info *cifs_sb;
        struct cifs_tcon *tcon;
        struct cifsFileInfo *open_file;
        struct cifs_readdata *rdata, *tmp;
        struct list_head rdata_list;
-       struct iov_iter to;
        pid_t pid;
 
-       if (!nr_segs)
-               return 0;
-
-       len = iov_length(iov, nr_segs);
+       len = iov_iter_count(to);
        if (!len)
                return 0;
 
-       iov_iter_init(&to, iov, nr_segs, len, 0);
-
        INIT_LIST_HEAD(&rdata_list);
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        open_file = file->private_data;
@@ -2914,7 +2902,7 @@ error:
        if (!list_empty(&rdata_list))
                rc = 0;
 
-       len = iov_iter_count(&to);
+       len = iov_iter_count(to);
        /* the loop below should proceed in the order of increasing offsets */
        list_for_each_entry_safe(rdata, tmp, &rdata_list, list) {
        again:
@@ -2931,7 +2919,7 @@ error:
                                        goto again;
                                }
                        } else {
-                               rc = cifs_readdata_to_iov(rdata, &to);
+                               rc = cifs_readdata_to_iov(rdata, to);
                        }
 
                }
@@ -2939,7 +2927,7 @@ error:
                kref_put(&rdata->refcount, cifs_uncached_readdata_release);
        }
 
-       total_read = len - iov_iter_count(&to);
+       total_read = len - iov_iter_count(to);
 
        cifs_stats_bytes_read(tcon, total_read);
 
@@ -2948,15 +2936,14 @@ error:
                rc = 0;
 
        if (total_read) {
-               iocb->ki_pos = pos + total_read;
+               iocb->ki_pos += total_read;
                return total_read;
        }
        return rc;
 }
 
 ssize_t
-cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
-                 unsigned long nr_segs, loff_t pos)
+cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        struct cifsInodeInfo *cinode = CIFS_I(inode);
@@ -2975,22 +2962,22 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
         * pos+len-1.
         */
        if (!CIFS_CACHE_READ(cinode))
-               return cifs_user_readv(iocb, iov, nr_segs, pos);
+               return cifs_user_readv(iocb, to);
 
        if (cap_unix(tcon->ses) &&
            (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
            ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
-               return generic_file_aio_read(iocb, iov, nr_segs, pos);
+               return generic_file_read_iter(iocb, to);
 
        /*
         * We need to hold the sem to be sure nobody modifies lock list
         * with a brlock that prevents reading.
         */
        down_read(&cinode->lock_sem);
-       if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+       if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to),
                                     tcon->ses->server->vals->shared_lock_type,
                                     NULL, CIFS_READ_OP))
-               rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
+               rc = generic_file_read_iter(iocb, to);
        up_read(&cinode->lock_sem);
        return rc;
 }
@@ -3703,8 +3690,8 @@ void cifs_oplock_break(struct work_struct *work)
  * Direct IO is not yet supported in the cached mode. 
  */
 static ssize_t
-cifs_direct_io(int rw, struct kiocb *iocb, const struct iovec *iov,
-               loff_t pos, unsigned long nr_segs)
+cifs_direct_io(int rw, struct kiocb *iocb, struct iov_iter *iter,
+               loff_t pos)
 {
         /*
          * FIXME
index aadc2b68678b7d70c0381d10c847c86624589c4c..a22d667f1069e5eb8485d121f241725de732b8a9 100644 (file)
@@ -1737,6 +1737,9 @@ cifs_inode_needs_reval(struct inode *inode)
        if (cifs_i->time == 0)
                return true;
 
+       if (!cifs_sb->actimeo)
+               return true;
+
        if (!time_in_range(jiffies, cifs_i->time,
                                cifs_i->time + cifs_sb->actimeo))
                return true;
index 31ba0935e32ed2f271253a1d828778a91193b211..98040ba388ac1e2db62f96f253bc141758013b10 100644 (file)
@@ -77,7 +77,6 @@ struct dio_submit {
        unsigned blocks_available;      /* At block_in_file.  changes */
        int reap_counter;               /* rate limit reaping */
        sector_t final_block_in_request;/* doesn't change */
-       unsigned first_block_in_page;   /* doesn't change, Used only once */
        int boundary;                   /* prev block is at a boundary */
        get_block_t *get_block;         /* block mapping function */
        dio_submit_t *submit_io;        /* IO submition function */
@@ -98,19 +97,14 @@ struct dio_submit {
        sector_t cur_page_block;        /* Where it starts */
        loff_t cur_page_fs_offset;      /* Offset in file */
 
-       /*
-        * Page fetching state. These variables belong to dio_refill_pages().
-        */
-       int curr_page;                  /* changes */
-       int total_pages;                /* doesn't change */
-       unsigned long curr_user_address;/* changes */
-
+       struct iov_iter *iter;
        /*
         * Page queue.  These variables belong to dio_refill_pages() and
         * dio_get_page().
         */
        unsigned head;                  /* next page to process */
        unsigned tail;                  /* last valid page + 1 */
+       size_t from, to;
 };
 
 /* dio_state communicated between submission path and end_io */
@@ -163,15 +157,10 @@ static inline unsigned dio_pages_present(struct dio_submit *sdio)
  */
 static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio)
 {
-       int ret;
-       int nr_pages;
+       ssize_t ret;
 
-       nr_pages = min(sdio->total_pages - sdio->curr_page, DIO_PAGES);
-       ret = get_user_pages_fast(
-               sdio->curr_user_address,                /* Where from? */
-               nr_pages,                       /* How many pages? */
-               dio->rw == READ,                /* Write to memory? */
-               &dio->pages[0]);                /* Put results here */
+       ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES * PAGE_SIZE,
+                               &sdio->from);
 
        if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) {
                struct page *page = ZERO_PAGE(0);
@@ -186,18 +175,19 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio)
                dio->pages[0] = page;
                sdio->head = 0;
                sdio->tail = 1;
-               ret = 0;
-               goto out;
+               sdio->from = 0;
+               sdio->to = PAGE_SIZE;
+               return 0;
        }
 
        if (ret >= 0) {
-               sdio->curr_user_address += ret * PAGE_SIZE;
-               sdio->curr_page += ret;
+               iov_iter_advance(sdio->iter, ret);
+               ret += sdio->from;
                sdio->head = 0;
-               sdio->tail = ret;
-               ret = 0;
+               sdio->tail = (ret + PAGE_SIZE - 1) / PAGE_SIZE;
+               sdio->to = ((ret - 1) & (PAGE_SIZE - 1)) + 1;
+               return 0;
        }
-out:
        return ret;     
 }
 
@@ -208,8 +198,9 @@ out:
  * L1 cache.
  */
 static inline struct page *dio_get_page(struct dio *dio,
-               struct dio_submit *sdio)
+               struct dio_submit *sdio, size_t *from, size_t *to)
 {
+       int n;
        if (dio_pages_present(sdio) == 0) {
                int ret;
 
@@ -218,7 +209,10 @@ static inline struct page *dio_get_page(struct dio *dio,
                        return ERR_PTR(ret);
                BUG_ON(dio_pages_present(sdio) == 0);
        }
-       return dio->pages[sdio->head++];
+       n = sdio->head++;
+       *from = n ? 0 : sdio->from;
+       *to = (n == sdio->tail - 1) ? sdio->to : PAGE_SIZE;
+       return dio->pages[n];
 }
 
 /**
@@ -422,8 +416,8 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
  */
 static inline void dio_cleanup(struct dio *dio, struct dio_submit *sdio)
 {
-       while (dio_pages_present(sdio))
-               page_cache_release(dio_get_page(dio, sdio));
+       while (sdio->head < sdio->tail)
+               page_cache_release(dio->pages[sdio->head++]);
 }
 
 /*
@@ -912,23 +906,18 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio,
                        struct buffer_head *map_bh)
 {
        const unsigned blkbits = sdio->blkbits;
-       const unsigned blocks_per_page = PAGE_SIZE >> blkbits;
-       struct page *page;
-       unsigned block_in_page;
        int ret = 0;
 
-       /* The I/O can start at any block offset within the first page */
-       block_in_page = sdio->first_block_in_page;
-
        while (sdio->block_in_file < sdio->final_block_in_request) {
-               page = dio_get_page(dio, sdio);
+               struct page *page;
+               size_t from, to;
+               page = dio_get_page(dio, sdio, &from, &to);
                if (IS_ERR(page)) {
                        ret = PTR_ERR(page);
                        goto out;
                }
 
-               while (block_in_page < blocks_per_page) {
-                       unsigned offset_in_page = block_in_page << blkbits;
+               while (from < to) {
                        unsigned this_chunk_bytes;      /* # of bytes mapped */
                        unsigned this_chunk_blocks;     /* # of blocks */
                        unsigned u;
@@ -999,10 +988,10 @@ do_holes:
                                        page_cache_release(page);
                                        goto out;
                                }
-                               zero_user(page, block_in_page << blkbits,
-                                               1 << blkbits);
+                               zero_user(page, from, 1 << blkbits);
                                sdio->block_in_file++;
-                               block_in_page++;
+                               from += 1 << blkbits;
+                               dio->result += 1 << blkbits;
                                goto next_block;
                        }
 
@@ -1019,7 +1008,7 @@ do_holes:
                         * can add to this page
                         */
                        this_chunk_blocks = sdio->blocks_available;
-                       u = (PAGE_SIZE - offset_in_page) >> blkbits;
+                       u = (to - from) >> blkbits;
                        if (this_chunk_blocks > u)
                                this_chunk_blocks = u;
                        u = sdio->final_block_in_request - sdio->block_in_file;
@@ -1031,7 +1020,7 @@ do_holes:
                        if (this_chunk_blocks == sdio->blocks_available)
                                sdio->boundary = buffer_boundary(map_bh);
                        ret = submit_page_section(dio, sdio, page,
-                                                 offset_in_page,
+                                                 from,
                                                  this_chunk_bytes,
                                                  sdio->next_block_for_io,
                                                  map_bh);
@@ -1042,7 +1031,8 @@ do_holes:
                        sdio->next_block_for_io += this_chunk_blocks;
 
                        sdio->block_in_file += this_chunk_blocks;
-                       block_in_page += this_chunk_blocks;
+                       from += this_chunk_bytes;
+                       dio->result += this_chunk_bytes;
                        sdio->blocks_available -= this_chunk_blocks;
 next_block:
                        BUG_ON(sdio->block_in_file > sdio->final_block_in_request);
@@ -1052,7 +1042,6 @@ next_block:
 
                /* Drop the ref which was taken in get_user_pages() */
                page_cache_release(page);
-               block_in_page = 0;
        }
 out:
        return ret;
@@ -1107,24 +1096,20 @@ static inline int drop_refcount(struct dio *dio)
  */
 static inline ssize_t
 do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
-       struct block_device *bdev, const struct iovec *iov, loff_t offset, 
-       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       struct block_device *bdev, struct iov_iter *iter, loff_t offset, 
+       get_block_t get_block, dio_iodone_t end_io,
        dio_submit_t submit_io, int flags)
 {
-       int seg;
-       size_t size;
-       unsigned long addr;
        unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits);
        unsigned blkbits = i_blkbits;
        unsigned blocksize_mask = (1 << blkbits) - 1;
        ssize_t retval = -EINVAL;
-       loff_t end = offset;
+       loff_t end = offset + iov_iter_count(iter);
        struct dio *dio;
        struct dio_submit sdio = { 0, };
-       unsigned long user_addr;
-       size_t bytes;
        struct buffer_head map_bh = { 0, };
        struct blk_plug plug;
+       unsigned long align = offset | iov_iter_alignment(iter);
 
        if (rw & WRITE)
                rw = WRITE_ODIRECT;
@@ -1134,32 +1119,16 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
         * the early prefetch in the caller enough time.
         */
 
-       if (offset & blocksize_mask) {
+       if (align & blocksize_mask) {
                if (bdev)
                        blkbits = blksize_bits(bdev_logical_block_size(bdev));
                blocksize_mask = (1 << blkbits) - 1;
-               if (offset & blocksize_mask)
+               if (align & blocksize_mask)
                        goto out;
        }
 
-       /* Check the memory alignment.  Blocks cannot straddle pages */
-       for (seg = 0; seg < nr_segs; seg++) {
-               addr = (unsigned long)iov[seg].iov_base;
-               size = iov[seg].iov_len;
-               end += size;
-               if (unlikely((addr & blocksize_mask) ||
-                            (size & blocksize_mask))) {
-                       if (bdev)
-                               blkbits = blksize_bits(
-                                        bdev_logical_block_size(bdev));
-                       blocksize_mask = (1 << blkbits) - 1;
-                       if ((addr & blocksize_mask) || (size & blocksize_mask))
-                               goto out;
-               }
-       }
-
        /* watch out for a 0 len io from a tricksy fs */
-       if (rw == READ && end == offset)
+       if (rw == READ && !iov_iter_count(iter))
                return 0;
 
        dio = kmem_cache_alloc(dio_cache, GFP_KERNEL);
@@ -1249,6 +1218,10 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        spin_lock_init(&dio->bio_lock);
        dio->refcount = 1;
 
+       sdio.iter = iter;
+       sdio.final_block_in_request =
+               (offset + iov_iter_count(iter)) >> blkbits;
+
        /*
         * In case of non-aligned buffers, we may need 2 more
         * pages since we need to zero out first and last block.
@@ -1256,47 +1229,13 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        if (unlikely(sdio.blkfactor))
                sdio.pages_in_io = 2;
 
-       for (seg = 0; seg < nr_segs; seg++) {
-               user_addr = (unsigned long)iov[seg].iov_base;
-               sdio.pages_in_io +=
-                       ((user_addr + iov[seg].iov_len + PAGE_SIZE-1) /
-                               PAGE_SIZE - user_addr / PAGE_SIZE);
-       }
+       sdio.pages_in_io += iov_iter_npages(iter, INT_MAX);
 
        blk_start_plug(&plug);
 
-       for (seg = 0; seg < nr_segs; seg++) {
-               user_addr = (unsigned long)iov[seg].iov_base;
-               sdio.size += bytes = iov[seg].iov_len;
-
-               /* Index into the first page of the first block */
-               sdio.first_block_in_page = (user_addr & ~PAGE_MASK) >> blkbits;
-               sdio.final_block_in_request = sdio.block_in_file +
-                                               (bytes >> blkbits);
-               /* Page fetching state */
-               sdio.head = 0;
-               sdio.tail = 0;
-               sdio.curr_page = 0;
-
-               sdio.total_pages = 0;
-               if (user_addr & (PAGE_SIZE-1)) {
-                       sdio.total_pages++;
-                       bytes -= PAGE_SIZE - (user_addr & (PAGE_SIZE - 1));
-               }
-               sdio.total_pages += (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
-               sdio.curr_user_address = user_addr;
-
-               retval = do_direct_IO(dio, &sdio, &map_bh);
-
-               dio->result += iov[seg].iov_len -
-                       ((sdio.final_block_in_request - sdio.block_in_file) <<
-                                       blkbits);
-
-               if (retval) {
-                       dio_cleanup(dio, &sdio);
-                       break;
-               }
-       } /* end iovec loop */
+       retval = do_direct_IO(dio, &sdio, &map_bh);
+       if (retval)
+               dio_cleanup(dio, &sdio);
 
        if (retval == -ENOTBLK) {
                /*
@@ -1365,8 +1304,8 @@ out:
 
 ssize_t
 __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
-       struct block_device *bdev, const struct iovec *iov, loff_t offset,
-       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       struct block_device *bdev, struct iov_iter *iter, loff_t offset,
+       get_block_t get_block, dio_iodone_t end_io,
        dio_submit_t submit_io, int flags)
 {
        /*
@@ -1381,9 +1320,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        prefetch(bdev->bd_queue);
        prefetch((char *)bdev->bd_queue + SMP_CACHE_BYTES);
 
-       return do_blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-                                    nr_segs, get_block, end_io,
-                                    submit_io, flags);
+       return do_blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset,
+                                    get_block, end_io, submit_io, flags);
 }
 
 EXPORT_SYMBOL(__blockdev_direct_IO);
index b1eaa7a1f82cd0ce03ebb0bad15c2d8f5b6f6e9c..b4b6ab9873ae420a61cf800224253f7f91a62653 100644 (file)
  * The function to be used for directory reads is ecryptfs_read.
  */
 static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
-                               const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos)
+                               struct iov_iter *to)
 {
        ssize_t rc;
        struct path *path;
        struct file *file = iocb->ki_filp;
 
-       rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
+       rc = generic_file_read_iter(iocb, to);
        /*
         * Even though this is a async interface, we need to wait
         * for IO to finish to update atime
@@ -230,8 +229,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       ecryptfs_dentry->d_name.name, rc);
+                       "[%pd]; rc = [%d]\n", __func__,
+                       ecryptfs_dentry, rc);
                goto out_free;
        }
        if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
@@ -352,10 +351,10 @@ const struct file_operations ecryptfs_dir_fops = {
 
 const struct file_operations ecryptfs_main_fops = {
        .llseek = generic_file_llseek,
-       .read = do_sync_read,
-       .aio_read = ecryptfs_read_update_atime,
-       .write = do_sync_write,
-       .aio_write = generic_file_aio_write,
+       .read = new_sync_read,
+       .read_iter = ecryptfs_read_update_atime,
+       .write = new_sync_write,
+       .write_iter = generic_file_write_iter,
        .iterate = ecryptfs_readdir,
        .unlocked_ioctl = ecryptfs_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
index d4a9431ec73ce0cb215fc3b6e52727b4059f9528..4d6c7e48828d5eab09ce2c06816089666319f40e 100644 (file)
@@ -250,8 +250,8 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       ecryptfs_dentry->d_name.name, rc);
+                       "[%pd]; rc = [%d]\n", __func__,
+                       ecryptfs_dentry, rc);
                goto out;
        }
        rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode);
@@ -313,8 +313,8 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode)
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       dentry->d_name.name, rc);
+                       "[%pd]; rc = [%d]\n", __func__,
+                       dentry, rc);
                return rc;
        }
 
@@ -418,8 +418,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
                ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
-                               "[%d] on lower_dentry = [%s]\n", __func__, rc,
-                               ecryptfs_dentry->d_name.name);
+                               "[%d] on lower_dentry = [%pd]\n", __func__, rc,
+                               ecryptfs_dentry);
                goto out;
        }
        if (lower_dentry->d_inode)
index 491c6c078e7f5e0ac420646288452d93cca86ce2..71bf8e4fb5d427c660e9913a57054dec59f99dfc 100644 (file)
@@ -67,17 +67,17 @@ static int exofs_flush(struct file *file, fl_owner_t id)
 
 const struct file_operations exofs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .open           = generic_file_open,
        .release        = exofs_release_file,
        .fsync          = exofs_file_fsync,
        .flush          = exofs_flush,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
 };
 
 const struct inode_operations exofs_file_inode_operations = {
index d1c244d676679c8d087bafeada190ce268a02c6e..3f9cafd739312bd1392b21bc6ed3dc6bb9b666a1 100644 (file)
@@ -964,7 +964,7 @@ static void exofs_invalidatepage(struct page *page, unsigned int offset,
 
  /* TODO: Should be easy enough to do proprly */
 static ssize_t exofs_direct_IO(int rw, struct kiocb *iocb,
-               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+               struct iov_iter *iter, loff_t offset)
 {
        return 0;
 }
index 44c36e5907655982cc10e26b822cc1061312fbd1..7c87b22a7228c4ce9ed3c915c64283e2aa72a328 100644 (file)
@@ -62,10 +62,10 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
  */
 const struct file_operations ext2_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
@@ -75,7 +75,7 @@ const struct file_operations ext2_file_operations = {
        .release        = ext2_release_file,
        .fsync          = ext2_fsync,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
 };
 
 #ifdef CONFIG_EXT2_FS_XIP
index b1d2a4675d4280e10ff10f9f89ffaa25d109d920..36d35c36311d69a025c5b804e8d8597cbd9cb2b2 100644 (file)
@@ -850,18 +850,18 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
 }
 
 static ssize_t
-ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
-                       loff_t offset, unsigned long nr_segs)
+ext2_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
+                       loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                ext2_get_block);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, ext2_get_block);
        if (ret < 0 && (rw & WRITE))
-               ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
+               ext2_write_failed(mapping, offset + count);
        return ret;
 }
 
index aad05311392a046f3df724102580c511185c0fa2..a062fa1e1b113e56e7545bb4c6bac7ac1bf7d741 100644 (file)
@@ -50,10 +50,10 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
 
 const struct file_operations ext3_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .unlocked_ioctl = ext3_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext3_compat_ioctl,
@@ -63,7 +63,7 @@ const struct file_operations ext3_file_operations = {
        .release        = ext3_release_file,
        .fsync          = ext3_sync_file,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
 };
 
 const struct inode_operations ext3_file_inode_operations = {
index f5157d0d1b43772e95aace234b4ee50fca9ade3b..4d32133a76c4bbfd0393528f8ad463bf239bf354 100644 (file)
@@ -1820,8 +1820,7 @@ static int ext3_releasepage(struct page *page, gfp_t wait)
  * VFS code falls back into buffered path in that case so we are safe.
  */
 static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
-                       const struct iovec *iov, loff_t offset,
-                       unsigned long nr_segs)
+                       struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
@@ -1829,10 +1828,10 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
        handle_t *handle;
        ssize_t ret;
        int orphan = 0;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        int retries = 0;
 
-       trace_ext3_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw);
+       trace_ext3_direct_IO_enter(inode, offset, count, rw);
 
        if (rw == WRITE) {
                loff_t final_size = offset + count;
@@ -1856,15 +1855,14 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
        }
 
 retry:
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                ext3_get_block);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, ext3_get_block);
        /*
         * In case of error extending write may have instantiated a few
         * blocks outside i_size. Trim these off again.
         */
        if (unlikely((rw & WRITE) && ret < 0)) {
                loff_t isize = i_size_read(inode);
-               loff_t end = offset + iov_length(iov, nr_segs);
+               loff_t end = offset + count;
 
                if (end > isize)
                        ext3_truncate_failed_direct_write(inode);
@@ -1909,8 +1907,7 @@ retry:
                        ret = err;
        }
 out:
-       trace_ext3_direct_IO_exit(inode, offset,
-                               iov_length(iov, nr_segs), rw, ret);
+       trace_ext3_direct_IO_exit(inode, offset, count, rw, ret);
        return ret;
 }
 
index 66946aa621270716c580a2617bceecbcadb6bda7..6b45afa4961003ea1e1e17a0ebb16bbade9f262f 100644 (file)
@@ -158,7 +158,6 @@ struct ext4_allocation_request {
 #define EXT4_MAP_MAPPED                (1 << BH_Mapped)
 #define EXT4_MAP_UNWRITTEN     (1 << BH_Unwritten)
 #define EXT4_MAP_BOUNDARY      (1 << BH_Boundary)
-#define EXT4_MAP_UNINIT                (1 << BH_Uninit)
 /* Sometimes (in the bigalloc case, from ext4_da_get_block_prep) the caller of
  * ext4_map_blocks wants to know whether or not the underlying cluster has
  * already been accounted for. EXT4_MAP_FROM_CLUSTER conveys to the caller that
@@ -169,7 +168,7 @@ struct ext4_allocation_request {
 #define EXT4_MAP_FROM_CLUSTER  (1 << BH_AllocFromCluster)
 #define EXT4_MAP_FLAGS         (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
                                 EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
-                                EXT4_MAP_UNINIT | EXT4_MAP_FROM_CLUSTER)
+                                EXT4_MAP_FROM_CLUSTER)
 
 struct ext4_map_blocks {
        ext4_fsblk_t m_pblk;
@@ -184,7 +183,7 @@ struct ext4_map_blocks {
 #define        EXT4_IO_END_UNWRITTEN   0x0001
 
 /*
- * For converting uninitialized extents on a work queue. 'handle' is used for
+ * For converting unwritten extents on a work queue. 'handle' is used for
  * buffered writeback.
  */
 typedef struct ext4_io_end {
@@ -537,26 +536,26 @@ enum {
 /*
  * Flags used by ext4_map_blocks()
  */
-       /* Allocate any needed blocks and/or convert an unitialized
+       /* Allocate any needed blocks and/or convert an unwritten
           extent to be an initialized ext4 */
 #define EXT4_GET_BLOCKS_CREATE                 0x0001
-       /* Request the creation of an unitialized extent */
-#define EXT4_GET_BLOCKS_UNINIT_EXT             0x0002
-#define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT      (EXT4_GET_BLOCKS_UNINIT_EXT|\
+       /* Request the creation of an unwritten extent */
+#define EXT4_GET_BLOCKS_UNWRIT_EXT             0x0002
+#define EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT      (EXT4_GET_BLOCKS_UNWRIT_EXT|\
                                                 EXT4_GET_BLOCKS_CREATE)
        /* Caller is from the delayed allocation writeout path
         * finally doing the actual allocation of delayed blocks */
 #define EXT4_GET_BLOCKS_DELALLOC_RESERVE       0x0004
        /* caller is from the direct IO path, request to creation of an
-       unitialized extents if not allocated, split the uninitialized
+       unwritten extents if not allocated, split the unwritten
        extent if blocks has been preallocated already*/
 #define EXT4_GET_BLOCKS_PRE_IO                 0x0008
 #define EXT4_GET_BLOCKS_CONVERT                        0x0010
 #define EXT4_GET_BLOCKS_IO_CREATE_EXT          (EXT4_GET_BLOCKS_PRE_IO|\
-                                        EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
+                                        EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
        /* Convert extent to initialized after IO complete */
 #define EXT4_GET_BLOCKS_IO_CONVERT_EXT         (EXT4_GET_BLOCKS_CONVERT|\
-                                        EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
+                                        EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
        /* Eventual metadata allocation (due to growing extent tree)
         * should not fail, so try to use reserved blocks for that.*/
 #define EXT4_GET_BLOCKS_METADATA_NOFAIL                0x0020
@@ -876,6 +875,8 @@ struct ext4_inode_info {
        struct inode vfs_inode;
        struct jbd2_inode *jinode;
 
+       spinlock_t i_raw_lock;  /* protects updates to the raw inode */
+
        /*
         * File creation time. Its function is same as that of
         * struct timespec i_{a,c,m}time in the generic inode.
@@ -2150,8 +2151,7 @@ extern void ext4_da_update_reserve_space(struct inode *inode,
 extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
                                struct ext4_map_blocks *map, int flags);
 extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
-                               const struct iovec *iov, loff_t offset,
-                               unsigned long nr_segs);
+                               struct iov_iter *iter, loff_t offset);
 extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
 extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks);
 extern void ext4_ind_truncate(handle_t *, struct inode *inode);
@@ -2784,10 +2784,9 @@ extern int ext4_mmp_csum_verify(struct super_block *sb,
  * See EXT4_MAP_... to see where this is used.
  */
 enum ext4_state_bits {
-       BH_Uninit       /* blocks are allocated but uninitialized on disk */
-        = BH_JBDPrivateStart,
-       BH_AllocFromCluster,    /* allocated blocks were part of already
+       BH_AllocFromCluster     /* allocated blocks were part of already
                                 * allocated cluster. */
+       = BH_JBDPrivateStart
 };
 
 /*
index 5074fe23f19e5a05544fb9d05095634ddcbe20a8..a867f5ca99919d05e2e6709f80f08566a33c435d 100644 (file)
@@ -137,21 +137,21 @@ struct ext4_ext_path {
  * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
  * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
  * MSB of ee_len field in the extent datastructure to signify if this
- * particular extent is an initialized extent or an uninitialized (i.e.
+ * particular extent is an initialized extent or an unwritten (i.e.
  * preallocated).
- * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
- * uninitialized extent.
+ * EXT_UNWRITTEN_MAX_LEN is the maximum number of blocks we can have in an
+ * unwritten extent.
  * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
- * uninitialized one. In other words, if MSB of ee_len is set, it is an
- * uninitialized extent with only one special scenario when ee_len = 0x8000.
- * In this case we can not have an uninitialized extent of zero length and
+ * unwritten one. In other words, if MSB of ee_len is set, it is an
+ * unwritten extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an unwritten extent of zero length and
  * thus we make it as a special case of initialized extent with 0x8000 length.
  * This way we get better extent-to-group alignment for initialized extents.
  * Hence, the maximum number of blocks we can have in an *initialized*
- * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ * extent is 2^15 (32768) and in an *unwritten* extent is 2^15-1 (32767).
  */
 #define EXT_INIT_MAX_LEN       (1UL << 15)
-#define EXT_UNINIT_MAX_LEN     (EXT_INIT_MAX_LEN - 1)
+#define EXT_UNWRITTEN_MAX_LEN  (EXT_INIT_MAX_LEN - 1)
 
 
 #define EXT_FIRST_EXTENT(__hdr__) \
@@ -187,14 +187,14 @@ static inline unsigned short ext_depth(struct inode *inode)
        return le16_to_cpu(ext_inode_hdr(inode)->eh_depth);
 }
 
-static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
+static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext)
 {
-       /* We can not have an uninitialized extent of zero length! */
+       /* We can not have an unwritten extent of zero length! */
        BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
        ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
 }
 
-static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
+static inline int ext4_ext_is_unwritten(struct ext4_extent *ext)
 {
        /* Extent with ee_len of 0x8000 is treated as an initialized extent */
        return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
index 01b0c208f62507e12f50ddd4fd3669972797f823..086baa9b5983f53a7c266f1630665b272ee082ee 100644 (file)
@@ -29,6 +29,7 @@
  *   - smart tree reduction
  */
 
+#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/time.h>
 #include <linux/jbd2.h>
@@ -50,8 +51,8 @@
  */
 #define EXT4_EXT_MAY_ZEROOUT   0x1  /* safe to zeroout if split fails \
                                        due to ENOSPC */
-#define EXT4_EXT_MARK_UNINIT1  0x2  /* mark first half uninitialized */
-#define EXT4_EXT_MARK_UNINIT2  0x4  /* mark second half uninitialized */
+#define EXT4_EXT_MARK_UNWRIT1  0x2  /* mark first half unwritten */
+#define EXT4_EXT_MARK_UNWRIT2  0x4  /* mark second half unwritten */
 
 #define EXT4_EXT_DATA_VALID1   0x8  /* first half contains valid data */
 #define EXT4_EXT_DATA_VALID2   0x10 /* second half contains valid data */
@@ -524,7 +525,7 @@ __read_extent_tree_block(const char *function, unsigned int line,
                                                     lblk - prev, ~0,
                                                     EXTENT_STATUS_HOLE);
 
-                       if (ext4_ext_is_uninitialized(ex))
+                       if (ext4_ext_is_unwritten(ex))
                                status = EXTENT_STATUS_UNWRITTEN;
                        ext4_es_cache_extent(inode, lblk, len,
                                             ext4_ext_pblock(ex), status);
@@ -620,7 +621,7 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
                } else if (path->p_ext) {
                        ext_debug("  %d:[%d]%d:%llu ",
                                  le32_to_cpu(path->p_ext->ee_block),
-                                 ext4_ext_is_uninitialized(path->p_ext),
+                                 ext4_ext_is_unwritten(path->p_ext),
                                  ext4_ext_get_actual_len(path->p_ext),
                                  ext4_ext_pblock(path->p_ext));
                } else
@@ -646,7 +647,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
 
        for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
                ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block),
-                         ext4_ext_is_uninitialized(ex),
+                         ext4_ext_is_unwritten(ex),
                          ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex));
        }
        ext_debug("\n");
@@ -677,7 +678,7 @@ static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path,
                ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
                                le32_to_cpu(ex->ee_block),
                                ext4_ext_pblock(ex),
-                               ext4_ext_is_uninitialized(ex),
+                               ext4_ext_is_unwritten(ex),
                                ext4_ext_get_actual_len(ex),
                                newblock);
                ex++;
@@ -802,7 +803,7 @@ ext4_ext_binsearch(struct inode *inode,
        ext_debug("  -> %d:%llu:[%d]%d ",
                        le32_to_cpu(path->p_ext->ee_block),
                        ext4_ext_pblock(path->p_ext),
-                       ext4_ext_is_uninitialized(path->p_ext),
+                       ext4_ext_is_unwritten(path->p_ext),
                        ext4_ext_get_actual_len(path->p_ext));
 
 #ifdef CHECK_BINSEARCH
@@ -1686,11 +1687,11 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
 
        /*
         * Make sure that both extents are initialized. We don't merge
-        * uninitialized extents so that we can be sure that end_io code has
+        * unwritten extents so that we can be sure that end_io code has
         * the extent that was written properly split out and conversion to
         * initialized is trivial.
         */
-       if (ext4_ext_is_uninitialized(ex1) != ext4_ext_is_uninitialized(ex2))
+       if (ext4_ext_is_unwritten(ex1) != ext4_ext_is_unwritten(ex2))
                return 0;
 
        ext1_ee_len = ext4_ext_get_actual_len(ex1);
@@ -1707,10 +1708,10 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
         */
        if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN)
                return 0;
-       if (ext4_ext_is_uninitialized(ex1) &&
+       if (ext4_ext_is_unwritten(ex1) &&
            (ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) ||
             atomic_read(&EXT4_I(inode)->i_unwritten) ||
-            (ext1_ee_len + ext2_ee_len > EXT_UNINIT_MAX_LEN)))
+            (ext1_ee_len + ext2_ee_len > EXT_UNWRITTEN_MAX_LEN)))
                return 0;
 #ifdef AGGRESSIVE_TEST
        if (ext1_ee_len >= 4)
@@ -1735,7 +1736,7 @@ static int ext4_ext_try_to_merge_right(struct inode *inode,
 {
        struct ext4_extent_header *eh;
        unsigned int depth, len;
-       int merge_done = 0, uninit;
+       int merge_done = 0, unwritten;
 
        depth = ext_depth(inode);
        BUG_ON(path[depth].p_hdr == NULL);
@@ -1745,11 +1746,11 @@ static int ext4_ext_try_to_merge_right(struct inode *inode,
                if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
                        break;
                /* merge with next extent! */
-               uninit = ext4_ext_is_uninitialized(ex);
+               unwritten = ext4_ext_is_unwritten(ex);
                ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
                                + ext4_ext_get_actual_len(ex + 1));
-               if (uninit)
-                       ext4_ext_mark_uninitialized(ex);
+               if (unwritten)
+                       ext4_ext_mark_unwritten(ex);
 
                if (ex + 1 < EXT_LAST_EXTENT(eh)) {
                        len = (EXT_LAST_EXTENT(eh) - ex - 1)
@@ -1903,7 +1904,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        struct ext4_ext_path *npath = NULL;
        int depth, len, err;
        ext4_lblk_t next;
-       int mb_flags = 0, uninit;
+       int mb_flags = 0, unwritten;
 
        if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
                EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
@@ -1943,21 +1944,21 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
                if (ext4_can_extents_be_merged(inode, ex, newext)) {
                        ext_debug("append [%d]%d block to %u:[%d]%d"
                                  "(from %llu)\n",
-                                 ext4_ext_is_uninitialized(newext),
+                                 ext4_ext_is_unwritten(newext),
                                  ext4_ext_get_actual_len(newext),
                                  le32_to_cpu(ex->ee_block),
-                                 ext4_ext_is_uninitialized(ex),
+                                 ext4_ext_is_unwritten(ex),
                                  ext4_ext_get_actual_len(ex),
                                  ext4_ext_pblock(ex));
                        err = ext4_ext_get_access(handle, inode,
                                                  path + depth);
                        if (err)
                                return err;
-                       uninit = ext4_ext_is_uninitialized(ex);
+                       unwritten = ext4_ext_is_unwritten(ex);
                        ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
                                        + ext4_ext_get_actual_len(newext));
-                       if (uninit)
-                               ext4_ext_mark_uninitialized(ex);
+                       if (unwritten)
+                               ext4_ext_mark_unwritten(ex);
                        eh = path[depth].p_hdr;
                        nearex = ex;
                        goto merge;
@@ -1969,10 +1970,10 @@ prepend:
                        ext_debug("prepend %u[%d]%d block to %u:[%d]%d"
                                  "(from %llu)\n",
                                  le32_to_cpu(newext->ee_block),
-                                 ext4_ext_is_uninitialized(newext),
+                                 ext4_ext_is_unwritten(newext),
                                  ext4_ext_get_actual_len(newext),
                                  le32_to_cpu(ex->ee_block),
-                                 ext4_ext_is_uninitialized(ex),
+                                 ext4_ext_is_unwritten(ex),
                                  ext4_ext_get_actual_len(ex),
                                  ext4_ext_pblock(ex));
                        err = ext4_ext_get_access(handle, inode,
@@ -1980,13 +1981,13 @@ prepend:
                        if (err)
                                return err;
 
-                       uninit = ext4_ext_is_uninitialized(ex);
+                       unwritten = ext4_ext_is_unwritten(ex);
                        ex->ee_block = newext->ee_block;
                        ext4_ext_store_pblock(ex, ext4_ext_pblock(newext));
                        ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
                                        + ext4_ext_get_actual_len(newext));
-                       if (uninit)
-                               ext4_ext_mark_uninitialized(ex);
+                       if (unwritten)
+                               ext4_ext_mark_unwritten(ex);
                        eh = path[depth].p_hdr;
                        nearex = ex;
                        goto merge;
@@ -2046,7 +2047,7 @@ has_space:
                ext_debug("first extent in the leaf: %u:%llu:[%d]%d\n",
                                le32_to_cpu(newext->ee_block),
                                ext4_ext_pblock(newext),
-                               ext4_ext_is_uninitialized(newext),
+                               ext4_ext_is_unwritten(newext),
                                ext4_ext_get_actual_len(newext));
                nearex = EXT_FIRST_EXTENT(eh);
        } else {
@@ -2057,7 +2058,7 @@ has_space:
                                        "nearest %p\n",
                                        le32_to_cpu(newext->ee_block),
                                        ext4_ext_pblock(newext),
-                                       ext4_ext_is_uninitialized(newext),
+                                       ext4_ext_is_unwritten(newext),
                                        ext4_ext_get_actual_len(newext),
                                        nearex);
                        nearex++;
@@ -2068,7 +2069,7 @@ has_space:
                                        "nearest %p\n",
                                        le32_to_cpu(newext->ee_block),
                                        ext4_ext_pblock(newext),
-                                       ext4_ext_is_uninitialized(newext),
+                                       ext4_ext_is_unwritten(newext),
                                        ext4_ext_get_actual_len(newext),
                                        nearex);
                }
@@ -2078,7 +2079,7 @@ has_space:
                                        "move %d extents from 0x%p to 0x%p\n",
                                        le32_to_cpu(newext->ee_block),
                                        ext4_ext_pblock(newext),
-                                       ext4_ext_is_uninitialized(newext),
+                                       ext4_ext_is_unwritten(newext),
                                        ext4_ext_get_actual_len(newext),
                                        len, nearex, nearex + 1);
                        memmove(nearex + 1, nearex,
@@ -2200,7 +2201,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
                        es.es_lblk = le32_to_cpu(ex->ee_block);
                        es.es_len = ext4_ext_get_actual_len(ex);
                        es.es_pblk = ext4_ext_pblock(ex);
-                       if (ext4_ext_is_uninitialized(ex))
+                       if (ext4_ext_is_unwritten(ex))
                                flags |= FIEMAP_EXTENT_UNWRITTEN;
                }
 
@@ -2576,7 +2577,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        unsigned num;
        ext4_lblk_t ex_ee_block;
        unsigned short ex_ee_len;
-       unsigned uninitialized = 0;
+       unsigned unwritten = 0;
        struct ext4_extent *ex;
        ext4_fsblk_t pblk;
 
@@ -2623,13 +2624,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        while (ex >= EXT_FIRST_EXTENT(eh) &&
                        ex_ee_block + ex_ee_len > start) {
 
-               if (ext4_ext_is_uninitialized(ex))
-                       uninitialized = 1;
+               if (ext4_ext_is_unwritten(ex))
+                       unwritten = 1;
                else
-                       uninitialized = 0;
+                       unwritten = 0;
 
                ext_debug("remove ext %u:[%d]%d\n", ex_ee_block,
-                        uninitialized, ex_ee_len);
+                         unwritten, ex_ee_len);
                path[depth].p_ext = ex;
 
                a = ex_ee_block > start ? ex_ee_block : start;
@@ -2701,11 +2702,11 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
 
                ex->ee_len = cpu_to_le16(num);
                /*
-                * Do not mark uninitialized if all the blocks in the
+                * Do not mark unwritten if all the blocks in the
                 * extent have been removed.
                 */
-               if (uninitialized && num)
-                       ext4_ext_mark_uninitialized(ex);
+               if (unwritten && num)
+                       ext4_ext_mark_unwritten(ex);
                /*
                 * If the extent was completely released,
                 * we need to remove it from the leaf
@@ -2854,9 +2855,9 @@ again:
                    end < ee_block + ext4_ext_get_actual_len(ex) - 1) {
                        int split_flag = 0;
 
-                       if (ext4_ext_is_uninitialized(ex))
-                               split_flag = EXT4_EXT_MARK_UNINIT1 |
-                                            EXT4_EXT_MARK_UNINIT2;
+                       if (ext4_ext_is_unwritten(ex))
+                               split_flag = EXT4_EXT_MARK_UNWRIT1 |
+                                            EXT4_EXT_MARK_UNWRIT2;
 
                        /*
                         * Split the extent in two so that 'end' is the last
@@ -3113,7 +3114,7 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
  * @path: the path to the extent
  * @split: the logical block where the extent is splitted.
  * @split_flags: indicates if the extent could be zeroout if split fails, and
- *              the states(init or uninit) of new extents.
+ *              the states(init or unwritten) of new extents.
  * @flags: flags used to insert new extent to extent tree.
  *
  *
@@ -3155,10 +3156,10 @@ static int ext4_split_extent_at(handle_t *handle,
        newblock = split - ee_block + ext4_ext_pblock(ex);
 
        BUG_ON(split < ee_block || split >= (ee_block + ee_len));
-       BUG_ON(!ext4_ext_is_uninitialized(ex) &&
+       BUG_ON(!ext4_ext_is_unwritten(ex) &&
               split_flag & (EXT4_EXT_MAY_ZEROOUT |
-                            EXT4_EXT_MARK_UNINIT1 |
-                            EXT4_EXT_MARK_UNINIT2));
+                            EXT4_EXT_MARK_UNWRIT1 |
+                            EXT4_EXT_MARK_UNWRIT2));
 
        err = ext4_ext_get_access(handle, inode, path + depth);
        if (err)
@@ -3170,8 +3171,8 @@ static int ext4_split_extent_at(handle_t *handle,
                 * then we just change the state of the extent, and splitting
                 * is not needed.
                 */
-               if (split_flag & EXT4_EXT_MARK_UNINIT2)
-                       ext4_ext_mark_uninitialized(ex);
+               if (split_flag & EXT4_EXT_MARK_UNWRIT2)
+                       ext4_ext_mark_unwritten(ex);
                else
                        ext4_ext_mark_initialized(ex);
 
@@ -3185,8 +3186,8 @@ static int ext4_split_extent_at(handle_t *handle,
        /* case a */
        memcpy(&orig_ex, ex, sizeof(orig_ex));
        ex->ee_len = cpu_to_le16(split - ee_block);
-       if (split_flag & EXT4_EXT_MARK_UNINIT1)
-               ext4_ext_mark_uninitialized(ex);
+       if (split_flag & EXT4_EXT_MARK_UNWRIT1)
+               ext4_ext_mark_unwritten(ex);
 
        /*
         * path may lead to new leaf, not to original leaf any more
@@ -3200,8 +3201,8 @@ static int ext4_split_extent_at(handle_t *handle,
        ex2->ee_block = cpu_to_le32(split);
        ex2->ee_len   = cpu_to_le16(ee_len - (split - ee_block));
        ext4_ext_store_pblock(ex2, newblock);
-       if (split_flag & EXT4_EXT_MARK_UNINIT2)
-               ext4_ext_mark_uninitialized(ex2);
+       if (split_flag & EXT4_EXT_MARK_UNWRIT2)
+               ext4_ext_mark_unwritten(ex2);
 
        err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
        if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
@@ -3278,7 +3279,7 @@ static int ext4_split_extent(handle_t *handle,
        struct ext4_extent *ex;
        unsigned int ee_len, depth;
        int err = 0;
-       int uninitialized;
+       int unwritten;
        int split_flag1, flags1;
        int allocated = map->m_len;
 
@@ -3286,14 +3287,14 @@ static int ext4_split_extent(handle_t *handle,
        ex = path[depth].p_ext;
        ee_block = le32_to_cpu(ex->ee_block);
        ee_len = ext4_ext_get_actual_len(ex);
-       uninitialized = ext4_ext_is_uninitialized(ex);
+       unwritten = ext4_ext_is_unwritten(ex);
 
        if (map->m_lblk + map->m_len < ee_block + ee_len) {
                split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
                flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;
-               if (uninitialized)
-                       split_flag1 |= EXT4_EXT_MARK_UNINIT1 |
-                                      EXT4_EXT_MARK_UNINIT2;
+               if (unwritten)
+                       split_flag1 |= EXT4_EXT_MARK_UNWRIT1 |
+                                      EXT4_EXT_MARK_UNWRIT2;
                if (split_flag & EXT4_EXT_DATA_VALID2)
                        split_flag1 |= EXT4_EXT_DATA_VALID1;
                err = ext4_split_extent_at(handle, inode, path,
@@ -3318,15 +3319,15 @@ static int ext4_split_extent(handle_t *handle,
                                 (unsigned long) map->m_lblk);
                return -EIO;
        }
-       uninitialized = ext4_ext_is_uninitialized(ex);
+       unwritten = ext4_ext_is_unwritten(ex);
        split_flag1 = 0;
 
        if (map->m_lblk >= ee_block) {
                split_flag1 = split_flag & EXT4_EXT_DATA_VALID2;
-               if (uninitialized) {
-                       split_flag1 |= EXT4_EXT_MARK_UNINIT1;
+               if (unwritten) {
+                       split_flag1 |= EXT4_EXT_MARK_UNWRIT1;
                        split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT |
-                                                    EXT4_EXT_MARK_UNINIT2);
+                                                    EXT4_EXT_MARK_UNWRIT2);
                }
                err = ext4_split_extent_at(handle, inode, path,
                                map->m_lblk, split_flag1, flags);
@@ -3341,16 +3342,16 @@ out:
 
 /*
  * This function is called by ext4_ext_map_blocks() if someone tries to write
- * to an uninitialized extent. It may result in splitting the uninitialized
+ * to an unwritten extent. It may result in splitting the unwritten
  * extent into multiple extents (up to three - one initialized and two
- * uninitialized).
+ * unwritten).
  * There are three possibilities:
  *   a> There is no split required: Entire extent should be initialized
  *   b> Splits in two extents: Write is happening at either end of the extent
  *   c> Splits in three extents: Somone is writing in middle of the extent
  *
  * Pre-conditions:
- *  - The extent pointed to by 'path' is uninitialized.
+ *  - The extent pointed to by 'path' is unwritten.
  *  - The extent pointed to by 'path' contains a superset
  *    of the logical span [map->m_lblk, map->m_lblk + map->m_len).
  *
@@ -3396,12 +3397,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
        trace_ext4_ext_convert_to_initialized_enter(inode, map, ex);
 
        /* Pre-conditions */
-       BUG_ON(!ext4_ext_is_uninitialized(ex));
+       BUG_ON(!ext4_ext_is_unwritten(ex));
        BUG_ON(!in_range(map->m_lblk, ee_block, ee_len));
 
        /*
         * Attempt to transfer newly initialized blocks from the currently
-        * uninitialized extent to its neighbor. This is much cheaper
+        * unwritten extent to its neighbor. This is much cheaper
         * than an insertion followed by a merge as those involve costly
         * memmove() calls. Transferring to the left is the common case in
         * steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE)
@@ -3437,7 +3438,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                 * - C4: abut_ex can receive the additional blocks without
                 *   overflowing the (initialized) length limit.
                 */
-               if ((!ext4_ext_is_uninitialized(abut_ex)) &&            /*C1*/
+               if ((!ext4_ext_is_unwritten(abut_ex)) &&                /*C1*/
                        ((prev_lblk + prev_len) == ee_block) &&         /*C2*/
                        ((prev_pblk + prev_len) == ee_pblk) &&          /*C3*/
                        (prev_len < (EXT_INIT_MAX_LEN - map_len))) {    /*C4*/
@@ -3452,7 +3453,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        ex->ee_block = cpu_to_le32(ee_block + map_len);
                        ext4_ext_store_pblock(ex, ee_pblk + map_len);
                        ex->ee_len = cpu_to_le16(ee_len - map_len);
-                       ext4_ext_mark_uninitialized(ex); /* Restore the flag */
+                       ext4_ext_mark_unwritten(ex); /* Restore the flag */
 
                        /* Extend abut_ex by 'map_len' blocks */
                        abut_ex->ee_len = cpu_to_le16(prev_len + map_len);
@@ -3483,7 +3484,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                 * - C4: abut_ex can receive the additional blocks without
                 *   overflowing the (initialized) length limit.
                 */
-               if ((!ext4_ext_is_uninitialized(abut_ex)) &&            /*C1*/
+               if ((!ext4_ext_is_unwritten(abut_ex)) &&                /*C1*/
                    ((map->m_lblk + map_len) == next_lblk) &&           /*C2*/
                    ((ee_pblk + ee_len) == next_pblk) &&                /*C3*/
                    (next_len < (EXT_INIT_MAX_LEN - map_len))) {        /*C4*/
@@ -3498,7 +3499,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        abut_ex->ee_block = cpu_to_le32(next_lblk - map_len);
                        ext4_ext_store_pblock(abut_ex, next_pblk - map_len);
                        ex->ee_len = cpu_to_le16(ee_len - map_len);
-                       ext4_ext_mark_uninitialized(ex); /* Restore the flag */
+                       ext4_ext_mark_unwritten(ex); /* Restore the flag */
 
                        /* Extend abut_ex by 'map_len' blocks */
                        abut_ex->ee_len = cpu_to_le16(next_len + map_len);
@@ -3603,26 +3604,26 @@ out:
 /*
  * This function is called by ext4_ext_map_blocks() from
  * ext4_get_blocks_dio_write() when DIO to write
- * to an uninitialized extent.
+ * to an unwritten extent.
  *
- * Writing to an uninitialized extent may result in splitting the uninitialized
- * extent into multiple initialized/uninitialized extents (up to three)
+ * Writing to an unwritten extent may result in splitting the unwritten
+ * extent into multiple initialized/unwritten extents (up to three)
  * There are three possibilities:
- *   a> There is no split required: Entire extent should be uninitialized
+ *   a> There is no split required: Entire extent should be unwritten
  *   b> Splits in two extents: Write is happening at either end of the extent
  *   c> Splits in three extents: Somone is writing in middle of the extent
  *
  * This works the same way in the case of initialized -> unwritten conversion.
  *
  * One of more index blocks maybe needed if the extent tree grow after
- * the uninitialized extent split. To prevent ENOSPC occur at the IO
- * complete, we need to split the uninitialized extent before DIO submit
- * the IO. The uninitialized extent called at this time will be split
- * into three uninitialized extent(at most). After IO complete, the part
+ * the unwritten extent split. To prevent ENOSPC occur at the IO
+ * complete, we need to split the unwritten extent before DIO submit
+ * the IO. The unwritten extent called at this time will be split
+ * into three unwritten extent(at most). After IO complete, the part
  * being filled will be convert to initialized by the end_io callback function
  * via ext4_convert_unwritten_extents().
  *
- * Returns the size of uninitialized extent to be written on success.
+ * Returns the size of unwritten extent to be written on success.
  */
 static int ext4_split_convert_extents(handle_t *handle,
                                        struct inode *inode,
@@ -3660,7 +3661,7 @@ static int ext4_split_convert_extents(handle_t *handle,
        } else if (flags & EXT4_GET_BLOCKS_CONVERT) {
                split_flag |= ee_block + ee_len <= eof_block ?
                              EXT4_EXT_MAY_ZEROOUT : 0;
-               split_flag |= (EXT4_EXT_MARK_UNINIT2 | EXT4_EXT_DATA_VALID2);
+               split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
        }
        flags |= EXT4_GET_BLOCKS_PRE_IO;
        return ext4_split_extent(handle, inode, path, map, split_flag, flags);
@@ -3710,8 +3711,8 @@ static int ext4_convert_initialized_extents(handle_t *handle,
        err = ext4_ext_get_access(handle, inode, path + depth);
        if (err)
                goto out;
-       /* first mark the extent as uninitialized */
-       ext4_ext_mark_uninitialized(ex);
+       /* first mark the extent as unwritten */
+       ext4_ext_mark_unwritten(ex);
 
        /* note: ext4_ext_correct_indexes() isn't needed here because
         * borders are not changed
@@ -3971,10 +3972,10 @@ ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode,
 
        /*
         * Make sure that the extent is no bigger than we support with
-        * uninitialized extent
+        * unwritten extent
         */
-       if (map->m_len > EXT_UNINIT_MAX_LEN)
-               map->m_len = EXT_UNINIT_MAX_LEN / 2;
+       if (map->m_len > EXT_UNWRITTEN_MAX_LEN)
+               map->m_len = EXT_UNWRITTEN_MAX_LEN / 2;
 
        ret = ext4_convert_initialized_extents(handle, inode, map,
                                                path);
@@ -3993,7 +3994,7 @@ ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode,
 }
 
 static int
-ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
+ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
                        struct ext4_map_blocks *map,
                        struct ext4_ext_path *path, int flags,
                        unsigned int allocated, ext4_fsblk_t newblock)
@@ -4002,19 +4003,19 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
        int err = 0;
        ext4_io_end_t *io = ext4_inode_aio(inode);
 
-       ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical "
+       ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical "
                  "block %llu, max_blocks %u, flags %x, allocated %u\n",
                  inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
                  flags, allocated);
        ext4_ext_show_leaf(inode, path);
 
        /*
-        * When writing into uninitialized space, we should not fail to
+        * When writing into unwritten space, we should not fail to
         * allocate metadata blocks for the new extent block if needed.
         */
        flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;
 
-       trace_ext4_ext_handle_uninitialized_extents(inode, map, flags,
+       trace_ext4_ext_handle_unwritten_extents(inode, map, flags,
                                                    allocated, newblock);
 
        /* get_block() before submit the IO, split the extent */
@@ -4033,8 +4034,6 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
                else
                        ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
                map->m_flags |= EXT4_MAP_UNWRITTEN;
-               if (ext4_should_dioread_nolock(inode))
-                       map->m_flags |= EXT4_MAP_UNINIT;
                goto out;
        }
        /* IO end_io complete, convert the filled extent to written */
@@ -4059,7 +4058,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
         * repeat fallocate creation request
         * we already have an unwritten extent
         */
-       if (flags & EXT4_GET_BLOCKS_UNINIT_EXT) {
+       if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) {
                map->m_flags |= EXT4_MAP_UNWRITTEN;
                goto map_out;
        }
@@ -4310,7 +4309,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 
 
                /*
-                * Uninitialized extents are treated as holes, except that
+                * unwritten extents are treated as holes, except that
                 * we split out initialized portions during a write.
                 */
                ee_len = ext4_ext_get_actual_len(ex);
@@ -4329,16 +4328,16 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                         * If the extent is initialized check whether the
                         * caller wants to convert it to unwritten.
                         */
-                       if ((!ext4_ext_is_uninitialized(ex)) &&
+                       if ((!ext4_ext_is_unwritten(ex)) &&
                            (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) {
                                allocated = ext4_ext_convert_initialized_extent(
                                                handle, inode, map, path, flags,
                                                allocated, newblock);
                                goto out2;
-                       } else if (!ext4_ext_is_uninitialized(ex))
+                       } else if (!ext4_ext_is_unwritten(ex))
                                goto out;
 
-                       ret = ext4_ext_handle_uninitialized_extents(
+                       ret = ext4_ext_handle_unwritten_extents(
                                handle, inode, map, path, flags,
                                allocated, newblock);
                        if (ret < 0)
@@ -4410,15 +4409,15 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        /*
         * See if request is beyond maximum number of blocks we can have in
         * a single extent. For an initialized extent this limit is
-        * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
-        * EXT_UNINIT_MAX_LEN.
+        * EXT_INIT_MAX_LEN and for an unwritten extent this limit is
+        * EXT_UNWRITTEN_MAX_LEN.
         */
        if (map->m_len > EXT_INIT_MAX_LEN &&
-           !(flags & EXT4_GET_BLOCKS_UNINIT_EXT))
+           !(flags & EXT4_GET_BLOCKS_UNWRIT_EXT))
                map->m_len = EXT_INIT_MAX_LEN;
-       else if (map->m_len > EXT_UNINIT_MAX_LEN &&
-                (flags & EXT4_GET_BLOCKS_UNINIT_EXT))
-               map->m_len = EXT_UNINIT_MAX_LEN;
+       else if (map->m_len > EXT_UNWRITTEN_MAX_LEN &&
+                (flags & EXT4_GET_BLOCKS_UNWRIT_EXT))
+               map->m_len = EXT_UNWRITTEN_MAX_LEN;
 
        /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */
        newex.ee_len = cpu_to_le16(map->m_len);
@@ -4466,21 +4465,19 @@ got_allocated_blocks:
        /* try to insert new extent into found leaf and return */
        ext4_ext_store_pblock(&newex, newblock + offset);
        newex.ee_len = cpu_to_le16(ar.len);
-       /* Mark uninitialized */
-       if (flags & EXT4_GET_BLOCKS_UNINIT_EXT){
-               ext4_ext_mark_uninitialized(&newex);
+       /* Mark unwritten */
+       if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){
+               ext4_ext_mark_unwritten(&newex);
                map->m_flags |= EXT4_MAP_UNWRITTEN;
                /*
                 * io_end structure was created for every IO write to an
-                * uninitialized extent. To avoid unnecessary conversion,
+                * unwritten extent. To avoid unnecessary conversion,
                 * here we flag the IO that really needs the conversion.
                 * For non asycn direct IO case, flag the inode state
                 * that we need to perform conversion when IO is done.
                 */
                if ((flags & EXT4_GET_BLOCKS_PRE_IO))
                        set_unwritten = 1;
-               if (ext4_should_dioread_nolock(inode))
-                       map->m_flags |= EXT4_MAP_UNINIT;
        }
 
        err = 0;
@@ -4607,9 +4604,9 @@ got_allocated_blocks:
 
        /*
         * Cache the extent and update transaction to commit on fdatasync only
-        * when it is _not_ an uninitialized extent.
+        * when it is _not_ an unwritten extent.
         */
-       if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0)
+       if ((flags & EXT4_GET_BLOCKS_UNWRIT_EXT) == 0)
                ext4_update_inode_fsync_trans(handle, inode, 1);
        else
                ext4_update_inode_fsync_trans(handle, inode, 0);
@@ -4683,7 +4680,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
         * that it doesn't get unnecessarily split into multiple
         * extents.
         */
-       if (len <= EXT_UNINIT_MAX_LEN)
+       if (len <= EXT_UNWRITTEN_MAX_LEN)
                flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
 
        /*
@@ -4775,7 +4772,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        else
                max_blocks -= lblk;
 
-       flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT |
+       flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT |
                EXT4_GET_BLOCKS_CONVERT_UNWRITTEN;
        if (mode & FALLOC_FL_KEEP_SIZE)
                flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
@@ -4865,6 +4862,14 @@ out_mutex:
        return ret;
 }
 
+#ifdef CONFIG_EXT4_DEBUG
+int ext4_fallocate_mode_block __read_mostly;
+
+module_param_named(fallocate_mode_block, ext4_fallocate_mode_block, int, 0644);
+MODULE_PARM_DESC(fallocate_mode_block,
+                "Fallocate modes which are blocked for debugging purposes");
+#endif
+
 /*
  * preallocate space for a file. This implements ext4's fallocate file
  * operation, which gets called from sys_fallocate system call.
@@ -4884,6 +4889,15 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        struct timespec tv;
        unsigned int blkbits = inode->i_blkbits;
 
+#ifdef CONFIG_EXT4_DEBUG
+       /*
+        * For debugging purposes, allow certain fallocate operations
+        * to be disabled
+        */
+       if (unlikely(mode & ext4_fallocate_mode_block))
+               return -EOPNOTSUPP;
+#endif
+
        /* Return error if mode is not supported */
        if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
                     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))
@@ -4918,7 +4932,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
                - lblk;
 
-       flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT;
+       flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
        if (mode & FALLOC_FL_KEEP_SIZE)
                flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
 
index 0ebc21204b5184841405f890fa11dd5ae11ef54c..98c90f5834eec1a639cf5642705cac834b81328d 100644 (file)
@@ -433,7 +433,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode,
                ee_start = ext4_ext_pblock(ex);
                ee_len = ext4_ext_get_actual_len(ex);
 
-               ee_status = ext4_ext_is_uninitialized(ex) ? 1 : 0;
+               ee_status = ext4_ext_is_unwritten(ex) ? 1 : 0;
                es_status = ext4_es_is_unwritten(es) ? 1 : 0;
 
                /*
index 063fc1538355972d912553ad6c8e419390f057de..708aad7681991368262332520f09f5490af848de 100644 (file)
@@ -74,79 +74,105 @@ void ext4_unwritten_wait(struct inode *inode)
  * or one thread will zero the other's data, causing corruption.
  */
 static int
-ext4_unaligned_aio(struct inode *inode, const struct iovec *iov,
-                  unsigned long nr_segs, loff_t pos)
+ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos)
 {
        struct super_block *sb = inode->i_sb;
        int blockmask = sb->s_blocksize - 1;
-       size_t count = iov_length(iov, nr_segs);
-       loff_t final_size = pos + count;
 
        if (pos >= i_size_read(inode))
                return 0;
 
-       if ((pos & blockmask) || (final_size & blockmask))
+       if ((pos | iov_iter_alignment(from)) & blockmask)
                return 1;
 
        return 0;
 }
 
 static ssize_t
-ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
-                   unsigned long nr_segs, loff_t pos)
+ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = file->f_mapping->host;
+       struct inode *inode = file_inode(iocb->ki_filp);
+       struct mutex *aio_mutex = NULL;
        struct blk_plug plug;
-       int unaligned_aio = 0;
-       ssize_t ret;
+       int o_direct = file->f_flags & O_DIRECT;
        int overwrite = 0;
-       size_t length = iov_length(iov, nr_segs);
-
-       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
-           !is_sync_kiocb(iocb))
-               unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos);
+       size_t length = iov_iter_count(from);
+       ssize_t ret;
+       loff_t pos = iocb->ki_pos;
 
-       /* Unaligned direct AIO must be serialized; see comment above */
-       if (unaligned_aio) {
-               mutex_lock(ext4_aio_mutex(inode));
+       /*
+        * Unaligned direct AIO must be serialized; see comment above
+        * In the case of O_APPEND, assume that we must always serialize
+        */
+       if (o_direct &&
+           ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
+           !is_sync_kiocb(iocb) &&
+           (file->f_flags & O_APPEND ||
+            ext4_unaligned_aio(inode, from, pos))) {
+               aio_mutex = ext4_aio_mutex(inode);
+               mutex_lock(aio_mutex);
                ext4_unwritten_wait(inode);
        }
 
-       BUG_ON(iocb->ki_pos != pos);
-
        mutex_lock(&inode->i_mutex);
-       blk_start_plug(&plug);
+       if (file->f_flags & O_APPEND)
+               iocb->ki_pos = pos = i_size_read(inode);
+
+       /*
+        * If we have encountered a bitmap-format file, the size limit
+        * is smaller than s_maxbytes, which is for extent-mapped files.
+        */
+       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
+               struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 
-       iocb->private = &overwrite;
+               if ((pos > sbi->s_bitmap_maxbytes) ||
+                   (pos == sbi->s_bitmap_maxbytes && length > 0)) {
+                       mutex_unlock(&inode->i_mutex);
+                       ret = -EFBIG;
+                       goto errout;
+               }
 
-       /* check whether we do a DIO overwrite or not */
-       if (ext4_should_dioread_nolock(inode) && !unaligned_aio &&
-           !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) {
-               struct ext4_map_blocks map;
-               unsigned int blkbits = inode->i_blkbits;
-               int err, len;
+               if (pos + length > sbi->s_bitmap_maxbytes)
+                       iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos);
+       }
 
-               map.m_lblk = pos >> blkbits;
-               map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits)
-                       - map.m_lblk;
-               len = map.m_len;
+       if (o_direct) {
+               blk_start_plug(&plug);
 
-               err = ext4_map_blocks(NULL, inode, &map, 0);
-               /*
-                * 'err==len' means that all of blocks has been preallocated no
-                * matter they are initialized or not.  For excluding
-                * uninitialized extents, we need to check m_flags.  There are
-                * two conditions that indicate for initialized extents.
-                * 1) If we hit extent cache, EXT4_MAP_MAPPED flag is returned;
-                * 2) If we do a real lookup, non-flags are returned.
-                * So we should check these two conditions.
-                */
-               if (err == len && (map.m_flags & EXT4_MAP_MAPPED))
-                       overwrite = 1;
+               iocb->private = &overwrite;
+
+               /* check whether we do a DIO overwrite or not */
+               if (ext4_should_dioread_nolock(inode) && !aio_mutex &&
+                   !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) {
+                       struct ext4_map_blocks map;
+                       unsigned int blkbits = inode->i_blkbits;
+                       int err, len;
+
+                       map.m_lblk = pos >> blkbits;
+                       map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits)
+                               - map.m_lblk;
+                       len = map.m_len;
+
+                       err = ext4_map_blocks(NULL, inode, &map, 0);
+                       /*
+                        * 'err==len' means that all of blocks has
+                        * been preallocated no matter they are
+                        * initialized or not.  For excluding
+                        * unwritten extents, we need to check
+                        * m_flags.  There are two conditions that
+                        * indicate for initialized extents.  1) If we
+                        * hit extent cache, EXT4_MAP_MAPPED flag is
+                        * returned; 2) If we do a real lookup,
+                        * non-flags are returned.  So we should check
+                        * these two conditions.
+                        */
+                       if (err == len && (map.m_flags & EXT4_MAP_MAPPED))
+                               overwrite = 1;
+               }
        }
 
-       ret = __generic_file_aio_write(iocb, iov, nr_segs);
+       ret = __generic_file_write_iter(iocb, from);
        mutex_unlock(&inode->i_mutex);
 
        if (ret > 0) {
@@ -156,45 +182,12 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
                if (err < 0)
                        ret = err;
        }
-       blk_finish_plug(&plug);
-
-       if (unaligned_aio)
-               mutex_unlock(ext4_aio_mutex(inode));
-
-       return ret;
-}
-
-static ssize_t
-ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t pos)
-{
-       struct inode *inode = file_inode(iocb->ki_filp);
-       ssize_t ret;
-
-       /*
-        * If we have encountered a bitmap-format file, the size limit
-        * is smaller than s_maxbytes, which is for extent-mapped files.
-        */
-
-       if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
-               struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-               size_t length = iov_length(iov, nr_segs);
-
-               if ((pos > sbi->s_bitmap_maxbytes ||
-                   (pos == sbi->s_bitmap_maxbytes && length > 0)))
-                       return -EFBIG;
-
-               if (pos + length > sbi->s_bitmap_maxbytes) {
-                       nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
-                                             sbi->s_bitmap_maxbytes - pos);
-               }
-       }
-
-       if (unlikely(iocb->ki_filp->f_flags & O_DIRECT))
-               ret = ext4_file_dio_write(iocb, iov, nr_segs, pos);
-       else
-               ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+       if (o_direct)
+               blk_finish_plug(&plug);
 
+errout:
+       if (aio_mutex)
+               mutex_unlock(aio_mutex);
        return ret;
 }
 
@@ -593,10 +586,10 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)
 
 const struct file_operations ext4_file_operations = {
        .llseek         = ext4_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = ext4_file_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = ext4_file_write_iter,
        .unlocked_ioctl = ext4_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext4_compat_ioctl,
@@ -606,7 +599,7 @@ const struct file_operations ext4_file_operations = {
        .release        = ext4_release_file,
        .fsync          = ext4_sync_file,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .fallocate      = ext4_fallocate,
 };
 
index 594009f5f523f0fd2228a72f1aa593a6f3ebf66f..8a57e9fcd1b987bdab029e7658ae100d10949d5a 100644 (file)
@@ -639,8 +639,7 @@ out:
  * VFS code falls back into buffered path in that case so we are safe.
  */
 ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
-                          const struct iovec *iov, loff_t offset,
-                          unsigned long nr_segs)
+                          struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
@@ -648,7 +647,7 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
        handle_t *handle;
        ssize_t ret;
        int orphan = 0;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        int retries = 0;
 
        if (rw == WRITE) {
@@ -687,18 +686,17 @@ retry:
                        goto locked;
                }
                ret = __blockdev_direct_IO(rw, iocb, inode,
-                                inode->i_sb->s_bdev, iov,
-                                offset, nr_segs,
+                                inode->i_sb->s_bdev, iter, offset,
                                 ext4_get_block, NULL, NULL, 0);
                inode_dio_done(inode);
        } else {
 locked:
-               ret = blockdev_direct_IO(rw, iocb, inode, iov,
-                                offset, nr_segs, ext4_get_block);
+               ret = blockdev_direct_IO(rw, iocb, inode, iter,
+                                offset, ext4_get_block);
 
                if (unlikely((rw & WRITE) && ret < 0)) {
                        loff_t isize = i_size_read(inode);
-                       loff_t end = offset + iov_length(iov, nr_segs);
+                       loff_t end = offset + count;
 
                        if (end > isize)
                                ext4_truncate_failed_write(inode);
index d7b7462a0e13e11e7131f2b148d1323a3de5c996..b1dc33423cf2c4cbc1029878c9a54f543a7d33d7 100644 (file)
@@ -489,8 +489,8 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
  * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
  * based files
  *
- * On success, it returns the number of blocks being mapped or allocate.
- * if create==0 and the blocks are pre-allocated and uninitialized block,
+ * On success, it returns the number of blocks being mapped or allocated.
+ * if create==0 and the blocks are pre-allocated and unwritten block,
  * the result buffer head is unmapped. If the create ==1, it will make sure
  * the buffer head is mapped.
  *
@@ -622,7 +622,7 @@ found:
        map->m_flags &= ~EXT4_MAP_FLAGS;
 
        /*
-        * New blocks allocate and/or writing to uninitialized extent
+        * New blocks allocate and/or writing to unwritten extent
         * will possibly result in updating i_data, so we take
         * the write lock of i_data_sem, and call get_blocks()
         * with create == 1 flag.
@@ -2032,7 +2032,7 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
  * Scan buffers corresponding to changed extent (we expect corresponding pages
  * to be already locked) and update buffer state according to new extent state.
  * We map delalloc buffers to their physical location, clear unwritten bits,
- * and mark buffers as uninit when we perform writes to uninitialized extents
+ * and mark buffers as uninit when we perform writes to unwritten extents
  * and do extent conversion after IO is finished. If the last page is not fully
  * mapped, we update @map to the next extent in the last page that needs
  * mapping. Otherwise we submit the page for IO.
@@ -2126,12 +2126,12 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
        struct inode *inode = mpd->inode;
        struct ext4_map_blocks *map = &mpd->map;
        int get_blocks_flags;
-       int err;
+       int err, dioread_nolock;
 
        trace_ext4_da_write_pages_extent(inode, map);
        /*
         * Call ext4_map_blocks() to allocate any delayed allocation blocks, or
-        * to convert an uninitialized extent to be initialized (in the case
+        * to convert an unwritten extent to be initialized (in the case
         * where we have written into one or more preallocated blocks).  It is
         * possible that we're going to need more metadata blocks than
         * previously reserved. However we must not fail because we're in
@@ -2148,7 +2148,8 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
         */
        get_blocks_flags = EXT4_GET_BLOCKS_CREATE |
                           EXT4_GET_BLOCKS_METADATA_NOFAIL;
-       if (ext4_should_dioread_nolock(inode))
+       dioread_nolock = ext4_should_dioread_nolock(inode);
+       if (dioread_nolock)
                get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
        if (map->m_flags & (1 << BH_Delay))
                get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE;
@@ -2156,7 +2157,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
        err = ext4_map_blocks(handle, inode, map, get_blocks_flags);
        if (err < 0)
                return err;
-       if (map->m_flags & EXT4_MAP_UNINIT) {
+       if (dioread_nolock && (map->m_flags & EXT4_MAP_UNWRITTEN)) {
                if (!mpd->io_submit.io_end->handle &&
                    ext4_handle_valid(handle)) {
                        mpd->io_submit.io_end->handle = handle->h_rsv_handle;
@@ -3070,9 +3071,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
  * preallocated extents, and those write extend the file, no need to
  * fall back to buffered IO.
  *
- * For holes, we fallocate those blocks, mark them as uninitialized
+ * For holes, we fallocate those blocks, mark them as unwritten
  * If those blocks were preallocated, we mark sure they are split, but
- * still keep the range to write as uninitialized.
+ * still keep the range to write as unwritten.
  *
  * The unwritten extents will be converted to written when DIO is completed.
  * For async direct IO, since the IO may still pending when return, we
@@ -3085,13 +3086,12 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
  *
  */
 static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
-                             const struct iovec *iov, loff_t offset,
-                             unsigned long nr_segs)
+                             struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        ssize_t ret;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        int overwrite = 0;
        get_block_t *get_block_func = NULL;
        int dio_flags = 0;
@@ -3100,7 +3100,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
 
        /* Use the old path for reads and writes beyond i_size. */
        if (rw != WRITE || final_size > inode->i_size)
-               return ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
+               return ext4_ind_direct_IO(rw, iocb, iter, offset);
 
        BUG_ON(iocb->private == NULL);
 
@@ -3124,12 +3124,12 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
         * We could direct write to holes and fallocate.
         *
         * Allocated blocks to fill the hole are marked as
-        * uninitialized to prevent parallel buffered read to expose
+        * unwritten to prevent parallel buffered read to expose
         * the stale data before DIO complete the data IO.
         *
         * As to previously fallocated extents, ext4 get_block will
         * just simply mark the buffer mapped but still keep the
-        * extents uninitialized.
+        * extents unwritten.
         *
         * For non AIO case, we will convert those unwritten extents
         * to written after return back from blockdev_direct_IO.
@@ -3167,8 +3167,8 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
                dio_flags = DIO_LOCKING;
        }
        ret = __blockdev_direct_IO(rw, iocb, inode,
-                                  inode->i_sb->s_bdev, iov,
-                                  offset, nr_segs,
+                                  inode->i_sb->s_bdev, iter,
+                                  offset,
                                   get_block_func,
                                   ext4_end_io_dio,
                                   NULL,
@@ -3222,11 +3222,11 @@ retake_lock:
 }
 
 static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
-                             const struct iovec *iov, loff_t offset,
-                             unsigned long nr_segs)
+                             struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
        /*
@@ -3239,13 +3239,12 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
        if (ext4_has_inline_data(inode))
                return 0;
 
-       trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw);
+       trace_ext4_direct_IO_enter(inode, offset, count, rw);
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
-               ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);
+               ret = ext4_ext_direct_IO(rw, iocb, iter, offset);
        else
-               ret = ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
-       trace_ext4_direct_IO_exit(inode, offset,
-                               iov_length(iov, nr_segs), rw, ret);
+               ret = ext4_ind_direct_IO(rw, iocb, iter, offset);
+       trace_ext4_direct_IO_exit(inode, offset, count, rw, ret);
        return ret;
 }
 
@@ -4304,12 +4303,15 @@ static int ext4_do_update_inode(handle_t *handle,
        struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
        struct ext4_inode_info *ei = EXT4_I(inode);
        struct buffer_head *bh = iloc->bh;
+       struct super_block *sb = inode->i_sb;
        int err = 0, rc, block;
-       int need_datasync = 0;
+       int need_datasync = 0, set_large_file = 0;
        uid_t i_uid;
        gid_t i_gid;
 
-       /* For fields not not tracking in the in-memory inode,
+       spin_lock(&ei->i_raw_lock);
+
+       /* For fields not tracked in the in-memory inode,
         * initialise them to zero for new inodes. */
        if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
                memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
@@ -4347,8 +4349,10 @@ static int ext4_do_update_inode(handle_t *handle,
        EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
        EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
 
-       if (ext4_inode_blocks_set(handle, raw_inode, ei))
+       if (ext4_inode_blocks_set(handle, raw_inode, ei)) {
+               spin_unlock(&ei->i_raw_lock);
                goto out_brelse;
+       }
        raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
        raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF);
        if (likely(!test_opt2(inode->i_sb, HURD_COMPAT)))
@@ -4360,24 +4364,11 @@ static int ext4_do_update_inode(handle_t *handle,
                need_datasync = 1;
        }
        if (ei->i_disksize > 0x7fffffffULL) {
-               struct super_block *sb = inode->i_sb;
                if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
                                EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
                                EXT4_SB(sb)->s_es->s_rev_level ==
-                               cpu_to_le32(EXT4_GOOD_OLD_REV)) {
-                       /* If this is the first large file
-                        * created, add a flag to the superblock.
-                        */
-                       err = ext4_journal_get_write_access(handle,
-                                       EXT4_SB(sb)->s_sbh);
-                       if (err)
-                               goto out_brelse;
-                       ext4_update_dynamic_rev(sb);
-                       EXT4_SET_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
-                       ext4_handle_sync(handle);
-                       err = ext4_handle_dirty_super(handle, sb);
-               }
+                   cpu_to_le32(EXT4_GOOD_OLD_REV))
+                       set_large_file = 1;
        }
        raw_inode->i_generation = cpu_to_le32(inode->i_generation);
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
@@ -4409,12 +4400,23 @@ static int ext4_do_update_inode(handle_t *handle,
 
        ext4_inode_csum_set(inode, raw_inode, ei);
 
+       spin_unlock(&ei->i_raw_lock);
+
        BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
        rc = ext4_handle_dirty_metadata(handle, NULL, bh);
        if (!err)
                err = rc;
        ext4_clear_inode_state(inode, EXT4_STATE_NEW);
-
+       if (set_large_file) {
+               err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
+               if (err)
+                       goto out_brelse;
+               ext4_update_dynamic_rev(sb);
+               EXT4_SET_RO_COMPAT_FEATURE(sb,
+                                          EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
+               ext4_handle_sync(handle);
+               err = ext4_handle_dirty_super(handle, sb);
+       }
        ext4_update_inode_fsync_trans(handle, inode, need_datasync);
 out_brelse:
        brelse(bh);
index 58ee7dc87669d9f49961a4be47335ae5e4615638..1b809fe51da18df7ac4ae5b63b20a7b02c3bf038 100644 (file)
@@ -57,8 +57,8 @@ get_ext_path(struct inode *inode, ext4_lblk_t lblock,
 static void
 copy_extent_status(struct ext4_extent *src, struct ext4_extent *dest)
 {
-       if (ext4_ext_is_uninitialized(src))
-               ext4_ext_mark_uninitialized(dest);
+       if (ext4_ext_is_unwritten(src))
+               ext4_ext_mark_unwritten(dest);
        else
                dest->ee_len = cpu_to_le16(ext4_ext_get_actual_len(dest));
 }
@@ -593,14 +593,14 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext,
  * @inode:             inode in question
  * @from:              block offset of inode
  * @count:             block count to be checked
- * @uninit:            extents expected to be uninitialized
+ * @unwritten:         extents expected to be unwritten
  * @err:               pointer to save error value
  *
  * Return 1 if all extents in range has expected type, and zero otherwise.
  */
 static int
 mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count,
-                         int uninit, int *err)
+                   int unwritten, int *err)
 {
        struct ext4_ext_path *path = NULL;
        struct ext4_extent *ext;
@@ -611,7 +611,7 @@ mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count,
                if (*err)
                        goto out;
                ext = path[ext_depth(inode)].p_ext;
-               if (uninit != ext4_ext_is_uninitialized(ext))
+               if (unwritten != ext4_ext_is_unwritten(ext))
                        goto out;
                from += ext4_ext_get_actual_len(ext);
                ext4_ext_drop_refs(path);
@@ -894,7 +894,7 @@ out:
  * @orig_page_offset:          page index on original file
  * @data_offset_in_page:       block index where data swapping starts
  * @block_len_in_page:         the number of blocks to be swapped
- * @uninit:                    orig extent is uninitialized or not
+ * @unwritten:                 orig extent is unwritten or not
  * @err:                       pointer to save return value
  *
  * Save the data in original inode blocks and replace original inode extents
@@ -905,7 +905,7 @@ out:
 static int
 move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
                  pgoff_t orig_page_offset, int data_offset_in_page,
-                 int block_len_in_page, int uninit, int *err)
+                 int block_len_in_page, int unwritten, int *err)
 {
        struct inode *orig_inode = file_inode(o_filp);
        struct page *pagep[2] = {NULL, NULL};
@@ -962,27 +962,27 @@ again:
        if (unlikely(*err < 0))
                goto stop_journal;
        /*
-        * If orig extent was uninitialized it can become initialized
+        * If orig extent was unwritten it can become initialized
         * at any time after i_data_sem was dropped, in order to
         * serialize with delalloc we have recheck extent while we
         * hold page's lock, if it is still the case data copy is not
         * necessary, just swap data blocks between orig and donor.
         */
-       if (uninit) {
+       if (unwritten) {
                ext4_double_down_write_data_sem(orig_inode, donor_inode);
                /* If any of extents in range became initialized we have to
                 * fallback to data copying */
-               uninit = mext_check_coverage(orig_inode, orig_blk_offset,
-                                            block_len_in_page, 1, err);
+               unwritten = mext_check_coverage(orig_inode, orig_blk_offset,
+                                               block_len_in_page, 1, err);
                if (*err)
                        goto drop_data_sem;
 
-               uninit &= mext_check_coverage(donor_inode, orig_blk_offset,
-                                             block_len_in_page, 1, err);
+               unwritten &= mext_check_coverage(donor_inode, orig_blk_offset,
+                                                block_len_in_page, 1, err);
                if (*err)
                        goto drop_data_sem;
 
-               if (!uninit) {
+               if (!unwritten) {
                        ext4_double_up_write_data_sem(orig_inode, donor_inode);
                        goto data_copy;
                }
@@ -1259,7 +1259,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
        int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits;
        int data_offset_in_page;
        int block_len_in_page;
-       int uninit;
+       int unwritten;
 
        if (orig_inode->i_sb != donor_inode->i_sb) {
                ext4_debug("ext4 move extent: The argument files "
@@ -1391,8 +1391,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
                    !last_extent)
                        continue;
 
-               /* Is original extent is uninitialized */
-               uninit = ext4_ext_is_uninitialized(ext_prev);
+               /* Is original extent is unwritten */
+               unwritten = ext4_ext_is_unwritten(ext_prev);
 
                data_offset_in_page = seq_start % blocks_per_page;
 
@@ -1432,8 +1432,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
                                                o_filp, donor_inode,
                                                orig_page_offset,
                                                data_offset_in_page,
-                                               block_len_in_page, uninit,
-                                               &ret);
+                                               block_len_in_page,
+                                               unwritten, &ret);
 
                        /* Count how many blocks we have exchanged */
                        *moved_len += block_len_in_page;
index 1cb84f78909ee2d96a5721569cdbd383e9011a35..a683f958f12859df492d7eb93b8c51c48cec6ee6 100644 (file)
@@ -2510,8 +2510,7 @@ static int empty_dir(struct inode *inode)
                 ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
        de = ext4_next_entry(de1, sb->s_blocksize);
        while (offset < inode->i_size) {
-               if (!bh ||
-                   (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
+               if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
                        unsigned int lblock;
                        err = 0;
                        brelse(bh);
index 6f9e6fadac04e1c8af1d4a98d6258cdbc2f45dea..1f8cb1812723a1a1d4127780dba100a1b3310eaf 100644 (file)
@@ -879,6 +879,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
                return NULL;
 
        ei->vfs_inode.i_version = 1;
+       spin_lock_init(&ei->i_raw_lock);
        INIT_LIST_HEAD(&ei->i_prealloc_list);
        spin_lock_init(&ei->i_prealloc_lock);
        ext4_es_init_tree(&ei->i_es_tree);
@@ -3337,7 +3338,7 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb)
         * By default we reserve 2% or 4096 clusters, whichever is smaller.
         * This should cover the situations where we can not afford to run
         * out of space like for example punch hole, or converting
-        * uninitialized extents in delalloc path. In most cases such
+        * unwritten extents in delalloc path. In most cases such
         * allocation would require 1, or 2 blocks, higher numbers are
         * very rare.
         */
index e93e4ec7d165afe85800bf6acf68f01178d9d836..dbe2141d10ad7d77e67804ec3a8ee0e843a71486 100644 (file)
@@ -240,7 +240,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
                }
        }
 
-       error = f2fs_setxattr(inode, name_index, "", value, size, ipage);
+       error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0);
 
        kfree(value);
        if (!error)
index 4aa521aa9bc3a794fbe52625e689b93140ed38a5..4206f1664be51c8e918170ee40792b8cda0d09ca 100644 (file)
@@ -33,12 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
        struct address_space *mapping = META_MAPPING(sbi);
        struct page *page = NULL;
 repeat:
-       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
+       page = grab_cache_page(mapping, index);
        if (!page) {
                cond_resched();
                goto repeat;
        }
-
+       f2fs_wait_on_page_writeback(page, META);
        SetPageUptodate(page);
        return page;
 }
@@ -73,7 +73,7 @@ out:
        return page;
 }
 
-inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
+static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
 {
        switch (type) {
        case META_NAT:
@@ -174,10 +174,7 @@ no_write:
        return 0;
 
 redirty_out:
-       dec_page_count(sbi, F2FS_DIRTY_META);
-       wbc->pages_skipped++;
-       account_page_redirty(page);
-       set_page_dirty(page);
+       redirty_page_for_writepage(wbc, page);
        return AOP_WRITEPAGE_ACTIVATE;
 }
 
@@ -555,14 +552,13 @@ fail_no_cp:
 static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       struct list_head *head = &sbi->dir_inode_list;
-       struct dir_inode_entry *entry;
 
-       list_for_each_entry(entry, head, list)
-               if (unlikely(entry->inode == inode))
-                       return -EEXIST;
+       if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
+               return -EEXIST;
 
-       list_add_tail(&new->list, head);
+       set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
+       F2FS_I(inode)->dirty_dir = new;
+       list_add_tail(&new->list, &sbi->dir_inode_list);
        stat_inc_dirty_dir(sbi);
        return 0;
 }
@@ -611,31 +607,26 @@ void add_dirty_dir_inode(struct inode *inode)
 void remove_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       struct list_head *head;
        struct dir_inode_entry *entry;
 
        if (!S_ISDIR(inode->i_mode))
                return;
 
        spin_lock(&sbi->dir_inode_lock);
-       if (get_dirty_dents(inode)) {
+       if (get_dirty_dents(inode) ||
+                       !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
                spin_unlock(&sbi->dir_inode_lock);
                return;
        }
 
-       head = &sbi->dir_inode_list;
-       list_for_each_entry(entry, head, list) {
-               if (entry->inode == inode) {
-                       list_del(&entry->list);
-                       stat_dec_dirty_dir(sbi);
-                       spin_unlock(&sbi->dir_inode_lock);
-                       kmem_cache_free(inode_entry_slab, entry);
-                       goto done;
-               }
-       }
+       entry = F2FS_I(inode)->dirty_dir;
+       list_del(&entry->list);
+       F2FS_I(inode)->dirty_dir = NULL;
+       clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
+       stat_dec_dirty_dir(sbi);
        spin_unlock(&sbi->dir_inode_lock);
+       kmem_cache_free(inode_entry_slab, entry);
 
-done:
        /* Only from the recovery routine */
        if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
                clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
@@ -643,26 +634,6 @@ done:
        }
 }
 
-struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
-{
-
-       struct list_head *head;
-       struct inode *inode = NULL;
-       struct dir_inode_entry *entry;
-
-       spin_lock(&sbi->dir_inode_lock);
-
-       head = &sbi->dir_inode_list;
-       list_for_each_entry(entry, head, list) {
-               if (entry->inode->i_ino == ino) {
-                       inode = entry->inode;
-                       break;
-               }
-       }
-       spin_unlock(&sbi->dir_inode_lock);
-       return inode;
-}
-
 void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
 {
        struct list_head *head;
@@ -762,6 +733,12 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        void *kaddr;
        int i;
 
+       /*
+        * This avoids to conduct wrong roll-forward operations and uses
+        * metapages, so should be called prior to sync_meta_pages below.
+        */
+       discard_next_dnode(sbi);
+
        /* Flush all the NAT/SIT pages */
        while (get_pages(sbi, F2FS_DIRTY_META))
                sync_meta_pages(sbi, META, LONG_MAX);
index 45abd60e2bff54323139b037ed1bccd1e534e96e..3e867230052c699a1005807aecb95371dad1a802 100644 (file)
@@ -417,7 +417,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
        if (unlikely(dn.data_blkaddr == NEW_ADDR))
                return ERR_PTR(-EINVAL);
 
-       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
+       page = grab_cache_page(mapping, index);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -455,7 +455,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
        int err;
 
 repeat:
-       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
+       page = grab_cache_page(mapping, index);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -652,8 +652,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
                goto put_out;
        }
 
-       end_offset = IS_INODE(dn.node_page) ?
-                       ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
+       end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
        bh_result->b_size = (((size_t)1) << blkbits);
        dn.ofs_in_node++;
        pgofs++;
@@ -675,8 +674,7 @@ get_next:
                if (dn.data_blkaddr == NEW_ADDR)
                        goto put_out;
 
-               end_offset = IS_INODE(dn.node_page) ?
-                       ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
+               end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
        }
 
        if (maxblocks > (bh_result->b_size >> blkbits)) {
@@ -798,10 +796,8 @@ static int f2fs_write_data_page(struct page *page,
         * this page does not have to be written to disk.
         */
        offset = i_size & (PAGE_CACHE_SIZE - 1);
-       if ((page->index >= end_index + 1) || !offset) {
-               inode_dec_dirty_dents(inode);
+       if ((page->index >= end_index + 1) || !offset)
                goto out;
-       }
 
        zero_user_segment(page, offset, PAGE_CACHE_SIZE);
 write:
@@ -810,7 +806,6 @@ write:
 
        /* Dentry blocks are controlled by checkpoint */
        if (S_ISDIR(inode->i_mode)) {
-               inode_dec_dirty_dents(inode);
                err = do_write_data_page(page, &fio);
                goto done;
        }
@@ -832,15 +827,16 @@ done:
 
        clear_cold_data(page);
 out:
+       inode_dec_dirty_dents(inode);
        unlock_page(page);
        if (need_balance_fs)
                f2fs_balance_fs(sbi);
+       if (wbc->for_reclaim)
+               f2fs_submit_merged_bio(sbi, DATA, WRITE);
        return 0;
 
 redirty_out:
-       wbc->pages_skipped++;
-       account_page_redirty(page);
-       set_page_dirty(page);
+       redirty_page_for_writepage(wbc, page);
        return AOP_WRITEPAGE_ACTIVATE;
 }
 
@@ -867,7 +863,8 @@ static int f2fs_write_data_pages(struct address_space *mapping,
                return 0;
 
        if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
-                       get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA))
+                       get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA) &&
+                       available_free_memory(sbi, DIRTY_DENTS))
                goto skip_write;
 
        diff = nr_pages_to_write(sbi, DATA, wbc);
@@ -912,6 +909,10 @@ repeat:
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
                return -ENOMEM;
+
+       /* to avoid latency during memory pressure */
+       unlock_page(page);
+
        *pagep = page;
 
        if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
@@ -923,10 +924,18 @@ repeat:
        f2fs_unlock_op(sbi);
 
        if (err) {
-               f2fs_put_page(page, 1);
+               f2fs_put_page(page, 0);
                return err;
        }
 inline_data:
+       lock_page(page);
+       if (unlikely(page->mapping != mapping)) {
+               f2fs_put_page(page, 1);
+               goto repeat;
+       }
+
+       f2fs_wait_on_page_writeback(page, DATA);
+
        if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
                return 0;
 
@@ -992,10 +1001,9 @@ static int f2fs_write_end(struct file *file,
 }
 
 static int check_direct_IO(struct inode *inode, int rw,
-               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+               struct iov_iter *iter, loff_t offset)
 {
        unsigned blocksize_mask = inode->i_sb->s_blocksize - 1;
-       int i;
 
        if (rw == READ)
                return 0;
@@ -1003,14 +1011,14 @@ static int check_direct_IO(struct inode *inode, int rw,
        if (offset & blocksize_mask)
                return -EINVAL;
 
-       for (i = 0; i < nr_segs; i++)
-               if (iov[i].iov_len & blocksize_mask)
-                       return -EINVAL;
+       if (iov_iter_alignment(iter) & blocksize_mask)
+               return -EINVAL;
+
        return 0;
 }
 
 static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
-               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+               struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
@@ -1019,11 +1027,11 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
        if (f2fs_has_inline_data(inode))
                return 0;
 
-       if (check_direct_IO(inode, rw, iov, offset, nr_segs))
+       if (check_direct_IO(inode, rw, iter, offset))
                return 0;
 
-       return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                                       get_data_block);
+       return blockdev_direct_IO(rw, iocb, inode, iter, offset,
+                                 get_data_block);
 }
 
 static void f2fs_invalidate_data_page(struct page *page, unsigned int offset,
@@ -1061,6 +1069,11 @@ static int f2fs_set_data_page_dirty(struct page *page)
 
 static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
 {
+       struct inode *inode = mapping->host;
+
+       if (f2fs_has_inline_data(inode))
+               return 0;
+
        return generic_block_bmap(mapping, block, get_data_block);
 }
 
index 972fd0ef230f9aff12f877a4f056980ad07757f3..c3f148555c378cf3942fa2860ffb8b04b7e542ef 100644 (file)
@@ -268,6 +268,8 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
 {
        struct f2fs_inode *ri;
 
+       f2fs_wait_on_page_writeback(ipage, NODE);
+
        /* copy name info. to this inode page */
        ri = F2FS_INODE(ipage);
        ri->i_namelen = cpu_to_le32(name->len);
@@ -637,11 +639,17 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
        struct f2fs_dentry_block *dentry_blk = NULL;
        struct f2fs_dir_entry *de = NULL;
        struct page *dentry_page = NULL;
+       struct file_ra_state *ra = &file->f_ra;
        unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
        unsigned char d_type = DT_UNKNOWN;
 
        bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
 
+       /* readahead for multi pages of dir */
+       if (npages - n > 1 && !ra_has_index(ra, n))
+               page_cache_sync_readahead(inode->i_mapping, ra, file, n,
+                               min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
+
        for (; n < npages; n++) {
                dentry_page = get_lock_data_page(inode, n);
                if (IS_ERR(dentry_page))
index 2ecac8312359062268986adfe894f6320379bdd4..676a2c6ccec744d6962787a80743f478339a7c9e 100644 (file)
@@ -182,6 +182,8 @@ enum {
 
 #define F2FS_LINK_MAX          32000   /* maximum link count per file */
 
+#define MAX_DIR_RA_PAGES       4       /* maximum ra pages of dir */
+
 /* for in-memory extent cache entry */
 #define F2FS_MIN_EXTENT_LEN    16      /* minimum extent length */
 
@@ -218,6 +220,7 @@ struct f2fs_inode_info {
        nid_t i_xattr_nid;              /* node id that contains xattrs */
        unsigned long long xattr_ver;   /* cp version of xattr modification */
        struct extent_info ext;         /* in-memory extent cache entry */
+       struct dir_inode_entry *dirty_dir;      /* the pointer of dirty dir */
 };
 
 static inline void get_extent_info(struct extent_info *ext,
@@ -243,6 +246,7 @@ static inline void set_raw_extent(struct extent_info *ext,
 struct f2fs_nm_info {
        block_t nat_blkaddr;            /* base disk address of NAT */
        nid_t max_nid;                  /* maximum possible node ids */
+       nid_t available_nids;           /* maximum available node ids */
        nid_t next_scan_nid;            /* the next nid to be scanned */
        unsigned int ram_thresh;        /* control the memory footprint */
 
@@ -323,6 +327,15 @@ struct flush_cmd {
        int ret;
 };
 
+struct flush_cmd_control {
+       struct task_struct *f2fs_issue_flush;   /* flush thread */
+       wait_queue_head_t flush_wait_queue;     /* waiting queue for wake-up */
+       struct flush_cmd *issue_list;           /* list for command issue */
+       struct flush_cmd *dispatch_list;        /* list for command dispatch */
+       spinlock_t issue_lock;                  /* for issue list lock */
+       struct flush_cmd *issue_tail;           /* list tail of issue list */
+};
+
 struct f2fs_sm_info {
        struct sit_info *sit_info;              /* whole segment information */
        struct free_segmap_info *free_info;     /* free segment information */
@@ -353,12 +366,8 @@ struct f2fs_sm_info {
        unsigned int min_ipu_util;      /* in-place-update threshold */
 
        /* for flush command control */
-       struct task_struct *f2fs_issue_flush;   /* flush thread */
-       wait_queue_head_t flush_wait_queue;     /* waiting queue for wake-up */
-       struct flush_cmd *issue_list;           /* list for command issue */
-       struct flush_cmd *dispatch_list;        /* list for command dispatch */
-       spinlock_t issue_lock;                  /* for issue list lock */
-       struct flush_cmd *issue_tail;           /* list tail of issue list */
+       struct flush_cmd_control *cmd_control_info;
+
 };
 
 /*
@@ -958,6 +967,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr)
 enum {
        FI_NEW_INODE,           /* indicate newly allocated inode */
        FI_DIRTY_INODE,         /* indicate inode is dirty or not */
+       FI_DIRTY_DIR,           /* indicate directory has dirty pages */
        FI_INC_LINK,            /* need to increment i_nlink */
        FI_ACL_MODE,            /* indicate acl mode */
        FI_NO_ALLOC,            /* should not allocate any blocks */
@@ -1071,6 +1081,12 @@ static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi)
        ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
         (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
 
+/* get offset of first page in next direct node */
+#define PGOFS_OF_NEXT_DNODE(pgofs, fi)                         \
+       ((pgofs < ADDRS_PER_INODE(fi)) ? ADDRS_PER_INODE(fi) :  \
+       (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) /       \
+       ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
+
 /*
  * file.c
  */
@@ -1140,6 +1156,7 @@ f2fs_hash_t f2fs_dentry_hash(const char *, size_t);
 struct dnode_of_data;
 struct node_info;
 
+bool available_free_memory(struct f2fs_sb_info *, int);
 int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
 bool fsync_mark_done(struct f2fs_sb_info *, nid_t);
 void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
@@ -1176,9 +1193,12 @@ void destroy_node_manager_caches(void);
 void f2fs_balance_fs(struct f2fs_sb_info *);
 void f2fs_balance_fs_bg(struct f2fs_sb_info *);
 int f2fs_issue_flush(struct f2fs_sb_info *);
+int create_flush_cmd_control(struct f2fs_sb_info *);
+void destroy_flush_cmd_control(struct f2fs_sb_info *);
 void invalidate_blocks(struct f2fs_sb_info *, block_t);
 void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
 void clear_prefree_segments(struct f2fs_sb_info *);
+void discard_next_dnode(struct f2fs_sb_info *);
 int npages_for_summary_flush(struct f2fs_sb_info *);
 void allocate_new_segments(struct f2fs_sb_info *);
 struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
@@ -1221,7 +1241,6 @@ int get_valid_checkpoint(struct f2fs_sb_info *);
 void set_dirty_dir_page(struct inode *, struct page *);
 void add_dirty_dir_inode(struct inode *);
 void remove_dirty_dir_inode(struct inode *);
-struct inode *check_dirty_dir_inode(struct f2fs_sb_info *, nid_t);
 void sync_dirty_dir_inodes(struct f2fs_sb_info *);
 void write_checkpoint(struct f2fs_sb_info *, bool);
 void init_orphan_info(struct f2fs_sb_info *);
@@ -1391,5 +1410,6 @@ bool f2fs_may_inline(struct inode *);
 int f2fs_read_inline_data(struct inode *, struct page *);
 int f2fs_convert_inline_data(struct inode *, pgoff_t);
 int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
+void truncate_inline_data(struct inode *, u64);
 int recover_inline_data(struct inode *, struct page *);
 #endif
index 60e7d5448a1d8b705d6a30fb0ea266e0989d3201..37d0e1f512a993d07c75ba0b7e121855db939f3e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/compat.h>
 #include <linux/uaccess.h>
 #include <linux/mount.h>
+#include <linux/pagevec.h>
 
 #include "f2fs.h"
 #include "node.h"
@@ -194,6 +195,132 @@ out:
        return ret;
 }
 
+static pgoff_t __get_first_dirty_index(struct address_space *mapping,
+                                               pgoff_t pgofs, int whence)
+{
+       struct pagevec pvec;
+       int nr_pages;
+
+       if (whence != SEEK_DATA)
+               return 0;
+
+       /* find first dirty page index */
+       pagevec_init(&pvec, 0);
+       nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1);
+       pgofs = nr_pages ? pvec.pages[0]->index: LONG_MAX;
+       pagevec_release(&pvec);
+       return pgofs;
+}
+
+static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
+                                                       int whence)
+{
+       switch (whence) {
+       case SEEK_DATA:
+               if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
+                       (blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
+                       return true;
+               break;
+       case SEEK_HOLE:
+               if (blkaddr == NULL_ADDR)
+                       return true;
+               break;
+       }
+       return false;
+}
+
+static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
+{
+       struct inode *inode = file->f_mapping->host;
+       loff_t maxbytes = inode->i_sb->s_maxbytes;
+       struct dnode_of_data dn;
+       pgoff_t pgofs, end_offset, dirty;
+       loff_t data_ofs = offset;
+       loff_t isize;
+       int err = 0;
+
+       mutex_lock(&inode->i_mutex);
+
+       isize = i_size_read(inode);
+       if (offset >= isize)
+               goto fail;
+
+       /* handle inline data case */
+       if (f2fs_has_inline_data(inode)) {
+               if (whence == SEEK_HOLE)
+                       data_ofs = isize;
+               goto found;
+       }
+
+       pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT);
+
+       dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence);
+
+       for (; data_ofs < isize; data_ofs = pgofs << PAGE_CACHE_SHIFT) {
+               set_new_dnode(&dn, inode, NULL, NULL, 0);
+               err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA);
+               if (err && err != -ENOENT) {
+                       goto fail;
+               } else if (err == -ENOENT) {
+                       /* direct node is not exist */
+                       if (whence == SEEK_DATA) {
+                               pgofs = PGOFS_OF_NEXT_DNODE(pgofs,
+                                                       F2FS_I(inode));
+                               continue;
+                       } else {
+                               goto found;
+                       }
+               }
+
+               end_offset = IS_INODE(dn.node_page) ?
+                       ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
+
+               /* find data/hole in dnode block */
+               for (; dn.ofs_in_node < end_offset;
+                               dn.ofs_in_node++, pgofs++,
+                               data_ofs = pgofs << PAGE_CACHE_SHIFT) {
+                       block_t blkaddr;
+                       blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+
+                       if (__found_offset(blkaddr, dirty, pgofs, whence)) {
+                               f2fs_put_dnode(&dn);
+                               goto found;
+                       }
+               }
+               f2fs_put_dnode(&dn);
+       }
+
+       if (whence == SEEK_DATA)
+               goto fail;
+found:
+       if (whence == SEEK_HOLE && data_ofs > isize)
+               data_ofs = isize;
+       mutex_unlock(&inode->i_mutex);
+       return vfs_setpos(file, data_ofs, maxbytes);
+fail:
+       mutex_unlock(&inode->i_mutex);
+       return -ENXIO;
+}
+
+static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
+{
+       struct inode *inode = file->f_mapping->host;
+       loff_t maxbytes = inode->i_sb->s_maxbytes;
+
+       switch (whence) {
+       case SEEK_SET:
+       case SEEK_CUR:
+       case SEEK_END:
+               return generic_file_llseek_size(file, offset, whence,
+                                               maxbytes, i_size_read(inode));
+       case SEEK_DATA:
+       case SEEK_HOLE:
+               return f2fs_seek_block(file, offset, whence);
+       }
+
+       return -EINVAL;
+}
+
 static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        file_accessed(file);
@@ -242,6 +369,9 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
        unsigned offset = from & (PAGE_CACHE_SIZE - 1);
        struct page *page;
 
+       if (f2fs_has_inline_data(inode))
+               return truncate_inline_data(inode, from);
+
        if (!offset)
                return;
 
@@ -288,10 +418,7 @@ int truncate_blocks(struct inode *inode, u64 from)
                return err;
        }
 
-       if (IS_INODE(dn.node_page))
-               count = ADDRS_PER_INODE(F2FS_I(inode));
-       else
-               count = ADDRS_PER_BLOCK;
+       count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
 
        count -= dn.ofs_in_node;
        f2fs_bug_on(count < 0);
@@ -678,11 +805,11 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 #endif
 
 const struct file_operations f2fs_file_operations = {
-       .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .llseek         = f2fs_llseek,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .open           = generic_file_open,
        .mmap           = f2fs_file_mmap,
        .fsync          = f2fs_sync_file,
@@ -692,5 +819,5 @@ const struct file_operations f2fs_file_operations = {
        .compat_ioctl   = f2fs_compat_ioctl,
 #endif
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
 };
index 383db1fabcf4447637fd4153915e9512054b27ac..1bba5228c197443eb3a8ec893ab84d09462525e4 100644 (file)
@@ -81,8 +81,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
 
        f2fs_lock_op(sbi);
        ipage = get_node_page(sbi, inode->i_ino);
-       if (IS_ERR(ipage))
-               return PTR_ERR(ipage);
+       if (IS_ERR(ipage)) {
+               err = PTR_ERR(ipage);
+               goto out;
+       }
 
        /*
         * i_addr[0] is not used for inline data,
@@ -90,11 +92,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
         */
        set_new_dnode(&dn, inode, ipage, NULL, 0);
        err = f2fs_reserve_block(&dn, 0);
-       if (err) {
-               f2fs_unlock_op(sbi);
-               return err;
-       }
+       if (err)
+               goto out;
 
+       f2fs_wait_on_page_writeback(page, DATA);
        zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
 
        /* Copy the whole inline data block */
@@ -118,6 +119,7 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
 
        sync_inode_page(&dn);
        f2fs_put_dnode(&dn);
+out:
        f2fs_unlock_op(sbi);
        return err;
 }
@@ -132,7 +134,7 @@ int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size)
        else if (to_size <= MAX_INLINE_DATA)
                return 0;
 
-       page = grab_cache_page_write_begin(inode->i_mapping, 0, AOP_FLAG_NOFS);
+       page = grab_cache_page(inode->i_mapping, 0);
        if (!page)
                return -ENOMEM;
 
@@ -155,6 +157,7 @@ int f2fs_write_inline_data(struct inode *inode,
                return err;
        ipage = dn.inode_page;
 
+       f2fs_wait_on_page_writeback(ipage, NODE);
        zero_user_segment(ipage, INLINE_DATA_OFFSET,
                                 INLINE_DATA_OFFSET + MAX_INLINE_DATA);
        src_addr = kmap(page);
@@ -175,6 +178,26 @@ int f2fs_write_inline_data(struct inode *inode,
        return 0;
 }
 
+void truncate_inline_data(struct inode *inode, u64 from)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct page *ipage;
+
+       if (from >= MAX_INLINE_DATA)
+               return;
+
+       ipage = get_node_page(sbi, inode->i_ino);
+       if (IS_ERR(ipage))
+               return;
+
+       f2fs_wait_on_page_writeback(ipage, NODE);
+
+       zero_user_segment(ipage, INLINE_DATA_OFFSET + from,
+                               INLINE_DATA_OFFSET + MAX_INLINE_DATA);
+       set_page_dirty(ipage);
+       f2fs_put_page(ipage, 1);
+}
+
 int recover_inline_data(struct inode *inode, struct page *npage)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
@@ -199,6 +222,8 @@ process_inline:
                ipage = get_node_page(sbi, inode->i_ino);
                f2fs_bug_on(IS_ERR(ipage));
 
+               f2fs_wait_on_page_writeback(ipage, NODE);
+
                src_addr = inline_data_addr(npage);
                dst_addr = inline_data_addr(ipage);
                memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
@@ -210,6 +235,7 @@ process_inline:
        if (f2fs_has_inline_data(inode)) {
                ipage = get_node_page(sbi, inode->i_ino);
                f2fs_bug_on(IS_ERR(ipage));
+               f2fs_wait_on_page_writeback(ipage, NODE);
                zero_user_segment(ipage, INLINE_DATA_OFFSET,
                                 INLINE_DATA_OFFSET + MAX_INLINE_DATA);
                clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
index ee829d360468597f3619b5ef1b3719b1fd942516..adc622c6bdce68fd5363e1fb7f12e1d1bc9ccbbb 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/f2fs_fs.h>
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
+#include <linux/bitops.h>
 
 #include "f2fs.h"
 #include "node.h"
 void f2fs_set_inode_flags(struct inode *inode)
 {
        unsigned int flags = F2FS_I(inode)->i_flags;
-
-       inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE |
-                       S_NOATIME | S_DIRSYNC);
+       unsigned int new_fl = 0;
 
        if (flags & FS_SYNC_FL)
-               inode->i_flags |= S_SYNC;
+               new_fl |= S_SYNC;
        if (flags & FS_APPEND_FL)
-               inode->i_flags |= S_APPEND;
+               new_fl |= S_APPEND;
        if (flags & FS_IMMUTABLE_FL)
-               inode->i_flags |= S_IMMUTABLE;
+               new_fl |= S_IMMUTABLE;
        if (flags & FS_NOATIME_FL)
-               inode->i_flags |= S_NOATIME;
+               new_fl |= S_NOATIME;
        if (flags & FS_DIRSYNC_FL)
-               inode->i_flags |= S_DIRSYNC;
+               new_fl |= S_DIRSYNC;
+       set_mask_bits(&inode->i_flags,
+                       S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl);
 }
 
 static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
@@ -294,4 +295,5 @@ void f2fs_evict_inode(struct inode *inode)
        sb_end_intwrite(inode->i_sb);
 no_delete:
        clear_inode(inode);
+       invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
 }
index a161e955c4c808f01ba69b5c93eaf4943344b316..059aaf5dda2b3173480de3f4687f2b9584b52980 100644 (file)
 static struct kmem_cache *nat_entry_slab;
 static struct kmem_cache *free_nid_slab;
 
-static inline bool available_free_memory(struct f2fs_nm_info *nm_i, int type)
+bool available_free_memory(struct f2fs_sb_info *sbi, int type)
 {
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct sysinfo val;
        unsigned long mem_size = 0;
+       bool res = false;
 
        si_meminfo(&val);
-       if (type == FREE_NIDS)
-               mem_size = nm_i->fcnt * sizeof(struct free_nid);
-       else if (type == NAT_ENTRIES)
-               mem_size += nm_i->nat_cnt * sizeof(struct nat_entry);
-       mem_size >>= 12;
-
-       /* give 50:50 memory for free nids and nat caches respectively */
-       return (mem_size < ((val.totalram * nm_i->ram_thresh) >> 11));
+       /* give 25%, 25%, 50% memory for each components respectively */
+       if (type == FREE_NIDS) {
+               mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> 12;
+               res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
+       } else if (type == NAT_ENTRIES) {
+               mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12;
+               res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
+       } else if (type == DIRTY_DENTS) {
+               mem_size = get_pages(sbi, F2FS_DIRTY_DENTS);
+               res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1);
+       }
+       return res;
 }
 
 static void clear_node_page_dirty(struct page *page)
@@ -179,9 +185,7 @@ retry:
                        write_unlock(&nm_i->nat_tree_lock);
                        goto retry;
                }
-               nat_set_blkaddr(e, le32_to_cpu(ne->block_addr));
-               nat_set_ino(e, le32_to_cpu(ne->ino));
-               nat_set_version(e, ne->version);
+               node_info_from_raw_nat(&e->ni, ne);
        }
        write_unlock(&nm_i->nat_tree_lock);
 }
@@ -243,7 +247,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
 
-       if (available_free_memory(nm_i, NAT_ENTRIES))
+       if (available_free_memory(sbi, NAT_ENTRIES))
                return 0;
 
        write_lock(&nm_i->nat_tree_lock);
@@ -849,8 +853,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
        if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)))
                return ERR_PTR(-EPERM);
 
-       page = grab_cache_page_write_begin(NODE_MAPPING(sbi),
-                                       dn->nid, AOP_FLAG_NOFS);
+       page = grab_cache_page(NODE_MAPPING(sbi), dn->nid);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -867,6 +870,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
        new_ni.ino = dn->inode->i_ino;
        set_node_addr(sbi, &new_ni, NEW_ADDR, false);
 
+       f2fs_wait_on_page_writeback(page, NODE);
        fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
        set_cold_node(dn->inode, page);
        SetPageUptodate(page);
@@ -946,8 +950,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
        struct page *page;
        int err;
 repeat:
-       page = grab_cache_page_write_begin(NODE_MAPPING(sbi),
-                                       nid, AOP_FLAG_NOFS);
+       page = grab_cache_page(NODE_MAPPING(sbi), nid);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -1227,10 +1230,7 @@ static int f2fs_write_node_page(struct page *page,
        return 0;
 
 redirty_out:
-       dec_page_count(sbi, F2FS_DIRTY_NODES);
-       wbc->pages_skipped++;
-       account_page_redirty(page);
-       set_page_dirty(page);
+       redirty_page_for_writepage(wbc, page);
        return AOP_WRITEPAGE_ACTIVATE;
 }
 
@@ -1315,13 +1315,14 @@ static void __del_from_free_nid_list(struct f2fs_nm_info *nm_i,
        radix_tree_delete(&nm_i->free_nid_root, i->nid);
 }
 
-static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
+static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
 {
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct free_nid *i;
        struct nat_entry *ne;
        bool allocated = false;
 
-       if (!available_free_memory(nm_i, FREE_NIDS))
+       if (!available_free_memory(sbi, FREE_NIDS))
                return -1;
 
        /* 0 nid should not be used */
@@ -1374,9 +1375,10 @@ static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
                kmem_cache_free(free_nid_slab, i);
 }
 
-static void scan_nat_page(struct f2fs_nm_info *nm_i,
+static void scan_nat_page(struct f2fs_sb_info *sbi,
                        struct page *nat_page, nid_t start_nid)
 {
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct f2fs_nat_block *nat_blk = page_address(nat_page);
        block_t blk_addr;
        int i;
@@ -1391,7 +1393,7 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i,
                blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
                f2fs_bug_on(blk_addr == NEW_ADDR);
                if (blk_addr == NULL_ADDR) {
-                       if (add_free_nid(nm_i, start_nid, true) < 0)
+                       if (add_free_nid(sbi, start_nid, true) < 0)
                                break;
                }
        }
@@ -1415,7 +1417,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
        while (1) {
                struct page *page = get_current_nat_page(sbi, nid);
 
-               scan_nat_page(nm_i, page, nid);
+               scan_nat_page(sbi, page, nid);
                f2fs_put_page(page, 1);
 
                nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK));
@@ -1435,7 +1437,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
                block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr);
                nid = le32_to_cpu(nid_in_journal(sum, i));
                if (addr == NULL_ADDR)
-                       add_free_nid(nm_i, nid, true);
+                       add_free_nid(sbi, nid, true);
                else
                        remove_free_nid(nm_i, nid);
        }
@@ -1452,7 +1454,7 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct free_nid *i = NULL;
 retry:
-       if (unlikely(sbi->total_valid_node_count + 1 >= nm_i->max_nid))
+       if (unlikely(sbi->total_valid_node_count + 1 > nm_i->available_nids))
                return false;
 
        spin_lock(&nm_i->free_nid_list_lock);
@@ -1512,7 +1514,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
        spin_lock(&nm_i->free_nid_list_lock);
        i = __lookup_free_nid_list(nm_i, nid);
        f2fs_bug_on(!i || i->state != NID_ALLOC);
-       if (!available_free_memory(nm_i, FREE_NIDS)) {
+       if (!available_free_memory(sbi, FREE_NIDS)) {
                __del_from_free_nid_list(nm_i, i);
                need_free = true;
        } else {
@@ -1534,7 +1536,7 @@ void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
        clear_node_page_dirty(page);
 }
 
-void recover_inline_xattr(struct inode *inode, struct page *page)
+static void recover_inline_xattr(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        void *src_addr, *dst_addr;
@@ -1559,6 +1561,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page)
        src_addr = inline_xattr_addr(page);
        inline_size = inline_xattr_size(inode);
 
+       f2fs_wait_on_page_writeback(ipage, NODE);
        memcpy(dst_addr, src_addr, inline_size);
 
        update_inode(inode, ipage);
@@ -1614,6 +1617,11 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
        struct node_info old_ni, new_ni;
        struct page *ipage;
 
+       get_node_info(sbi, ino, &old_ni);
+
+       if (unlikely(old_ni.blk_addr != NULL_ADDR))
+               return -EINVAL;
+
        ipage = grab_cache_page(NODE_MAPPING(sbi), ino);
        if (!ipage)
                return -ENOMEM;
@@ -1621,7 +1629,6 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
        /* Should not use this inode  from free nid list */
        remove_free_nid(NM_I(sbi), ino);
 
-       get_node_info(sbi, ino, &old_ni);
        SetPageUptodate(ipage);
        fill_node_footer(ipage, ino, ino, 0, true);
 
@@ -1758,9 +1765,7 @@ retry:
                        write_unlock(&nm_i->nat_tree_lock);
                        goto retry;
                }
-               nat_set_blkaddr(ne, le32_to_cpu(raw_ne.block_addr));
-               nat_set_ino(ne, le32_to_cpu(raw_ne.ino));
-               nat_set_version(ne, raw_ne.version);
+               node_info_from_raw_nat(&ne->ni, &raw_ne);
                __set_nat_cache_dirty(nm_i, ne);
                write_unlock(&nm_i->nat_tree_lock);
        }
@@ -1793,7 +1798,6 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
                nid_t nid;
                struct f2fs_nat_entry raw_ne;
                int offset = -1;
-               block_t new_blkaddr;
 
                if (nat_get_blkaddr(ne) == NEW_ADDR)
                        continue;
@@ -1829,11 +1833,7 @@ to_nat_page:
                f2fs_bug_on(!nat_blk);
                raw_ne = nat_blk->entries[nid - start_nid];
 flush_now:
-               new_blkaddr = nat_get_blkaddr(ne);
-
-               raw_ne.ino = cpu_to_le32(nat_get_ino(ne));
-               raw_ne.block_addr = cpu_to_le32(new_blkaddr);
-               raw_ne.version = nat_get_version(ne);
+               raw_nat_from_node_info(&raw_ne, &ne->ni);
 
                if (offset < 0) {
                        nat_blk->entries[nid - start_nid] = raw_ne;
@@ -1843,7 +1843,7 @@ flush_now:
                }
 
                if (nat_get_blkaddr(ne) == NULL_ADDR &&
-                               add_free_nid(NM_I(sbi), nid, false) <= 0) {
+                               add_free_nid(sbi, nid, false) <= 0) {
                        write_lock(&nm_i->nat_tree_lock);
                        __del_from_nat_cache(nm_i, ne);
                        write_unlock(&nm_i->nat_tree_lock);
@@ -1871,8 +1871,10 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
        nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1;
        nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg);
 
+       nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks;
+
        /* not used nids: 0, node, meta, (and root counted as valid node) */
-       nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks - 3;
+       nm_i->available_nids = nm_i->max_nid - 3;
        nm_i->fcnt = 0;
        nm_i->nat_cnt = 0;
        nm_i->ram_thresh = DEF_RAM_THRESHOLD;
index 5decc1a375f0071ca00a81bd5d891b507e86ffba..4ee29d506f8cb8e336ef1c21885f5846d6c98f14 100644 (file)
@@ -75,9 +75,18 @@ static inline void node_info_from_raw_nat(struct node_info *ni,
        ni->version = raw_ne->version;
 }
 
-enum nid_type {
+static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne,
+                                               struct node_info *ni)
+{
+       raw_ne->ino = cpu_to_le32(ni->ino);
+       raw_ne->block_addr = cpu_to_le32(ni->blk_addr);
+       raw_ne->version = ni->version;
+}
+
+enum mem_type {
        FREE_NIDS,      /* indicates the free nid list */
-       NAT_ENTRIES     /* indicates the cached nat entry */
+       NAT_ENTRIES,    /* indicates the cached nat entry */
+       DIRTY_DENTS     /* indicates dirty dentry pages */
 };
 
 /*
@@ -263,7 +272,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
 {
        struct f2fs_node *rn = F2FS_NODE(p);
 
-       wait_on_page_writeback(p);
+       f2fs_wait_on_page_writeback(p, NODE);
 
        if (i)
                rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
index b1ae89f0f44e53878a7e37aea926c4e3a201c2a3..e950a2f50ac1173537ba5492626bd5f7940fadd1 100644 (file)
@@ -46,15 +46,17 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
        struct inode *dir, *einode;
        int err = 0;
 
-       dir = check_dirty_dir_inode(F2FS_SB(inode->i_sb), pino);
-       if (!dir) {
-               dir = f2fs_iget(inode->i_sb, pino);
-               if (IS_ERR(dir)) {
-                       err = PTR_ERR(dir);
-                       goto out;
-               }
-               set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
+       dir = f2fs_iget(inode->i_sb, pino);
+       if (IS_ERR(dir)) {
+               err = PTR_ERR(dir);
+               goto out;
+       }
+
+       if (is_inode_flag_set(F2FS_I(dir), FI_DIRTY_DIR)) {
+               iput(dir);
+       } else {
                add_dirty_dir_inode(dir);
+               set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
        }
 
        name.len = le32_to_cpu(raw_inode->i_namelen);
@@ -73,7 +75,8 @@ retry:
                einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino));
                if (IS_ERR(einode)) {
                        WARN_ON(1);
-                       if (PTR_ERR(einode) == -ENOENT)
+                       err = PTR_ERR(einode);
+                       if (err == -ENOENT)
                                err = -EEXIST;
                        goto out_unmap_put;
                }
@@ -299,10 +302,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                goto out;
 
        start = start_bidx_of_node(ofs_of_node(page), fi);
-       if (IS_INODE(page))
-               end = start + ADDRS_PER_INODE(fi);
-       else
-               end = start + ADDRS_PER_BLOCK;
+       end = start + ADDRS_PER_PAGE(page, fi);
 
        f2fs_lock_op(sbi);
 
index 085f548be7a31e53539f844f29c0ea74f87c2a83..2ecbffb91f370f6a9aa4e58c73aad0cbf3d9d501 100644 (file)
@@ -200,20 +200,20 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
 static int issue_flush_thread(void *data)
 {
        struct f2fs_sb_info *sbi = data;
-       struct f2fs_sm_info *sm_i = SM_I(sbi);
-       wait_queue_head_t *q = &sm_i->flush_wait_queue;
+       struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
+       wait_queue_head_t *q = &fcc->flush_wait_queue;
 repeat:
        if (kthread_should_stop())
                return 0;
 
-       spin_lock(&sm_i->issue_lock);
-       if (sm_i->issue_list) {
-               sm_i->dispatch_list = sm_i->issue_list;
-               sm_i->issue_list = sm_i->issue_tail = NULL;
+       spin_lock(&fcc->issue_lock);
+       if (fcc->issue_list) {
+               fcc->dispatch_list = fcc->issue_list;
+               fcc->issue_list = fcc->issue_tail = NULL;
        }
-       spin_unlock(&sm_i->issue_lock);
+       spin_unlock(&fcc->issue_lock);
 
-       if (sm_i->dispatch_list) {
+       if (fcc->dispatch_list) {
                struct bio *bio = bio_alloc(GFP_NOIO, 0);
                struct flush_cmd *cmd, *next;
                int ret;
@@ -221,42 +221,42 @@ repeat:
                bio->bi_bdev = sbi->sb->s_bdev;
                ret = submit_bio_wait(WRITE_FLUSH, bio);
 
-               for (cmd = sm_i->dispatch_list; cmd; cmd = next) {
+               for (cmd = fcc->dispatch_list; cmd; cmd = next) {
                        cmd->ret = ret;
                        next = cmd->next;
                        complete(&cmd->wait);
                }
-               sm_i->dispatch_list = NULL;
+               bio_put(bio);
+               fcc->dispatch_list = NULL;
        }
 
-       wait_event_interruptible(*q, kthread_should_stop() || sm_i->issue_list);
+       wait_event_interruptible(*q,
+                       kthread_should_stop() || fcc->issue_list);
        goto repeat;
 }
 
 int f2fs_issue_flush(struct f2fs_sb_info *sbi)
 {
-       struct f2fs_sm_info *sm_i = SM_I(sbi);
+       struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info;
        struct flush_cmd *cmd;
        int ret;
 
        if (!test_opt(sbi, FLUSH_MERGE))
                return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL);
 
-       cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC);
-       cmd->next = NULL;
-       cmd->ret = 0;
+       cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC | __GFP_ZERO);
        init_completion(&cmd->wait);
 
-       spin_lock(&sm_i->issue_lock);
-       if (sm_i->issue_list)
-               sm_i->issue_tail->next = cmd;
+       spin_lock(&fcc->issue_lock);
+       if (fcc->issue_list)
+               fcc->issue_tail->next = cmd;
        else
-               sm_i->issue_list = cmd;
-       sm_i->issue_tail = cmd;
-       spin_unlock(&sm_i->issue_lock);
+               fcc->issue_list = cmd;
+       fcc->issue_tail = cmd;
+       spin_unlock(&fcc->issue_lock);
 
-       if (!sm_i->dispatch_list)
-               wake_up(&sm_i->flush_wait_queue);
+       if (!fcc->dispatch_list)
+               wake_up(&fcc->flush_wait_queue);
 
        wait_for_completion(&cmd->wait);
        ret = cmd->ret;
@@ -264,6 +264,40 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi)
        return ret;
 }
 
+int create_flush_cmd_control(struct f2fs_sb_info *sbi)
+{
+       dev_t dev = sbi->sb->s_bdev->bd_dev;
+       struct flush_cmd_control *fcc;
+       int err = 0;
+
+       fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
+       if (!fcc)
+               return -ENOMEM;
+       spin_lock_init(&fcc->issue_lock);
+       init_waitqueue_head(&fcc->flush_wait_queue);
+       fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
+                               "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
+       if (IS_ERR(fcc->f2fs_issue_flush)) {
+               err = PTR_ERR(fcc->f2fs_issue_flush);
+               kfree(fcc);
+               return err;
+       }
+       sbi->sm_info->cmd_control_info = fcc;
+
+       return err;
+}
+
+void destroy_flush_cmd_control(struct f2fs_sb_info *sbi)
+{
+       struct flush_cmd_control *fcc =
+                               sbi->sm_info->cmd_control_info;
+
+       if (fcc && fcc->f2fs_issue_flush)
+               kthread_stop(fcc->f2fs_issue_flush);
+       kfree(fcc);
+       sbi->sm_info->cmd_control_info = NULL;
+}
+
 static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                enum dirty_type dirty_type)
 {
@@ -336,13 +370,26 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
        mutex_unlock(&dirty_i->seglist_lock);
 }
 
-static void f2fs_issue_discard(struct f2fs_sb_info *sbi,
+static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
                                block_t blkstart, block_t blklen)
 {
        sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart);
        sector_t len = SECTOR_FROM_BLOCK(sbi, blklen);
-       blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
        trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
+       return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
+}
+
+void discard_next_dnode(struct f2fs_sb_info *sbi)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+       block_t blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
+
+       if (f2fs_issue_discard(sbi, blkaddr, 1)) {
+               struct page *page = grab_meta_page(sbi, blkaddr);
+               /* zero-filled page */
+               set_page_dirty(page);
+               f2fs_put_page(page, 1);
+       }
 }
 
 static void add_discard_addrs(struct f2fs_sb_info *sbi,
@@ -1832,7 +1879,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
-       dev_t dev = sbi->sb->s_bdev->bd_dev;
        struct f2fs_sm_info *sm_info;
        int err;
 
@@ -1860,14 +1906,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
        sm_info->nr_discards = 0;
        sm_info->max_discards = 0;
 
-       if (test_opt(sbi, FLUSH_MERGE)) {
-               spin_lock_init(&sm_info->issue_lock);
-               init_waitqueue_head(&sm_info->flush_wait_queue);
-
-               sm_info->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
-                               "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
-               if (IS_ERR(sm_info->f2fs_issue_flush))
-                       return PTR_ERR(sm_info->f2fs_issue_flush);
+       if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) {
+               err = create_flush_cmd_control(sbi);
+               if (err)
+                       return err;
        }
 
        err = build_sit_info(sbi);
@@ -1976,10 +2018,10 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
 void destroy_segment_manager(struct f2fs_sb_info *sbi)
 {
        struct f2fs_sm_info *sm_info = SM_I(sbi);
+
        if (!sm_info)
                return;
-       if (sm_info->f2fs_issue_flush)
-               kthread_stop(sm_info->f2fs_issue_flush);
+       destroy_flush_cmd_control(sbi);
        destroy_dirty_segmap(sbi);
        destroy_curseg(sbi);
        destroy_free_segmap(sbi);
index c756923a7302cc6dc144e108a11a4d2ceb5800ed..b2b18637cb9eff9a959167b1b0d88dbe0a5116ed 100644 (file)
@@ -514,7 +514,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
 
-       if (!(root->d_sb->s_flags & MS_RDONLY) && test_opt(sbi, BG_GC))
+       if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC))
                seq_printf(seq, ",background_gc=%s", "on");
        else
                seq_printf(seq, ",background_gc=%s", "off");
@@ -542,7 +542,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, ",disable_ext_identify");
        if (test_opt(sbi, INLINE_DATA))
                seq_puts(seq, ",inline_data");
-       if (test_opt(sbi, FLUSH_MERGE))
+       if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE))
                seq_puts(seq, ",flush_merge");
        seq_printf(seq, ",active_logs=%u", sbi->active_logs);
 
@@ -594,6 +594,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct f2fs_mount_info org_mount_opt;
        int err, active_logs;
+       bool need_restart_gc = false;
+       bool need_stop_gc = false;
 
        sync_filesystem(sb);
 
@@ -611,7 +613,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 
        /*
         * Previous and new state of filesystem is RO,
-        * so no point in checking GC conditions.
+        * so skip checking GC and FLUSH_MERGE conditions.
         */
        if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY))
                goto skip;
@@ -625,18 +627,40 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
                if (sbi->gc_thread) {
                        stop_gc_thread(sbi);
                        f2fs_sync_fs(sb, 1);
+                       need_restart_gc = true;
                }
        } else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) {
                err = start_gc_thread(sbi);
                if (err)
                        goto restore_opts;
+               need_stop_gc = true;
+       }
+
+       /*
+        * We stop issue flush thread if FS is mounted as RO
+        * or if flush_merge is not passed in mount option.
+        */
+       if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
+               destroy_flush_cmd_control(sbi);
+       } else if (test_opt(sbi, FLUSH_MERGE) &&
+                                       !sbi->sm_info->cmd_control_info) {
+               err = create_flush_cmd_control(sbi);
+               if (err)
+                       goto restore_gc;
        }
 skip:
        /* Update the POSIXACL Flag */
         sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
        return 0;
-
+restore_gc:
+       if (need_restart_gc) {
+               if (start_gc_thread(sbi))
+                       f2fs_msg(sbi->sb, KERN_WARNING,
+                               "background gc thread is stop");
+       } else if (need_stop_gc) {
+               stop_gc_thread(sbi);
+       }
 restore_opts:
        sbi->mount_opt = org_mount_opt;
        sbi->active_logs = active_logs;
index 503c2451131e5ba78b26fcce09870b0ca1a3d9bb..1f546b4b6b61913691d34ca11eaa8f61205fb5d5 100644 (file)
@@ -26,7 +26,7 @@
 #include "xattr.h"
 
 static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list,
-               size_t list_size, const char *name, size_t name_len, int type)
+               size_t list_size, const char *name, size_t len, int type)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
        int total_len, prefix_len = 0;
@@ -53,11 +53,11 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list,
                return -EINVAL;
        }
 
-       total_len = prefix_len + name_len + 1;
+       total_len = prefix_len + len + 1;
        if (list && total_len <= list_size) {
                memcpy(list, prefix, prefix_len);
-               memcpy(list + prefix_len, name, name_len);
-               list[prefix_len + name_len] = '\0';
+               memcpy(list + prefix_len, name, len);
+               list[prefix_len + len] = '\0';
        }
        return total_len;
 }
@@ -108,11 +108,12 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name,
        if (strcmp(name, "") == 0)
                return -EINVAL;
 
-       return f2fs_setxattr(dentry->d_inode, type, name, value, size, NULL);
+       return f2fs_setxattr(dentry->d_inode, type, name,
+                                       value, size, NULL, flags);
 }
 
 static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list,
-               size_t list_size, const char *name, size_t name_len, int type)
+               size_t list_size, const char *name, size_t len, int type)
 {
        const char *xname = F2FS_SYSTEM_ADVISE_PREFIX;
        size_t size;
@@ -155,9 +156,10 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
 }
 
 #ifdef CONFIG_F2FS_FS_SECURITY
-static int __f2fs_setxattr(struct inode *inode, int name_index,
-                       const char *name, const void *value, size_t value_len,
-                       struct page *ipage);
+static int __f2fs_setxattr(struct inode *inode, int index,
+                       const char *name, const void *value, size_t size,
+                       struct page *ipage, int);
+
 static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
                void *page)
 {
@@ -167,7 +169,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
        for (xattr = xattr_array; xattr->name != NULL; xattr++) {
                err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
                                xattr->name, xattr->value,
-                               xattr->value_len, (struct page *)page);
+                               xattr->value_len, (struct page *)page, 0);
                if (err < 0)
                        break;
        }
@@ -241,26 +243,26 @@ const struct xattr_handler *f2fs_xattr_handlers[] = {
        NULL,
 };
 
-static inline const struct xattr_handler *f2fs_xattr_handler(int name_index)
+static inline const struct xattr_handler *f2fs_xattr_handler(int index)
 {
        const struct xattr_handler *handler = NULL;
 
-       if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map))
-               handler = f2fs_xattr_handler_map[name_index];
+       if (index > 0 && index < ARRAY_SIZE(f2fs_xattr_handler_map))
+               handler = f2fs_xattr_handler_map[index];
        return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int name_index,
-                                       size_t name_len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
+                                       size_t len, const char *name)
 {
        struct f2fs_xattr_entry *entry;
 
        list_for_each_xattr(entry, base_addr) {
-               if (entry->e_name_index != name_index)
+               if (entry->e_name_index != index)
                        continue;
-               if (entry->e_name_len != name_len)
+               if (entry->e_name_len != len)
                        continue;
-               if (!memcmp(entry->e_name, name, name_len))
+               if (!memcmp(entry->e_name, name, len))
                        break;
        }
        return entry;
@@ -347,6 +349,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
 
                if (ipage) {
                        inline_addr = inline_xattr_addr(ipage);
+                       f2fs_wait_on_page_writeback(ipage, NODE);
                } else {
                        page = get_node_page(sbi, inode->i_ino);
                        if (IS_ERR(page)) {
@@ -354,6 +357,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                                return PTR_ERR(page);
                        }
                        inline_addr = inline_xattr_addr(page);
+                       f2fs_wait_on_page_writeback(page, NODE);
                }
                memcpy(inline_addr, txattr_addr, inline_size);
                f2fs_put_page(page, 1);
@@ -374,6 +378,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                        return PTR_ERR(xpage);
                }
                f2fs_bug_on(new_nid);
+               f2fs_wait_on_page_writeback(xpage, NODE);
        } else {
                struct dnode_of_data dn;
                set_new_dnode(&dn, inode, NULL, NULL, new_nid);
@@ -396,42 +401,43 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
        return 0;
 }
 
-int f2fs_getxattr(struct inode *inode, int name_index, const char *name,
+int f2fs_getxattr(struct inode *inode, int index, const char *name,
                void *buffer, size_t buffer_size)
 {
        struct f2fs_xattr_entry *entry;
        void *base_addr;
        int error = 0;
-       size_t value_len, name_len;
+       size_t size, len;
 
        if (name == NULL)
                return -EINVAL;
-       name_len = strlen(name);
-       if (name_len > F2FS_NAME_LEN)
+
+       len = strlen(name);
+       if (len > F2FS_NAME_LEN)
                return -ERANGE;
 
        base_addr = read_all_xattrs(inode, NULL);
        if (!base_addr)
                return -ENOMEM;
 
-       entry = __find_xattr(base_addr, name_index, name_len, name);
+       entry = __find_xattr(base_addr, index, len, name);
        if (IS_XATTR_LAST_ENTRY(entry)) {
                error = -ENODATA;
                goto cleanup;
        }
 
-       value_len = le16_to_cpu(entry->e_value_size);
+       size = le16_to_cpu(entry->e_value_size);
 
-       if (buffer && value_len > buffer_size) {
+       if (buffer && size > buffer_size) {
                error = -ERANGE;
                goto cleanup;
        }
 
        if (buffer) {
                char *pval = entry->e_name + entry->e_name_len;
-               memcpy(buffer, pval, value_len);
+               memcpy(buffer, pval, size);
        }
-       error = value_len;
+       error = size;
 
 cleanup:
        kzfree(base_addr);
@@ -475,15 +481,15 @@ cleanup:
        return error;
 }
 
-static int __f2fs_setxattr(struct inode *inode, int name_index,
-                       const char *name, const void *value, size_t value_len,
-                       struct page *ipage)
+static int __f2fs_setxattr(struct inode *inode, int index,
+                       const char *name, const void *value, size_t size,
+                       struct page *ipage, int flags)
 {
        struct f2fs_inode_info *fi = F2FS_I(inode);
        struct f2fs_xattr_entry *here, *last;
        void *base_addr;
        int found, newsize;
-       size_t name_len;
+       size_t len;
        __u32 new_hsize;
        int error = -ENOMEM;
 
@@ -491,11 +497,11 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
                return -EINVAL;
 
        if (value == NULL)
-               value_len = 0;
+               size = 0;
 
-       name_len = strlen(name);
+       len = strlen(name);
 
-       if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode))
+       if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN(inode))
                return -ERANGE;
 
        base_addr = read_all_xattrs(inode, ipage);
@@ -503,16 +509,23 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
                goto exit;
 
        /* find entry with wanted name. */
-       here = __find_xattr(base_addr, name_index, name_len, name);
+       here = __find_xattr(base_addr, index, len, name);
 
        found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
-       last = here;
 
+       if ((flags & XATTR_REPLACE) && !found) {
+               error = -ENODATA;
+               goto exit;
+       } else if ((flags & XATTR_CREATE) && found) {
+               error = -EEXIST;
+               goto exit;
+       }
+
+       last = here;
        while (!IS_XATTR_LAST_ENTRY(last))
                last = XATTR_NEXT_ENTRY(last);
 
-       newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) +
-                       name_len + value_len);
+       newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
 
        /* 1. Check space */
        if (value) {
@@ -555,12 +568,12 @@ static int __f2fs_setxattr(struct inode *inode, int name_index,
                 * We just write new entry.
                 */
                memset(last, 0, newsize);
-               last->e_name_index = name_index;
-               last->e_name_len = name_len;
-               memcpy(last->e_name, name, name_len);
-               pval = last->e_name + name_len;
-               memcpy(pval, value, value_len);
-               last->e_value_size = cpu_to_le16(value_len);
+               last->e_name_index = index;
+               last->e_name_len = len;
+               memcpy(last->e_name, name, len);
+               pval = last->e_name + len;
+               memcpy(pval, value, size);
+               last->e_value_size = cpu_to_le16(size);
                new_hsize += newsize;
        }
 
@@ -583,8 +596,9 @@ exit:
        return error;
 }
 
-int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
-                       const void *value, size_t value_len, struct page *ipage)
+int f2fs_setxattr(struct inode *inode, int index, const char *name,
+                               const void *value, size_t size,
+                               struct page *ipage, int flags)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        int err;
@@ -594,7 +608,7 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
        f2fs_lock_op(sbi);
        /* protect xattr_ver */
        down_write(&F2FS_I(inode)->i_sem);
-       err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage);
+       err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
        up_write(&F2FS_I(inode)->i_sem);
        f2fs_unlock_op(sbi);
 
index b21d9ebdeff39efdf64485116bf53ce17263bb7e..34ab7dbcf5e3f0867b9afefb0d1e3a4952a247bb 100644 (file)
@@ -114,18 +114,18 @@ extern const struct xattr_handler f2fs_xattr_security_handler;
 extern const struct xattr_handler *f2fs_xattr_handlers[];
 
 extern int f2fs_setxattr(struct inode *, int, const char *,
-                               const void *, size_t, struct page *);
+                               const void *, size_t, struct page *, int);
 extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t);
 extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
 #else
 
 #define f2fs_xattr_handlers    NULL
-static inline int f2fs_setxattr(struct inode *inode, int name_index,
-               const char *name, const void *value, size_t value_len)
+static inline int f2fs_setxattr(struct inode *inode, int index,
+               const char *name, const void *value, size_t size, int flags)
 {
        return -EOPNOTSUPP;
 }
-static inline int f2fs_getxattr(struct inode *inode, int name_index,
+static inline int f2fs_getxattr(struct inode *inode, int index,
                const char *name, void *buffer, size_t buffer_size)
 {
        return -EOPNOTSUPP;
index 9b104f543056238016c683ef822046a784169f50..85f79a89e7474658c8c552cfe027e72ff048d542 100644 (file)
@@ -170,10 +170,10 @@ int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 
 const struct file_operations fat_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .release        = fat_file_release,
        .unlocked_ioctl = fat_generic_ioctl,
index b3361fe2bcb590183150fac820d6ffbc1f46e9f9..385cce464e822a3a9de91113d1b314482670965f 100644 (file)
@@ -185,12 +185,13 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
 }
 
 static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
-                            const struct iovec *iov,
-                            loff_t offset, unsigned long nr_segs)
+                            struct iov_iter *iter,
+                            loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
        if (rw == WRITE) {
@@ -203,7 +204,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
                 *
                 * Return 0, and fallback to normal buffered write.
                 */
-               loff_t size = offset + iov_length(iov, nr_segs);
+               loff_t size = offset + count;
                if (MSDOS_I(inode)->mmu_private < size)
                        return 0;
        }
@@ -212,10 +213,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
         * FAT need to use the DIO_LOCKING for avoiding the race
         * condition of fat_get_block() and ->truncate().
         */
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                fat_get_block);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, fat_get_block);
        if (ret < 0 && (rw & WRITE))
-               fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
+               fat_write_failed(mapping, offset + count);
 
        return ret;
 }
index 8f294cfac69749024c2c2e19d4b156755130e9ed..66923fe3176e49b03617e2f5477bb8e05fc89dc3 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -44,15 +44,10 @@ static void *alloc_fdmem(size_t size)
        return vmalloc(size);
 }
 
-static void free_fdmem(void *ptr)
-{
-       is_vmalloc_addr(ptr) ? vfree(ptr) : kfree(ptr);
-}
-
 static void __free_fdtable(struct fdtable *fdt)
 {
-       free_fdmem(fdt->fd);
-       free_fdmem(fdt->open_fds);
+       kvfree(fdt->fd);
+       kvfree(fdt->open_fds);
        kfree(fdt);
 }
 
@@ -130,7 +125,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
        return fdt;
 
 out_arr:
-       free_fdmem(fdt->fd);
+       kvfree(fdt->fd);
 out_fdt:
        kfree(fdt);
 out:
index a374f5033e97bab814977f8375f5c8cb1c899228..f8cc881fbbfb3ff7fca0ea2bc589f0ab8a9f48db 100644 (file)
@@ -175,6 +175,12 @@ struct file *alloc_file(struct path *path, fmode_t mode,
        file->f_path = *path;
        file->f_inode = path->dentry->d_inode;
        file->f_mapping = path->dentry->d_inode->i_mapping;
+       if ((mode & FMODE_READ) &&
+            likely(fop->read || fop->aio_read || fop->read_iter))
+               mode |= FMODE_CAN_READ;
+       if ((mode & FMODE_WRITE) &&
+            likely(fop->write || fop->aio_write || fop->write_iter))
+               mode |= FMODE_CAN_WRITE;
        file->f_mode = mode;
        file->f_op = fop;
        if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
index a0b0855d00a985c78288074f9adc813d14addfe1..205e0d5d530752532bcb045b4630ddee0ded7ffd 100644 (file)
@@ -348,7 +348,7 @@ int __init fuse_ctl_init(void)
        return register_filesystem(&fuse_ctl_fs_type);
 }
 
-void fuse_ctl_cleanup(void)
+void __exit fuse_ctl_cleanup(void)
 {
        unregister_filesystem(&fuse_ctl_fs_type);
 }
index 13b691a8a7d2ea4403161213486538dadf75a217..966ace8b243fa39796fbdd788c4d83ebd6024217 100644 (file)
@@ -94,8 +94,10 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
        loff_t pos = 0;
        struct iovec iov = { .iov_base = buf, .iov_len = count };
        struct fuse_io_priv io = { .async = 0, .file = file };
+       struct iov_iter ii;
+       iov_iter_init(&ii, READ, &iov, 1, count);
 
-       return fuse_direct_io(&io, &iov, 1, count, &pos, FUSE_DIO_CUSE);
+       return fuse_direct_io(&io, &ii, &pos, FUSE_DIO_CUSE);
 }
 
 static ssize_t cuse_write(struct file *file, const char __user *buf,
@@ -104,12 +106,14 @@ static ssize_t cuse_write(struct file *file, const char __user *buf,
        loff_t pos = 0;
        struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
        struct fuse_io_priv io = { .async = 0, .file = file };
+       struct iov_iter ii;
+       iov_iter_init(&ii, WRITE, &iov, 1, count);
 
        /*
         * No locking or generic_write_checks(), the server is
         * responsible for locking and sanity checks.
         */
-       return fuse_direct_io(&io, &iov, 1, count, &pos,
+       return fuse_direct_io(&io, &ii, &pos,
                              FUSE_DIO_WRITE | FUSE_DIO_CUSE);
 }
 
index 5b4e035b364cc604d68e72411337ef061a766fea..42198359fa1b472557e44f325e9f55c305237e99 100644 (file)
@@ -679,6 +679,14 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
        return create_new_entry(fc, req, dir, entry, S_IFLNK);
 }
 
+static inline void fuse_update_ctime(struct inode *inode)
+{
+       if (!IS_NOCMTIME(inode)) {
+               inode->i_ctime = current_fs_time(inode->i_sb);
+               mark_inode_dirty_sync(inode);
+       }
+}
+
 static int fuse_unlink(struct inode *dir, struct dentry *entry)
 {
        int err;
@@ -713,6 +721,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
                fuse_invalidate_attr(inode);
                fuse_invalidate_attr(dir);
                fuse_invalidate_entry_cache(entry);
+               fuse_update_ctime(inode);
        } else if (err == -EINTR)
                fuse_invalidate_entry(entry);
        return err;
@@ -743,23 +752,26 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
        return err;
 }
 
-static int fuse_rename(struct inode *olddir, struct dentry *oldent,
-                      struct inode *newdir, struct dentry *newent)
+static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
+                             struct inode *newdir, struct dentry *newent,
+                             unsigned int flags, int opcode, size_t argsize)
 {
        int err;
-       struct fuse_rename_in inarg;
+       struct fuse_rename2_in inarg;
        struct fuse_conn *fc = get_fuse_conn(olddir);
-       struct fuse_req *req = fuse_get_req_nopages(fc);
+       struct fuse_req *req;
 
+       req = fuse_get_req_nopages(fc);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
-       memset(&inarg, 0, sizeof(inarg));
+       memset(&inarg, 0, argsize);
        inarg.newdir = get_node_id(newdir);
-       req->in.h.opcode = FUSE_RENAME;
+       inarg.flags = flags;
+       req->in.h.opcode = opcode;
        req->in.h.nodeid = get_node_id(olddir);
        req->in.numargs = 3;
-       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].size = argsize;
        req->in.args[0].value = &inarg;
        req->in.args[1].size = oldent->d_name.len + 1;
        req->in.args[1].value = oldent->d_name.name;
@@ -771,15 +783,22 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        if (!err) {
                /* ctime changes */
                fuse_invalidate_attr(oldent->d_inode);
+               fuse_update_ctime(oldent->d_inode);
+
+               if (flags & RENAME_EXCHANGE) {
+                       fuse_invalidate_attr(newent->d_inode);
+                       fuse_update_ctime(newent->d_inode);
+               }
 
                fuse_invalidate_attr(olddir);
                if (olddir != newdir)
                        fuse_invalidate_attr(newdir);
 
                /* newent will end up negative */
-               if (newent->d_inode) {
+               if (!(flags & RENAME_EXCHANGE) && newent->d_inode) {
                        fuse_invalidate_attr(newent->d_inode);
                        fuse_invalidate_entry_cache(newent);
+                       fuse_update_ctime(newent->d_inode);
                }
        } else if (err == -EINTR) {
                /* If request was interrupted, DEITY only knows if the
@@ -795,6 +814,36 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        return err;
 }
 
+static int fuse_rename(struct inode *olddir, struct dentry *oldent,
+                      struct inode *newdir, struct dentry *newent)
+{
+       return fuse_rename_common(olddir, oldent, newdir, newent, 0,
+                                 FUSE_RENAME, sizeof(struct fuse_rename_in));
+}
+
+static int fuse_rename2(struct inode *olddir, struct dentry *oldent,
+                       struct inode *newdir, struct dentry *newent,
+                       unsigned int flags)
+{
+       struct fuse_conn *fc = get_fuse_conn(olddir);
+       int err;
+
+       if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
+               return -EINVAL;
+
+       if (fc->no_rename2 || fc->minor < 23)
+               return -EINVAL;
+
+       err = fuse_rename_common(olddir, oldent, newdir, newent, flags,
+                                FUSE_RENAME2, sizeof(struct fuse_rename2_in));
+       if (err == -ENOSYS) {
+               fc->no_rename2 = 1;
+               err = -EINVAL;
+       }
+       return err;
+
+}
+
 static int fuse_link(struct dentry *entry, struct inode *newdir,
                     struct dentry *newent)
 {
@@ -829,6 +878,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
                inc_nlink(inode);
                spin_unlock(&fc->lock);
                fuse_invalidate_attr(inode);
+               fuse_update_ctime(inode);
        } else if (err == -EINTR) {
                fuse_invalidate_attr(inode);
        }
@@ -846,6 +896,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
                attr->size = i_size_read(inode);
                attr->mtime = inode->i_mtime.tv_sec;
                attr->mtimensec = inode->i_mtime.tv_nsec;
+               attr->ctime = inode->i_ctime.tv_sec;
+               attr->ctimensec = inode->i_ctime.tv_nsec;
        }
 
        stat->dev = inode->i_sb->s_dev;
@@ -1504,7 +1556,7 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
 }
 
 static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
-                          bool trust_local_mtime)
+                          bool trust_local_cmtime)
 {
        unsigned ivalid = iattr->ia_valid;
 
@@ -1523,13 +1575,18 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
                if (!(ivalid & ATTR_ATIME_SET))
                        arg->valid |= FATTR_ATIME_NOW;
        }
-       if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_mtime)) {
+       if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) {
                arg->valid |= FATTR_MTIME;
                arg->mtime = iattr->ia_mtime.tv_sec;
                arg->mtimensec = iattr->ia_mtime.tv_nsec;
-               if (!(ivalid & ATTR_MTIME_SET) && !trust_local_mtime)
+               if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime)
                        arg->valid |= FATTR_MTIME_NOW;
        }
+       if ((ivalid & ATTR_CTIME) && trust_local_cmtime) {
+               arg->valid |= FATTR_CTIME;
+               arg->ctime = iattr->ia_ctime.tv_sec;
+               arg->ctimensec = iattr->ia_ctime.tv_nsec;
+       }
 }
 
 /*
@@ -1597,39 +1654,38 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req,
 /*
  * Flush inode->i_mtime to the server
  */
-int fuse_flush_mtime(struct file *file, bool nofail)
+int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
 {
-       struct inode *inode = file->f_mapping->host;
-       struct fuse_inode *fi = get_fuse_inode(inode);
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_req *req = NULL;
+       struct fuse_req *req;
        struct fuse_setattr_in inarg;
        struct fuse_attr_out outarg;
        int err;
 
-       if (nofail) {
-               req = fuse_get_req_nofail_nopages(fc, file);
-       } else {
-               req = fuse_get_req_nopages(fc);
-               if (IS_ERR(req))
-                       return PTR_ERR(req);
-       }
+       req = fuse_get_req_nopages(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        memset(&outarg, 0, sizeof(outarg));
 
-       inarg.valid |= FATTR_MTIME;
+       inarg.valid = FATTR_MTIME;
        inarg.mtime = inode->i_mtime.tv_sec;
        inarg.mtimensec = inode->i_mtime.tv_nsec;
-
+       if (fc->minor >= 23) {
+               inarg.valid |= FATTR_CTIME;
+               inarg.ctime = inode->i_ctime.tv_sec;
+               inarg.ctimensec = inode->i_ctime.tv_nsec;
+       }
+       if (ff) {
+               inarg.valid |= FATTR_FH;
+               inarg.fh = ff->fh;
+       }
        fuse_setattr_fill(fc, req, inode, &inarg, &outarg);
        fuse_request_send(fc, req);
        err = req->out.h.error;
        fuse_put_request(fc, req);
 
-       if (!err)
-               clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
-
        return err;
 }
 
@@ -1653,7 +1709,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
        bool is_wb = fc->writeback_cache;
        loff_t oldsize;
        int err;
-       bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode);
+       bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode);
 
        if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
                attr->ia_valid |= ATTR_FORCE;
@@ -1678,11 +1734,13 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
        if (is_truncate) {
                fuse_set_nowrite(inode);
                set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+               if (trust_local_cmtime && attr->ia_size != inode->i_size)
+                       attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
        }
 
        memset(&inarg, 0, sizeof(inarg));
        memset(&outarg, 0, sizeof(outarg));
-       iattr_to_fattr(attr, &inarg, trust_local_mtime);
+       iattr_to_fattr(attr, &inarg, trust_local_cmtime);
        if (file) {
                struct fuse_file *ff = file->private_data;
                inarg.valid |= FATTR_FH;
@@ -1711,9 +1769,12 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
 
        spin_lock(&fc->lock);
        /* the kernel maintains i_mtime locally */
-       if (trust_local_mtime && (attr->ia_valid & ATTR_MTIME)) {
-               inode->i_mtime = attr->ia_mtime;
-               clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
+       if (trust_local_cmtime) {
+               if (attr->ia_valid & ATTR_MTIME)
+                       inode->i_mtime = attr->ia_mtime;
+               if (attr->ia_valid & ATTR_CTIME)
+                       inode->i_ctime = attr->ia_ctime;
+               /* FIXME: clear I_DIRTY_SYNC? */
        }
 
        fuse_change_attributes_common(inode, &outarg.attr,
@@ -1810,8 +1871,10 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
                fc->no_setxattr = 1;
                err = -EOPNOTSUPP;
        }
-       if (!err)
+       if (!err) {
                fuse_invalidate_attr(inode);
+               fuse_update_ctime(inode);
+       }
        return err;
 }
 
@@ -1941,20 +2004,11 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
                fc->no_removexattr = 1;
                err = -EOPNOTSUPP;
        }
-       if (!err)
+       if (!err) {
                fuse_invalidate_attr(inode);
-       return err;
-}
-
-static int fuse_update_time(struct inode *inode, struct timespec *now,
-                           int flags)
-{
-       if (flags & S_MTIME) {
-               inode->i_mtime = *now;
-               set_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state);
-               BUG_ON(!S_ISREG(inode->i_mode));
+               fuse_update_ctime(inode);
        }
-       return 0;
+       return err;
 }
 
 static const struct inode_operations fuse_dir_inode_operations = {
@@ -1964,6 +2018,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
        .unlink         = fuse_unlink,
        .rmdir          = fuse_rmdir,
        .rename         = fuse_rename,
+       .rename2        = fuse_rename2,
        .link           = fuse_link,
        .setattr        = fuse_setattr,
        .create         = fuse_create,
@@ -1996,7 +2051,6 @@ static const struct inode_operations fuse_common_inode_operations = {
        .getxattr       = fuse_getxattr,
        .listxattr      = fuse_listxattr,
        .removexattr    = fuse_removexattr,
-       .update_time    = fuse_update_time,
 };
 
 static const struct inode_operations fuse_symlink_inode_operations = {
index 13f8bdec5110d1a7db12b2a262bb5e2ecb0e4f82..9828cf227f8af07ee9399ec09ba87c71b1bfe5ad 100644 (file)
@@ -223,6 +223,8 @@ void fuse_finish_open(struct inode *inode, struct file *file)
                i_size_write(inode, 0);
                spin_unlock(&fc->lock);
                fuse_invalidate_attr(inode);
+               if (fc->writeback_cache)
+                       file_update_time(file);
        }
        if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache)
                fuse_link_write_file(file);
@@ -232,18 +234,26 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
        int err;
+       bool lock_inode = (file->f_flags & O_TRUNC) &&
+                         fc->atomic_o_trunc &&
+                         fc->writeback_cache;
 
        err = generic_file_open(inode, file);
        if (err)
                return err;
 
+       if (lock_inode)
+               mutex_lock(&inode->i_mutex);
+
        err = fuse_do_open(fc, get_node_id(inode), file, isdir);
-       if (err)
-               return err;
 
-       fuse_finish_open(inode, file);
+       if (!err)
+               fuse_finish_open(inode, file);
 
-       return 0;
+       if (lock_inode)
+               mutex_unlock(&inode->i_mutex);
+
+       return err;
 }
 
 static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode)
@@ -314,10 +324,7 @@ static int fuse_release(struct inode *inode, struct file *file)
 
        /* see fuse_vma_close() for !writeback_cache case */
        if (fc->writeback_cache)
-               filemap_write_and_wait(file->f_mapping);
-
-       if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state))
-               fuse_flush_mtime(file, true);
+               write_inode_now(inode, 1);
 
        fuse_release_common(file, FUSE_RELEASE);
 
@@ -439,7 +446,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
        if (fc->no_flush)
                return 0;
 
-       err = filemap_write_and_wait(file->f_mapping);
+       err = write_inode_now(inode, 1);
        if (err)
                return err;
 
@@ -480,13 +487,6 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
        if (is_bad_inode(inode))
                return -EIO;
 
-       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (err)
-               return err;
-
-       if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
-               return 0;
-
        mutex_lock(&inode->i_mutex);
 
        /*
@@ -494,17 +494,17 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
         * wait for all outstanding writes, before sending the FSYNC
         * request.
         */
-       err = write_inode_now(inode, 0);
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
        if (err)
                goto out;
 
        fuse_sync_writes(inode);
+       err = sync_inode_metadata(inode, 1);
+       if (err)
+               goto out;
 
-       if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) {
-               int err = fuse_flush_mtime(file, false);
-               if (err)
-                       goto out;
-       }
+       if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
+               goto out;
 
        req = fuse_get_req_nopages(fc);
        if (IS_ERR(req)) {
@@ -933,8 +933,7 @@ out:
        return err;
 }
 
-static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
-                                 unsigned long nr_segs, loff_t pos)
+static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -945,14 +944,14 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
         * i_size is up to date).
         */
        if (fc->auto_inval_data ||
-           (pos + iov_length(iov, nr_segs) > i_size_read(inode))) {
+           (iocb->ki_pos + iov_iter_count(to) > i_size_read(inode))) {
                int err;
                err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
                if (err)
                        return err;
        }
 
-       return generic_file_aio_read(iocb, iov, nr_segs, pos);
+       return generic_file_read_iter(iocb, to);
 }
 
 static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
@@ -1183,19 +1182,17 @@ static ssize_t fuse_perform_write(struct file *file,
        return res > 0 ? res : err;
 }
 
-static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                                  unsigned long nr_segs, loff_t pos)
+static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
-       size_t count = 0;
-       size_t ocount = 0;
+       size_t count = iov_iter_count(from);
        ssize_t written = 0;
        ssize_t written_buffered = 0;
        struct inode *inode = mapping->host;
        ssize_t err;
-       struct iov_iter i;
        loff_t endbyte = 0;
+       loff_t pos = iocb->ki_pos;
 
        if (get_fuse_conn(inode)->writeback_cache) {
                /* Update size (EOF optimization) and mode (SUID clearing) */
@@ -1203,17 +1200,9 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                if (err)
                        return err;
 
-               return generic_file_aio_write(iocb, iov, nr_segs, pos);
+               return generic_file_write_iter(iocb, from);
        }
 
-       WARN_ON(iocb->ki_pos != pos);
-
-       ocount = 0;
-       err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
-       if (err)
-               return err;
-
-       count = ocount;
        mutex_lock(&inode->i_mutex);
 
        /* We can write back this queue in page reclaim */
@@ -1226,6 +1215,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (count == 0)
                goto out;
 
+       iov_iter_truncate(from, count);
        err = file_remove_suid(file);
        if (err)
                goto out;
@@ -1235,16 +1225,13 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                goto out;
 
        if (file->f_flags & O_DIRECT) {
-               written = generic_file_direct_write(iocb, iov, &nr_segs, pos, 
-                                                   count, ocount);
-               if (written < 0 || written == count)
+               written = generic_file_direct_write(iocb, from, pos);
+               if (written < 0 || !iov_iter_count(from))
                        goto out;
 
                pos += written;
-               count -= written;
 
-               iov_iter_init(&i, iov, nr_segs, count, written);
-               written_buffered = fuse_perform_write(file, mapping, &i, pos);
+               written_buffered = fuse_perform_write(file, mapping, from, pos);
                if (written_buffered < 0) {
                        err = written_buffered;
                        goto out;
@@ -1263,8 +1250,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                written += written_buffered;
                iocb->ki_pos = pos + written_buffered;
        } else {
-               iov_iter_init(&i, iov, nr_segs, count, 0);
-               written = fuse_perform_write(file, mapping, &i, pos);
+               written = fuse_perform_write(file, mapping, from, pos);
                if (written >= 0)
                        iocb->ki_pos = pos + written;
        }
@@ -1302,7 +1288,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
        size_t nbytes = 0;  /* # bytes already packed in req */
 
        /* Special case for kernel I/O: can copy directly into the buffer */
-       if (segment_eq(get_fs(), KERNEL_DS)) {
+       if (ii->type & ITER_KVEC) {
                unsigned long user_addr = fuse_get_user_addr(ii);
                size_t frag_size = fuse_get_frag_size(ii, *nbytesp);
 
@@ -1318,35 +1304,26 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
 
        while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
                unsigned npages;
-               unsigned long user_addr = fuse_get_user_addr(ii);
-               unsigned offset = user_addr & ~PAGE_MASK;
-               size_t frag_size = fuse_get_frag_size(ii, *nbytesp - nbytes);
-               int ret;
-
+               size_t start;
                unsigned n = req->max_pages - req->num_pages;
-               frag_size = min_t(size_t, frag_size, n << PAGE_SHIFT);
-
-               npages = (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-               npages = clamp(npages, 1U, n);
-
-               ret = get_user_pages_fast(user_addr, npages, !write,
-                                         &req->pages[req->num_pages]);
+               ssize_t ret = iov_iter_get_pages(ii,
+                                       &req->pages[req->num_pages],
+                                       n * PAGE_SIZE, &start);
                if (ret < 0)
                        return ret;
 
-               npages = ret;
-               frag_size = min_t(size_t, frag_size,
-                                 (npages << PAGE_SHIFT) - offset);
-               iov_iter_advance(ii, frag_size);
+               iov_iter_advance(ii, ret);
+               nbytes += ret;
+
+               ret += start;
+               npages = (ret + PAGE_SIZE - 1) / PAGE_SIZE;
 
-               req->page_descs[req->num_pages].offset = offset;
+               req->page_descs[req->num_pages].offset = start;
                fuse_page_descs_length_init(req, req->num_pages, npages);
 
                req->num_pages += npages;
                req->page_descs[req->num_pages - 1].length -=
-                       (npages << PAGE_SHIFT) - offset - frag_size;
-
-               nbytes += frag_size;
+                       (PAGE_SIZE - ret) & (PAGE_SIZE - 1);
        }
 
        if (write)
@@ -1361,24 +1338,11 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
 
 static inline int fuse_iter_npages(const struct iov_iter *ii_p)
 {
-       struct iov_iter ii = *ii_p;
-       int npages = 0;
-
-       while (iov_iter_count(&ii) && npages < FUSE_MAX_PAGES_PER_REQ) {
-               unsigned long user_addr = fuse_get_user_addr(&ii);
-               unsigned offset = user_addr & ~PAGE_MASK;
-               size_t frag_size = iov_iter_single_seg_count(&ii);
-
-               npages += (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-               iov_iter_advance(&ii, frag_size);
-       }
-
-       return min(npages, FUSE_MAX_PAGES_PER_REQ);
+       return iov_iter_npages(ii_p, FUSE_MAX_PAGES_PER_REQ);
 }
 
-ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
-                      unsigned long nr_segs, size_t count, loff_t *ppos,
-                      int flags)
+ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
+                      loff_t *ppos, int flags)
 {
        int write = flags & FUSE_DIO_WRITE;
        int cuse = flags & FUSE_DIO_CUSE;
@@ -1388,18 +1352,16 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
        struct fuse_conn *fc = ff->fc;
        size_t nmax = write ? fc->max_write : fc->max_read;
        loff_t pos = *ppos;
+       size_t count = iov_iter_count(iter);
        pgoff_t idx_from = pos >> PAGE_CACHE_SHIFT;
        pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT;
        ssize_t res = 0;
        struct fuse_req *req;
-       struct iov_iter ii;
-
-       iov_iter_init(&ii, iov, nr_segs, count, 0);
 
        if (io->async)
-               req = fuse_get_req_for_background(fc, fuse_iter_npages(&ii));
+               req = fuse_get_req_for_background(fc, fuse_iter_npages(iter));
        else
-               req = fuse_get_req(fc, fuse_iter_npages(&ii));
+               req = fuse_get_req(fc, fuse_iter_npages(iter));
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -1415,7 +1377,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
                size_t nres;
                fl_owner_t owner = current->files;
                size_t nbytes = min(count, nmax);
-               int err = fuse_get_user_pages(req, &ii, &nbytes, write);
+               int err = fuse_get_user_pages(req, iter, &nbytes, write);
                if (err) {
                        res = err;
                        break;
@@ -1445,9 +1407,9 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
                        fuse_put_request(fc, req);
                        if (io->async)
                                req = fuse_get_req_for_background(fc,
-                                       fuse_iter_npages(&ii));
+                                       fuse_iter_npages(iter));
                        else
-                               req = fuse_get_req(fc, fuse_iter_npages(&ii));
+                               req = fuse_get_req(fc, fuse_iter_npages(iter));
                        if (IS_ERR(req))
                                break;
                }
@@ -1462,9 +1424,8 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
 EXPORT_SYMBOL_GPL(fuse_direct_io);
 
 static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
-                                 const struct iovec *iov,
-                                 unsigned long nr_segs, loff_t *ppos,
-                                 size_t count)
+                                 struct iov_iter *iter,
+                                 loff_t *ppos)
 {
        ssize_t res;
        struct file *file = io->file;
@@ -1473,7 +1434,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
        if (is_bad_inode(inode))
                return -EIO;
 
-       res = fuse_direct_io(io, iov, nr_segs, count, ppos, 0);
+       res = fuse_direct_io(io, iter, ppos, 0);
 
        fuse_invalidate_attr(inode);
 
@@ -1485,22 +1446,26 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf,
 {
        struct fuse_io_priv io = { .async = 0, .file = file };
        struct iovec iov = { .iov_base = buf, .iov_len = count };
-       return __fuse_direct_read(&io, &iov, 1, ppos, count);
+       struct iov_iter ii;
+       iov_iter_init(&ii, READ, &iov, 1, count);
+       return __fuse_direct_read(&io, &ii, ppos);
 }
 
 static ssize_t __fuse_direct_write(struct fuse_io_priv *io,
-                                  const struct iovec *iov,
-                                  unsigned long nr_segs, loff_t *ppos)
+                                  struct iov_iter *iter,
+                                  loff_t *ppos)
 {
        struct file *file = io->file;
        struct inode *inode = file_inode(file);
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        ssize_t res;
 
+
        res = generic_write_checks(file, ppos, &count, 0);
-       if (!res)
-               res = fuse_direct_io(io, iov, nr_segs, count, ppos,
-                                    FUSE_DIO_WRITE);
+       if (!res) {
+               iov_iter_truncate(iter, count);
+               res = fuse_direct_io(io, iter, ppos, FUSE_DIO_WRITE);
+       }
 
        fuse_invalidate_attr(inode);
 
@@ -1514,13 +1479,15 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
        struct inode *inode = file_inode(file);
        ssize_t res;
        struct fuse_io_priv io = { .async = 0, .file = file };
+       struct iov_iter ii;
+       iov_iter_init(&ii, WRITE, &iov, 1, count);
 
        if (is_bad_inode(inode))
                return -EIO;
 
        /* Don't allow parallel writes to the same file */
        mutex_lock(&inode->i_mutex);
-       res = __fuse_direct_write(&io, &iov, 1, ppos);
+       res = __fuse_direct_write(&io, &ii, ppos);
        if (res > 0)
                fuse_write_update_size(inode, *ppos);
        mutex_unlock(&inode->i_mutex);
@@ -1659,13 +1626,13 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req)
        fuse_writepage_free(fc, req);
 }
 
-static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc,
-                                            struct fuse_inode *fi)
+static struct fuse_file *__fuse_write_file_get(struct fuse_conn *fc,
+                                              struct fuse_inode *fi)
 {
        struct fuse_file *ff = NULL;
 
        spin_lock(&fc->lock);
-       if (!WARN_ON(list_empty(&fi->write_files))) {
+       if (!list_empty(&fi->write_files)) {
                ff = list_entry(fi->write_files.next, struct fuse_file,
                                write_entry);
                fuse_file_get(ff);
@@ -1675,6 +1642,29 @@ static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc,
        return ff;
 }
 
+static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc,
+                                            struct fuse_inode *fi)
+{
+       struct fuse_file *ff = __fuse_write_file_get(fc, fi);
+       WARN_ON(!ff);
+       return ff;
+}
+
+int fuse_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_inode *fi = get_fuse_inode(inode);
+       struct fuse_file *ff;
+       int err;
+
+       ff = __fuse_write_file_get(fc, fi);
+       err = fuse_flush_times(inode, ff);
+       if (ff)
+               fuse_file_put(ff, 0);
+
+       return err;
+}
+
 static int fuse_writepage_locked(struct page *page)
 {
        struct address_space *mapping = page->mapping;
@@ -2281,7 +2271,6 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl)
                struct fuse_file *ff = file->private_data;
 
                /* emulate flock with POSIX locks */
-               fl->fl_owner = (fl_owner_t) file;
                ff->flock = true;
                err = fuse_setlk(file, fl, 1);
        }
@@ -2352,7 +2341,7 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
        if (!bytes)
                return 0;
 
-       iov_iter_init(&ii, iov, nr_segs, bytes, 0);
+       iov_iter_init(&ii, to_user ? READ : WRITE, iov, nr_segs, bytes);
 
        while (iov_iter_count(&ii)) {
                struct page *page = pages[page_idx++];
@@ -2874,8 +2863,8 @@ static inline loff_t fuse_round_up(loff_t off)
 }
 
 static ssize_t
-fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
-                       loff_t offset, unsigned long nr_segs)
+fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
+                       loff_t offset)
 {
        ssize_t ret = 0;
        struct file *file = iocb->ki_filp;
@@ -2884,7 +2873,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
        loff_t pos = 0;
        struct inode *inode;
        loff_t i_size;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        struct fuse_io_priv *io;
 
        pos = offset;
@@ -2899,6 +2888,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
                if (offset >= i_size)
                        return 0;
                count = min_t(loff_t, count, fuse_round_up(i_size - offset));
+               iov_iter_truncate(iter, count);
        }
 
        io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
@@ -2928,9 +2918,9 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
                io->async = false;
 
        if (rw == WRITE)
-               ret = __fuse_direct_write(io, iov, nr_segs, &pos);
+               ret = __fuse_direct_write(io, iter, &pos);
        else
-               ret = __fuse_direct_read(io, iov, nr_segs, &pos, count);
+               ret = __fuse_direct_read(io, iter, &pos);
 
        if (io->async) {
                fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
@@ -2972,6 +2962,9 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
        bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) ||
                           (mode & FALLOC_FL_PUNCH_HOLE);
 
+       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+               return -EOPNOTSUPP;
+
        if (fc->no_fallocate)
                return -EOPNOTSUPP;
 
@@ -3017,12 +3010,8 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
        if (!(mode & FALLOC_FL_KEEP_SIZE)) {
                bool changed = fuse_write_update_size(inode, offset + length);
 
-               if (changed && fc->writeback_cache) {
-                       struct fuse_inode *fi = get_fuse_inode(inode);
-
-                       inode->i_mtime = current_fs_time(inode->i_sb);
-                       set_bit(FUSE_I_MTIME_DIRTY, &fi->state);
-               }
+               if (changed && fc->writeback_cache)
+                       file_update_time(file);
        }
 
        if (mode & FALLOC_FL_PUNCH_HOLE)
@@ -3042,10 +3031,10 @@ out:
 
 static const struct file_operations fuse_file_operations = {
        .llseek         = fuse_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = fuse_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = fuse_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = fuse_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = fuse_file_write_iter,
        .mmap           = fuse_file_mmap,
        .open           = fuse_open,
        .flush          = fuse_flush,
index a257ed8ebee6c6db62339e1a8d3f2f87479310ea..e8e47a6ab5186be8df5889d65df28bc92bf8c97d 100644 (file)
@@ -119,8 +119,6 @@ enum {
        FUSE_I_INIT_RDPLUS,
        /** An operation changing file size is in progress  */
        FUSE_I_SIZE_UNSTABLE,
-       /** i_mtime has been updated locally; a flush to userspace needed */
-       FUSE_I_MTIME_DIRTY,
 };
 
 struct fuse_conn;
@@ -544,6 +542,9 @@ struct fuse_conn {
        /** Is fallocate not implemented by fs? */
        unsigned no_fallocate:1;
 
+       /** Is rename with flags implemented by fs? */
+       unsigned no_rename2:1;
+
        /** Use enhanced/automatic page cache invalidation. */
        unsigned auto_inval_data:1;
 
@@ -725,7 +726,7 @@ int fuse_dev_init(void);
 void fuse_dev_cleanup(void);
 
 int fuse_ctl_init(void);
-void fuse_ctl_cleanup(void);
+void __exit fuse_ctl_cleanup(void);
 
 /**
  * Allocate a request
@@ -879,9 +880,8 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
 /** CUSE pass fuse_direct_io() a file which f_mapping->host is not from FUSE */
 #define FUSE_DIO_CUSE  (1 << 1)
 
-ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
-                      unsigned long nr_segs, size_t count, loff_t *ppos,
-                      int flags);
+ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
+                      loff_t *ppos, int flags);
 long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
                   unsigned int flags);
 long fuse_ioctl_common(struct file *file, unsigned int cmd,
@@ -891,7 +891,8 @@ int fuse_dev_release(struct inode *inode, struct file *file);
 
 bool fuse_write_update_size(struct inode *inode, loff_t pos);
 
-int fuse_flush_mtime(struct file *file, bool nofail);
+int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
+int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
 
 int fuse_do_setattr(struct inode *inode, struct iattr *attr,
                    struct file *file);
index 8d611696fcad303dfe4137a2ff9bc9e1d2a5b97d..754dcf23de8abf10ceee81926f022731b810cb54 100644 (file)
@@ -175,9 +175,9 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
        if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) {
                inode->i_mtime.tv_sec   = attr->mtime;
                inode->i_mtime.tv_nsec  = attr->mtimensec;
+               inode->i_ctime.tv_sec   = attr->ctime;
+               inode->i_ctime.tv_nsec  = attr->ctimensec;
        }
-       inode->i_ctime.tv_sec   = attr->ctime;
-       inode->i_ctime.tv_nsec  = attr->ctimensec;
 
        if (attr->blksize != 0)
                inode->i_blkbits = ilog2(attr->blksize);
@@ -256,6 +256,8 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
        inode->i_size = attr->size;
        inode->i_mtime.tv_sec  = attr->mtime;
        inode->i_mtime.tv_nsec = attr->mtimensec;
+       inode->i_ctime.tv_sec  = attr->ctime;
+       inode->i_ctime.tv_nsec = attr->ctimensec;
        if (S_ISREG(inode->i_mode)) {
                fuse_init_common(inode);
                fuse_init_file_inode(inode);
@@ -303,7 +305,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
 
        if ((inode->i_state & I_NEW)) {
                inode->i_flags |= S_NOATIME;
-               if (!fc->writeback_cache || !S_ISREG(inode->i_mode))
+               if (!fc->writeback_cache || !S_ISREG(attr->mode))
                        inode->i_flags |= S_NOCMTIME;
                inode->i_generation = generation;
                inode->i_data.backing_dev_info = &fc->bdi;
@@ -788,6 +790,7 @@ static const struct super_operations fuse_super_operations = {
        .alloc_inode    = fuse_alloc_inode,
        .destroy_inode  = fuse_destroy_inode,
        .evict_inode    = fuse_evict_inode,
+       .write_inode    = fuse_write_inode,
        .drop_inode     = generic_delete_inode,
        .remount_fs     = fuse_remount_fs,
        .put_super      = fuse_put_super,
@@ -890,6 +893,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->async_dio = 1;
                        if (arg->flags & FUSE_WRITEBACK_CACHE)
                                fc->writeback_cache = 1;
+                       if (arg->time_gran && arg->time_gran <= 1000000000)
+                               fc->sb->s_time_gran = arg->time_gran;
+                       else
+                               fc->sb->s_time_gran = 1000000000;
+
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -996,7 +1004,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (sb->s_flags & MS_MANDLOCK)
                goto err;
 
-       sb->s_flags &= ~MS_NOSEC;
+       sb->s_flags &= ~(MS_NOSEC | MS_I_VERSION);
 
        if (!parse_fuse_opt((char *) data, &d, is_bdev))
                goto err;
index ce62dcac90b6ffbe8d3bbb20806a16a922291873..910838951d66c375d9c7a2b38fd4a225c45245b0 100644 (file)
@@ -1041,8 +1041,7 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
 
 
 static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
-                             const struct iovec *iov, loff_t offset,
-                             unsigned long nr_segs)
+                             struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
@@ -1082,7 +1081,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
         */
        if (mapping->nrpages) {
                loff_t lstart = offset & (PAGE_CACHE_SIZE - 1);
-               loff_t len = iov_length(iov, nr_segs);
+               loff_t len = iov_iter_count(iter);
                loff_t end = PAGE_ALIGN(offset + len) - 1;
 
                rv = 0;
@@ -1097,9 +1096,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
                        truncate_inode_pages_range(mapping, lstart, end);
        }
 
-       rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                                 offset, nr_segs, gfs2_get_block_direct,
-                                 NULL, NULL, 0);
+       rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
+                                 iter, offset,
+                                 gfs2_get_block_direct, NULL, NULL, 0);
 out:
        gfs2_glock_dq(&gh);
        gfs2_holder_uninit(&gh);
index 80d67253623cb20c16f9e47b9fef3633fcee64c3..01b4c5b1bff8ddd152a6b93ac3b5249d3d0a49a8 100644 (file)
@@ -684,7 +684,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
 }
 
 /**
- * gfs2_file_aio_write - Perform a write to a file
+ * gfs2_file_write_iter - Perform a write to a file
  * @iocb: The io context
  * @iov: The data to write
  * @nr_segs: Number of @iov segments
@@ -697,11 +697,9 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
  *
  */
 
-static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                                  unsigned long nr_segs, loff_t pos)
+static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
-       size_t writesize = iov_length(iov, nr_segs);
        struct gfs2_inode *ip = GFS2_I(file_inode(file));
        int ret;
 
@@ -709,7 +707,7 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (ret)
                return ret;
 
-       gfs2_size_hint(file, pos, writesize);
+       gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));
 
        if (file->f_flags & O_APPEND) {
                struct gfs2_holder gh;
@@ -720,7 +718,7 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                gfs2_glock_dq_uninit(&gh);
        }
 
-       return generic_file_aio_write(iocb, iov, nr_segs, pos);
+       return generic_file_write_iter(iocb, from);
 }
 
 static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
@@ -1058,10 +1056,10 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 
 const struct file_operations gfs2_file_fops = {
        .llseek         = gfs2_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = gfs2_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = gfs2_file_write_iter,
        .unlocked_ioctl = gfs2_ioctl,
        .mmap           = gfs2_mmap,
        .open           = gfs2_open,
@@ -1070,7 +1068,7 @@ const struct file_operations gfs2_file_fops = {
        .lock           = gfs2_lock,
        .flock          = gfs2_flock,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .setlease       = gfs2_setlease,
        .fallocate      = gfs2_fallocate,
 };
@@ -1090,17 +1088,17 @@ const struct file_operations gfs2_dir_fops = {
 
 const struct file_operations gfs2_file_fops_nolock = {
        .llseek         = gfs2_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = gfs2_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = gfs2_file_write_iter,
        .unlocked_ioctl = gfs2_ioctl,
        .mmap           = gfs2_mmap,
        .open           = gfs2_open,
        .release        = gfs2_release,
        .fsync          = gfs2_fsync,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .setlease       = generic_setlease,
        .fallocate      = gfs2_fallocate,
 };
index a294d8d8bcd47f8d6b3a26c17a3b6077e5e681c5..2c1ae861dc94421d4f2340201cfa6feaddb7791a 100644 (file)
@@ -75,7 +75,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
        unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number;
        struct gfs2_bitmap *bi = rgd->rd_bits + index;
 
-       if (bi->bi_clone == 0)
+       if (bi->bi_clone == NULL)
                return;
        if (sdp->sd_args.ar_discard)
                gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL);
index c4effff7cf559c701e890e804cef81dfb1cac30e..619389649d03f59f2b8971044eb41c1d0564b6f8 100644 (file)
@@ -778,6 +778,7 @@ get_a_page:
                i_size_write(inode, size);
        inode->i_mtime = inode->i_atime = CURRENT_TIME;
        mark_inode_dirty(inode);
+       set_bit(QDF_REFRESH, &qd->qd_flags);
        return 0;
 
 unlock_out:
index 9e2fecd62f6245b1a48afe12aac49c5d2573fbf2..d0929bc817826e012cc829bb0f021832eea24379 100644 (file)
@@ -125,15 +125,15 @@ static int hfs_releasepage(struct page *page, gfp_t mask)
 }
 
 static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
-               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+               struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = file_inode(file)->i_mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                hfs_get_block);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, hfs_get_block);
 
        /*
         * In case of error extending write may have instantiated a few
@@ -141,7 +141,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
         */
        if (unlikely((rw & WRITE) && ret < 0)) {
                loff_t isize = i_size_read(inode);
-               loff_t end = offset + iov_length(iov, nr_segs);
+               loff_t end = offset + count;
 
                if (end > isize)
                        hfs_write_failed(mapping, end);
@@ -674,10 +674,10 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
 
 static const struct file_operations hfs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .splice_read    = generic_file_splice_read,
        .fsync          = hfs_file_fsync,
index a4f45bd88a631ad5a153a8f45fdd1044a3637c1c..0cf786f2d046f9fbae9b110a2a2d212c008fb3aa 100644 (file)
@@ -123,14 +123,15 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
 }
 
 static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
-               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+               struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = file_inode(file)->i_mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, 
                                 hfsplus_get_block);
 
        /*
@@ -139,7 +140,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
         */
        if (unlikely((rw & WRITE) && ret < 0)) {
                loff_t isize = i_size_read(inode);
-               loff_t end = offset + iov_length(iov, nr_segs);
+               loff_t end = offset + count;
 
                if (end > isize)
                        hfsplus_write_failed(mapping, end);
@@ -340,10 +341,10 @@ static const struct inode_operations hfsplus_file_inode_operations = {
 
 static const struct file_operations hfsplus_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .splice_read    = generic_file_splice_read,
        .fsync          = hfsplus_file_fsync,
index 9c470fde9878eae280eeb62b7ef9ca3c263c9b4c..bb529f3b7f2bf8a119ec5f2eba3c260e09c361c7 100644 (file)
@@ -378,11 +378,11 @@ static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
 
 static const struct file_operations hostfs_file_fops = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
+       .read           = new_sync_read,
        .splice_read    = generic_file_splice_read,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
-       .write          = do_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
+       .write          = new_sync_write,
        .mmap           = generic_file_mmap,
        .open           = hostfs_file_open,
        .release        = hostfs_file_release,
index 67c1a61e09558e0bb632638b0f65d8316ab9b5f2..7f54e5f76cececd4bf76354edb13eb246a81df78 100644 (file)
@@ -197,10 +197,10 @@ const struct address_space_operations hpfs_aops = {
 const struct file_operations hpfs_file_ops =
 {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .release        = hpfs_file_release,
        .fsync          = hpfs_file_fsync,
index 256cd19a3b78c006a1439f893b1b51a0341c938a..64989ca9ba90b71e3a8d16ff90dda67a913cc988 100644 (file)
@@ -51,10 +51,10 @@ const struct file_operations jffs2_file_operations =
 {
        .llseek =       generic_file_llseek,
        .open =         generic_file_open,
-       .read =         do_sync_read,
-       .aio_read =     generic_file_aio_read,
-       .write =        do_sync_write,
-       .aio_write =    generic_file_aio_write,
+       .read =         new_sync_read,
+       .read_iter =    generic_file_read_iter,
+       .write =        new_sync_write,
+       .write_iter =   generic_file_write_iter,
        .unlocked_ioctl=jffs2_ioctl,
        .mmap =         generic_file_readonly_mmap,
        .fsync =        jffs2_fsync,
index 794da944d5cd29c63d8db31040340e83d7079d87..33aa0cc1f8b863b7b101bec470af4238d0c6eeb1 100644 (file)
@@ -151,13 +151,13 @@ const struct inode_operations jfs_file_inode_operations = {
 const struct file_operations jfs_file_operations = {
        .open           = jfs_open,
        .llseek         = generic_file_llseek,
-       .write          = do_sync_write,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .write          = new_sync_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .fsync          = jfs_fsync,
        .release        = jfs_release,
        .unlocked_ioctl = jfs_ioctl,
index 6f8fe72c2a7ae201be639a94e0aca529e9270019..bd3df1ca3c9b7f955571c056f86f98e97beda7b9 100644 (file)
@@ -331,15 +331,15 @@ static sector_t jfs_bmap(struct address_space *mapping, sector_t block)
 }
 
 static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
-       const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+       struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = file->f_mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                jfs_get_block);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, jfs_get_block);
 
        /*
         * In case of error extending write may have instantiated a few
@@ -347,7 +347,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
         */
        if (unlikely((rw & WRITE) && ret < 0)) {
                loff_t isize = i_size_read(inode);
-               loff_t end = offset + iov_length(iov, nr_segs);
+               loff_t end = offset + count;
 
                if (end > isize)
                        jfs_write_failed(mapping, end);
index 7f464c513ba0a85a2fd4fe7923a9799bb319e92b..6b0f816201a229da76d9667f8aa65bbb61436ea9 100644 (file)
 void jfs_set_inode_flags(struct inode *inode)
 {
        unsigned int flags = JFS_IP(inode)->mode2;
-
-       inode->i_flags &= ~(S_IMMUTABLE | S_APPEND |
-               S_NOATIME | S_DIRSYNC | S_SYNC);
+       unsigned int new_fl = 0;
 
        if (flags & JFS_IMMUTABLE_FL)
-               inode->i_flags |= S_IMMUTABLE;
+               new_fl |= S_IMMUTABLE;
        if (flags & JFS_APPEND_FL)
-               inode->i_flags |= S_APPEND;
+               new_fl |= S_APPEND;
        if (flags & JFS_NOATIME_FL)
-               inode->i_flags |= S_NOATIME;
+               new_fl |= S_NOATIME;
        if (flags & JFS_DIRSYNC_FL)
-               inode->i_flags |= S_DIRSYNC;
+               new_fl |= S_DIRSYNC;
        if (flags & JFS_SYNC_FL)
-               inode->i_flags |= S_SYNC;
+               new_fl |= S_SYNC;
+       inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND | S_NOATIME |
+                       S_DIRSYNC | S_SYNC);
 }
 
 void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip)
index e663aeac579e5d8aaa2596a177114b17f262bd6c..2367f31186626b66c7907daf1572dfeb14e2fd75 100644 (file)
 #include <linux/percpu.h>
 #include <linux/lglock.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/filelock.h>
+
 #include <asm/uaccess.h>
 
 #define IS_POSIX(fl)   (fl->fl_flags & FL_POSIX)
@@ -322,6 +325,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock,
                return -ENOMEM;
 
        fl->fl_file = filp;
+       fl->fl_owner = (fl_owner_t)filp;
        fl->fl_pid = current->tgid;
        fl->fl_flags = FL_FLOCK;
        fl->fl_type = type;
@@ -439,7 +443,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl)
        if (assign_type(fl, type) != 0)
                return -EINVAL;
 
-       fl->fl_owner = current->files;
+       fl->fl_owner = (fl_owner_t)filp;
        fl->fl_pid = current->tgid;
 
        fl->fl_file = filp;
@@ -1385,6 +1389,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
        }
 
        if (i_have_this_lease || (mode & O_NONBLOCK)) {
+               trace_break_lease_noblock(inode, new_fl);
                error = -EWOULDBLOCK;
                goto out;
        }
@@ -1396,10 +1401,12 @@ restart:
        if (break_time == 0)
                break_time++;
        locks_insert_block(flock, new_fl);
+       trace_break_lease_block(inode, new_fl);
        spin_unlock(&inode->i_lock);
        error = wait_event_interruptible_timeout(new_fl->fl_wait,
                                                !new_fl->fl_next, break_time);
        spin_lock(&inode->i_lock);
+       trace_break_lease_unblock(inode, new_fl);
        locks_delete_block(new_fl);
        if (error >= 0) {
                if (error == 0)
@@ -1521,6 +1528,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
        int error;
 
        lease = *flp;
+       trace_generic_add_lease(inode, lease);
+
        /*
         * In the delegation case we need mutual exclusion with
         * a number of operations that take the i_mutex.  We trylock
@@ -1610,6 +1619,8 @@ static int generic_delete_lease(struct file *filp, struct file_lock **flp)
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
 
+       trace_generic_delete_lease(inode, *flp);
+
        for (before = &inode->i_flock;
                        ((fl = *before) != NULL) && IS_LEASE(fl);
                        before = &fl->fl_next) {
@@ -2304,6 +2315,7 @@ void locks_remove_file(struct file *filp)
 
        if (filp->f_op->flock) {
                struct file_lock fl = {
+                       .fl_owner = (fl_owner_t)filp,
                        .fl_pid = current->tgid,
                        .fl_file = filp,
                        .fl_flags = FL_FLOCK,
@@ -2411,31 +2423,31 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
        seq_printf(f, "%lld:%s ", id, pfx);
        if (IS_POSIX(fl)) {
                if (fl->fl_flags & FL_ACCESS)
-                       seq_printf(f, "ACCESS");
+                       seq_puts(f, "ACCESS");
                else if (IS_OFDLCK(fl))
-                       seq_printf(f, "OFDLCK");
+                       seq_puts(f, "OFDLCK");
                else
-                       seq_printf(f, "POSIX ");
+                       seq_puts(f, "POSIX ");
 
                seq_printf(f, " %s ",
                             (inode == NULL) ? "*NOINODE*" :
                             mandatory_lock(inode) ? "MANDATORY" : "ADVISORY ");
        } else if (IS_FLOCK(fl)) {
                if (fl->fl_type & LOCK_MAND) {
-                       seq_printf(f, "FLOCK  MSNFS     ");
+                       seq_puts(f, "FLOCK  MSNFS     ");
                } else {
-                       seq_printf(f, "FLOCK  ADVISORY  ");
+                       seq_puts(f, "FLOCK  ADVISORY  ");
                }
        } else if (IS_LEASE(fl)) {
-               seq_printf(f, "LEASE  ");
+               seq_puts(f, "LEASE  ");
                if (lease_breaking(fl))
-                       seq_printf(f, "BREAKING  ");
+                       seq_puts(f, "BREAKING  ");
                else if (fl->fl_file)
-                       seq_printf(f, "ACTIVE    ");
+                       seq_puts(f, "ACTIVE    ");
                else
-                       seq_printf(f, "BREAKER   ");
+                       seq_puts(f, "BREAKER   ");
        } else {
-               seq_printf(f, "UNKNOWN UNKNOWN  ");
+               seq_puts(f, "UNKNOWN UNKNOWN  ");
        }
        if (fl->fl_type & LOCK_MAND) {
                seq_printf(f, "%s ",
@@ -2467,7 +2479,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                else
                        seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
        } else {
-               seq_printf(f, "0 EOF\n");
+               seq_puts(f, "0 EOF\n");
        }
 }
 
index 9c501449450dc9be6891e5d9c1a035ca31b5687b..427bb73e298f197d4cfc73b17baeffdd1c848c5d 100644 (file)
@@ -245,8 +245,8 @@ static int logfs_mtd_can_write_buf(struct super_block *sb, u64 ofs)
                goto out;
        if (memchr_inv(buf, 0xff, super->s_writesize))
                err = -EIO;
-       kfree(buf);
 out:
+       kfree(buf);
        return err;
 }
 
index 57914fc32b62538f43909d35ffc031742b98a881..8538752df2f6a7dbb3dad0119e4e8bc47f4a25f4 100644 (file)
@@ -264,15 +264,15 @@ const struct inode_operations logfs_reg_iops = {
 };
 
 const struct file_operations logfs_reg_fops = {
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .fsync          = logfs_fsync,
        .unlocked_ioctl = logfs_ioctl,
        .llseek         = generic_file_llseek,
        .mmap           = generic_file_readonly_mmap,
        .open           = generic_file_open,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
 };
 
 const struct address_space_operations logfs_reg_aops = {
index 54360293bcb5cd0680c3042e6f0b9b87e342c649..b256c0690e5b66f5b16a2b81be033cc3b345dec6 100644 (file)
@@ -287,14 +287,14 @@ static int logfs_make_writeable(struct super_block *sb)
        if (err)
                return err;
 
+       /* Do one GC pass before any data gets dirtied */
+       logfs_gc_pass(sb);
+
        /* Check areas for trailing unaccounted data */
        err = logfs_check_areas(sb);
        if (err)
                return err;
 
-       /* Do one GC pass before any data gets dirtied */
-       logfs_gc_pass(sb);
-
        /* after all initializations are done, replay the journal
         * for rw-mounts, if necessary */
        err = logfs_replay_journal(sb);
index adc6f5494231bc947f45d8a3c526db0b36f39bf3..a967de085ac0f4cf7193101cd4e54a08bb4fff50 100644 (file)
  */
 const struct file_operations minix_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
index b8797ae6831ff3e1be4c4b3f85c2c38e34252498..b122fe21fea0dce3ae5dbcbb362dcbb4820e73b8 100644 (file)
@@ -121,20 +121,20 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
  * shunt off direct read and write requests before the VFS gets them,
  * so this method is only ever called for swap.
  */
-ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs)
+ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos)
 {
 #ifndef CONFIG_NFS_SWAP
        dprintk("NFS: nfs_direct_IO (%pD) off/no(%Ld/%lu) EINVAL\n",
-                       iocb->ki_filp, (long long) pos, nr_segs);
+                       iocb->ki_filp, (long long) pos, iter->nr_segs);
 
        return -EINVAL;
 #else
        VM_BUG_ON(iocb->ki_nbytes != PAGE_SIZE);
 
        if (rw == READ || rw == KERNEL_READ)
-               return nfs_file_direct_read(iocb, iov, nr_segs, pos,
+               return nfs_file_direct_read(iocb, iter, pos,
                                rw == READ ? true : false);
-       return nfs_file_direct_write(iocb, iov, nr_segs, pos,
+       return nfs_file_direct_write(iocb, iter, pos,
                                rw == WRITE ? true : false);
 #endif /* CONFIG_NFS_SWAP */
 }
@@ -322,60 +322,37 @@ static const struct nfs_pgio_completion_ops nfs_direct_read_completion_ops = {
  * handled automatically by nfs_direct_read_result().  Otherwise, if
  * no requests have been sent, just return an error.
  */
-static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *desc,
-                                               const struct iovec *iov,
-                                               loff_t pos, bool uio)
-{
-       struct nfs_direct_req *dreq = desc->pg_dreq;
-       struct nfs_open_context *ctx = dreq->ctx;
-       struct inode *inode = ctx->dentry->d_inode;
-       unsigned long user_addr = (unsigned long)iov->iov_base;
-       size_t count = iov->iov_len;
-       size_t rsize = NFS_SERVER(inode)->rsize;
-       unsigned int pgbase;
-       int result;
-       ssize_t started = 0;
-       struct page **pagevec = NULL;
-       unsigned int npages;
-
-       do {
-               size_t bytes;
-               int i;
 
-               pgbase = user_addr & ~PAGE_MASK;
-               bytes = min(max_t(size_t, rsize, PAGE_SIZE), count);
+static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
+                                             struct iov_iter *iter,
+                                             loff_t pos)
+{
+       struct nfs_pageio_descriptor desc;
+       struct inode *inode = dreq->inode;
+       ssize_t result = -EINVAL;
+       size_t requested_bytes = 0;
+       size_t rsize = max_t(size_t, NFS_SERVER(inode)->rsize, PAGE_SIZE);
 
-               result = -ENOMEM;
-               npages = nfs_page_array_len(pgbase, bytes);
-               if (!pagevec)
-                       pagevec = kmalloc(npages * sizeof(struct page *),
-                                         GFP_KERNEL);
-               if (!pagevec)
-                       break;
-               if (uio) {
-                       down_read(&current->mm->mmap_sem);
-                       result = get_user_pages(current, current->mm, user_addr,
-                                       npages, 1, 0, pagevec, NULL);
-                       up_read(&current->mm->mmap_sem);
-                       if (result < 0)
-                               break;
-               } else {
-                       WARN_ON(npages != 1);
-                       result = get_kernel_page(user_addr, 1, pagevec);
-                       if (WARN_ON(result != 1))
-                               break;
-               }
+       NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode,
+                            &nfs_direct_read_completion_ops);
+       get_dreq(dreq);
+       desc.pg_dreq = dreq;
+       atomic_inc(&inode->i_dio_count);
 
-               if ((unsigned)result < npages) {
-                       bytes = result * PAGE_SIZE;
-                       if (bytes <= pgbase) {
-                               nfs_direct_release_pages(pagevec, result);
-                               break;
-                       }
-                       bytes -= pgbase;
-                       npages = result;
-               }
+       while (iov_iter_count(iter)) {
+               struct page **pagevec;
+               size_t bytes;
+               size_t pgbase;
+               unsigned npages, i;
 
+               result = iov_iter_get_pages_alloc(iter, &pagevec, 
+                                                 rsize, &pgbase);
+               if (result < 0)
+                       break;
+       
+               bytes = result;
+               iov_iter_advance(iter, bytes);
+               npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE;
                for (i = 0; i < npages; i++) {
                        struct nfs_page *req;
                        unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
@@ -389,56 +366,21 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de
                        }
                        req->wb_index = pos >> PAGE_SHIFT;
                        req->wb_offset = pos & ~PAGE_MASK;
-                       if (!nfs_pageio_add_request(desc, req)) {
-                               result = desc->pg_error;
+                       if (!nfs_pageio_add_request(&desc, req)) {
+                               result = desc.pg_error;
                                nfs_release_request(req);
                                break;
                        }
                        pgbase = 0;
                        bytes -= req_len;
-                       started += req_len;
-                       user_addr += req_len;
+                       requested_bytes += req_len;
                        pos += req_len;
-                       count -= req_len;
                        dreq->bytes_left -= req_len;
                }
-               /* The nfs_page now hold references to these pages */
                nfs_direct_release_pages(pagevec, npages);
-       } while (count != 0 && result >= 0);
-
-       kfree(pagevec);
-
-       if (started)
-               return started;
-       return result < 0 ? (ssize_t) result : -EFAULT;
-}
-
-static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
-                                             const struct iovec *iov,
-                                             unsigned long nr_segs,
-                                             loff_t pos, bool uio)
-{
-       struct nfs_pageio_descriptor desc;
-       struct inode *inode = dreq->inode;
-       ssize_t result = -EINVAL;
-       size_t requested_bytes = 0;
-       unsigned long seg;
-
-       NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode,
-                            &nfs_direct_read_completion_ops);
-       get_dreq(dreq);
-       desc.pg_dreq = dreq;
-       atomic_inc(&inode->i_dio_count);
-
-       for (seg = 0; seg < nr_segs; seg++) {
-               const struct iovec *vec = &iov[seg];
-               result = nfs_direct_read_schedule_segment(&desc, vec, pos, uio);
+               kvfree(pagevec);
                if (result < 0)
                        break;
-               requested_bytes += result;
-               if ((size_t)result < vec->iov_len)
-                       break;
-               pos += vec->iov_len;
        }
 
        nfs_pageio_complete(&desc);
@@ -461,8 +403,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
 /**
  * nfs_file_direct_read - file direct read operation for NFS files
  * @iocb: target I/O control block
- * @iov: vector of user buffers into which to read data
- * @nr_segs: size of iov vector
+ * @iter: vector of user buffers into which to read data
  * @pos: byte offset in file where reading starts
  *
  * We use this function for direct reads instead of calling
@@ -479,8 +420,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
  * client must read the updated atime from the server back into its
  * cache.
  */
-ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos, bool uio)
+ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
+                               loff_t pos, bool uio)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
@@ -488,9 +429,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
        struct nfs_direct_req *dreq;
        struct nfs_lock_context *l_ctx;
        ssize_t result = -EINVAL;
-       size_t count;
-
-       count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
 
        dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n",
@@ -513,7 +452,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
                goto out_unlock;
 
        dreq->inode = inode;
-       dreq->bytes_left = iov_length(iov, nr_segs);
+       dreq->bytes_left = count;
        dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
        l_ctx = nfs_get_lock_context(dreq->ctx);
        if (IS_ERR(l_ctx)) {
@@ -524,8 +463,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
-       NFS_I(inode)->read_io += iov_length(iov, nr_segs);
-       result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio);
+       NFS_I(inode)->read_io += count;
+       result = nfs_direct_read_schedule_iovec(dreq, iter, pos);
 
        mutex_unlock(&inode->i_mutex);
 
@@ -681,109 +620,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
 }
 #endif
 
-/*
- * NB: Return the value of the first error return code.  Subsequent
- *     errors after the first one are ignored.
- */
-/*
- * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
- * operation.  If nfs_writedata_alloc() or get_user_pages() fails,
- * bail and stop sending more writes.  Write length accounting is
- * handled automatically by nfs_direct_write_result().  Otherwise, if
- * no requests have been sent, just return an error.
- */
-static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *desc,
-                                                const struct iovec *iov,
-                                                loff_t pos, bool uio)
-{
-       struct nfs_direct_req *dreq = desc->pg_dreq;
-       struct nfs_open_context *ctx = dreq->ctx;
-       struct inode *inode = ctx->dentry->d_inode;
-       unsigned long user_addr = (unsigned long)iov->iov_base;
-       size_t count = iov->iov_len;
-       size_t wsize = NFS_SERVER(inode)->wsize;
-       unsigned int pgbase;
-       int result;
-       ssize_t started = 0;
-       struct page **pagevec = NULL;
-       unsigned int npages;
-
-       do {
-               size_t bytes;
-               int i;
-
-               pgbase = user_addr & ~PAGE_MASK;
-               bytes = min(max_t(size_t, wsize, PAGE_SIZE), count);
-
-               result = -ENOMEM;
-               npages = nfs_page_array_len(pgbase, bytes);
-               if (!pagevec)
-                       pagevec = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
-               if (!pagevec)
-                       break;
-
-               if (uio) {
-                       down_read(&current->mm->mmap_sem);
-                       result = get_user_pages(current, current->mm, user_addr,
-                                               npages, 0, 0, pagevec, NULL);
-                       up_read(&current->mm->mmap_sem);
-                       if (result < 0)
-                               break;
-               } else {
-                       WARN_ON(npages != 1);
-                       result = get_kernel_page(user_addr, 0, pagevec);
-                       if (WARN_ON(result != 1))
-                               break;
-               }
-
-               if ((unsigned)result < npages) {
-                       bytes = result * PAGE_SIZE;
-                       if (bytes <= pgbase) {
-                               nfs_direct_release_pages(pagevec, result);
-                               break;
-                       }
-                       bytes -= pgbase;
-                       npages = result;
-               }
-
-               for (i = 0; i < npages; i++) {
-                       struct nfs_page *req;
-                       unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
-
-                       req = nfs_create_request(dreq->ctx, dreq->inode,
-                                                pagevec[i],
-                                                pgbase, req_len);
-                       if (IS_ERR(req)) {
-                               result = PTR_ERR(req);
-                               break;
-                       }
-                       nfs_lock_request(req);
-                       req->wb_index = pos >> PAGE_SHIFT;
-                       req->wb_offset = pos & ~PAGE_MASK;
-                       if (!nfs_pageio_add_request(desc, req)) {
-                               result = desc->pg_error;
-                               nfs_unlock_and_release_request(req);
-                               break;
-                       }
-                       pgbase = 0;
-                       bytes -= req_len;
-                       started += req_len;
-                       user_addr += req_len;
-                       pos += req_len;
-                       count -= req_len;
-                       dreq->bytes_left -= req_len;
-               }
-               /* The nfs_page now hold references to these pages */
-               nfs_direct_release_pages(pagevec, npages);
-       } while (count != 0 && result >= 0);
-
-       kfree(pagevec);
-
-       if (started)
-               return started;
-       return result < 0 ? (ssize_t) result : -EFAULT;
-}
-
 static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
 {
        struct nfs_direct_req *dreq = hdr->dreq;
@@ -863,16 +699,27 @@ static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
        .completion = nfs_direct_write_completion,
 };
 
+
+/*
+ * NB: Return the value of the first error return code.  Subsequent
+ *     errors after the first one are ignored.
+ */
+/*
+ * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
+ * operation.  If nfs_writedata_alloc() or get_user_pages() fails,
+ * bail and stop sending more writes.  Write length accounting is
+ * handled automatically by nfs_direct_write_result().  Otherwise, if
+ * no requests have been sent, just return an error.
+ */
 static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
-                                              const struct iovec *iov,
-                                              unsigned long nr_segs,
-                                              loff_t pos, bool uio)
+                                              struct iov_iter *iter,
+                                              loff_t pos)
 {
        struct nfs_pageio_descriptor desc;
        struct inode *inode = dreq->inode;
        ssize_t result = 0;
        size_t requested_bytes = 0;
-       unsigned long seg;
+       size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE);
 
        NFS_PROTO(inode)->write_pageio_init(&desc, inode, FLUSH_COND_STABLE,
                              &nfs_direct_write_completion_ops);
@@ -880,16 +727,50 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
        get_dreq(dreq);
        atomic_inc(&inode->i_dio_count);
 
-       NFS_I(dreq->inode)->write_io += iov_length(iov, nr_segs);
-       for (seg = 0; seg < nr_segs; seg++) {
-               const struct iovec *vec = &iov[seg];
-               result = nfs_direct_write_schedule_segment(&desc, vec, pos, uio);
+       NFS_I(inode)->write_io += iov_iter_count(iter);
+       while (iov_iter_count(iter)) {
+               struct page **pagevec;
+               size_t bytes;
+               size_t pgbase;
+               unsigned npages, i;
+
+               result = iov_iter_get_pages_alloc(iter, &pagevec, 
+                                                 wsize, &pgbase);
                if (result < 0)
                        break;
-               requested_bytes += result;
-               if ((size_t)result < vec->iov_len)
+
+               bytes = result;
+               iov_iter_advance(iter, bytes);
+               npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE;
+               for (i = 0; i < npages; i++) {
+                       struct nfs_page *req;
+                       unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
+
+                       req = nfs_create_request(dreq->ctx, inode,
+                                                pagevec[i],
+                                                pgbase, req_len);
+                       if (IS_ERR(req)) {
+                               result = PTR_ERR(req);
+                               break;
+                       }
+                       nfs_lock_request(req);
+                       req->wb_index = pos >> PAGE_SHIFT;
+                       req->wb_offset = pos & ~PAGE_MASK;
+                       if (!nfs_pageio_add_request(&desc, req)) {
+                               result = desc.pg_error;
+                               nfs_unlock_and_release_request(req);
+                               break;
+                       }
+                       pgbase = 0;
+                       bytes -= req_len;
+                       requested_bytes += req_len;
+                       pos += req_len;
+                       dreq->bytes_left -= req_len;
+               }
+               nfs_direct_release_pages(pagevec, npages);
+               kvfree(pagevec);
+               if (result < 0)
                        break;
-               pos += vec->iov_len;
        }
        nfs_pageio_complete(&desc);
 
@@ -911,8 +792,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
 /**
  * nfs_file_direct_write - file direct write operation for NFS files
  * @iocb: target I/O control block
- * @iov: vector of user buffers from which to write data
- * @nr_segs: size of iov vector
+ * @iter: vector of user buffers from which to write data
  * @pos: byte offset in file where writing starts
  *
  * We use this function for direct writes instead of calling
@@ -930,8 +810,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
  * Note that O_APPEND is not supported for NFS direct writes, as there
  * is no atomic O_APPEND write facility in the NFS protocol.
  */
-ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos, bool uio)
+ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter,
+                               loff_t pos, bool uio)
 {
        ssize_t result = -EINVAL;
        struct file *file = iocb->ki_filp;
@@ -940,9 +820,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
        struct nfs_direct_req *dreq;
        struct nfs_lock_context *l_ctx;
        loff_t end;
-       size_t count;
-
-       count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
 
        nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
@@ -993,7 +871,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
-       result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio);
+       result = nfs_direct_write_schedule_iovec(dreq, iter, pos);
 
        if (mapping->nrpages) {
                invalidate_inode_pages2_range(mapping,
index 284ca901fe16cd26d064c603f2e51441708a5953..4042ff58fe3f3d0b18d705774c3f6d975e642248 100644 (file)
@@ -165,22 +165,21 @@ nfs_file_flush(struct file *file, fl_owner_t id)
 EXPORT_SYMBOL_GPL(nfs_file_flush);
 
 ssize_t
-nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t pos)
+nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        ssize_t result;
 
        if (iocb->ki_filp->f_flags & O_DIRECT)
-               return nfs_file_direct_read(iocb, iov, nr_segs, pos, true);
+               return nfs_file_direct_read(iocb, to, iocb->ki_pos, true);
 
-       dprintk("NFS: read(%pD2, %lu@%lu)\n",
+       dprintk("NFS: read(%pD2, %zu@%lu)\n",
                iocb->ki_filp,
-               (unsigned long) iov_length(iov, nr_segs), (unsigned long) pos);
+               iov_iter_count(to), (unsigned long) iocb->ki_pos);
 
        result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
        if (!result) {
-               result = generic_file_aio_read(iocb, iov, nr_segs, pos);
+               result = generic_file_read_iter(iocb, to);
                if (result > 0)
                        nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
        }
@@ -635,24 +634,24 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode)
        return 0;
 }
 
-ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
-                      unsigned long nr_segs, loff_t pos)
+ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
        unsigned long written = 0;
        ssize_t result;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(from);
+       loff_t pos = iocb->ki_pos;
 
        result = nfs_key_timeout_notify(file, inode);
        if (result)
                return result;
 
        if (file->f_flags & O_DIRECT)
-               return nfs_file_direct_write(iocb, iov, nr_segs, pos, true);
+               return nfs_file_direct_write(iocb, from, pos, true);
 
-       dprintk("NFS: write(%pD2, %lu@%Ld)\n",
-               file, (unsigned long) count, (long long) pos);
+       dprintk("NFS: write(%pD2, %zu@%Ld)\n",
+               file, count, (long long) pos);
 
        result = -EBUSY;
        if (IS_SWAPFILE(inode))
@@ -670,7 +669,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
        if (!count)
                goto out;
 
-       result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+       result = generic_file_write_iter(iocb, from);
        if (result > 0)
                written = result;
 
@@ -691,36 +690,6 @@ out_swapfile:
 }
 EXPORT_SYMBOL_GPL(nfs_file_write);
 
-ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
-                             struct file *filp, loff_t *ppos,
-                             size_t count, unsigned int flags)
-{
-       struct inode *inode = file_inode(filp);
-       unsigned long written = 0;
-       ssize_t ret;
-
-       dprintk("NFS splice_write(%pD2, %lu@%llu)\n",
-               filp, (unsigned long) count, (unsigned long long) *ppos);
-
-       /*
-        * The combination of splice and an O_APPEND destination is disallowed.
-        */
-
-       ret = generic_file_splice_write(pipe, filp, ppos, count, flags);
-       if (ret > 0)
-               written = ret;
-
-       if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
-               int err = vfs_fsync(filp, 0);
-               if (err < 0)
-                       ret = err;
-       }
-       if (ret > 0)
-               nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(nfs_file_splice_write);
-
 static int
 do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
@@ -916,10 +885,6 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
                is_local = 1;
 
        /* We're simulating flock() locks using posix locks on the server */
-       fl->fl_owner = (fl_owner_t)filp;
-       fl->fl_start = 0;
-       fl->fl_end = OFFSET_MAX;
-
        if (fl->fl_type == F_UNLCK)
                return do_unlk(filp, cmd, fl, is_local);
        return do_setlk(filp, cmd, fl, is_local);
@@ -939,10 +904,10 @@ EXPORT_SYMBOL_GPL(nfs_setlease);
 
 const struct file_operations nfs_file_operations = {
        .llseek         = nfs_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = nfs_file_read,
-       .aio_write      = nfs_file_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = nfs_file_read,
+       .write_iter     = nfs_file_write,
        .mmap           = nfs_file_mmap,
        .open           = nfs_file_open,
        .flush          = nfs_file_flush,
@@ -951,7 +916,7 @@ const struct file_operations nfs_file_operations = {
        .lock           = nfs_lock,
        .flock          = nfs_flock,
        .splice_read    = nfs_file_splice_read,
-       .splice_write   = nfs_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .check_flags    = nfs_check_flags,
        .setlease       = nfs_setlease,
 };
index 66984a9aafaad9ad74d81415d5737cbafad81618..b94f80420a584e596789fd048489463728a58789 100644 (file)
@@ -120,7 +120,8 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
 
        security_d_instantiate(ret, inode);
        spin_lock(&ret->d_lock);
-       if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
+       if (IS_ROOT(ret) && !ret->d_fsdata &&
+           !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
                ret->d_fsdata = name;
                name = NULL;
        }
index 0c438973f3c8687836fc16bae3fb9aa89a767727..c79f3e767c8ce10631b7f0c09c8982301253cde1 100644 (file)
@@ -1575,18 +1575,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        inode->i_version = fattr->change_attr;
                }
        } else if (server->caps & NFS_CAP_CHANGE_ATTR)
-               invalid |= save_cache_validity;
+               nfsi->cache_validity |= save_cache_validity;
 
        if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
                memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
        } else if (server->caps & NFS_CAP_MTIME)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_REVAL_FORCED);
 
        if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
                memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
        } else if (server->caps & NFS_CAP_CTIME)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_REVAL_FORCED);
 
        /* Check if our cached file size is stale */
@@ -1608,7 +1610,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                        (long long)new_isize);
                }
        } else
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_REVAL_PAGECACHE
                                | NFS_INO_REVAL_FORCED);
 
@@ -1616,7 +1619,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        if (fattr->valid & NFS_ATTR_FATTR_ATIME)
                memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
        else if (server->caps & NFS_CAP_ATIME)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATIME
                                | NFS_INO_REVAL_FORCED);
 
        if (fattr->valid & NFS_ATTR_FATTR_MODE) {
@@ -1627,7 +1631,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
                }
        } else if (server->caps & NFS_CAP_MODE)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL
                                | NFS_INO_REVAL_FORCED);
@@ -1638,7 +1643,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        inode->i_uid = fattr->uid;
                }
        } else if (server->caps & NFS_CAP_OWNER)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL
                                | NFS_INO_REVAL_FORCED);
@@ -1649,7 +1655,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        inode->i_gid = fattr->gid;
                }
        } else if (server->caps & NFS_CAP_OWNER_GROUP)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL
                                | NFS_INO_REVAL_FORCED);
@@ -1662,7 +1669,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        set_nlink(inode, fattr->nlink);
                }
        } else if (server->caps & NFS_CAP_NLINK)
-               invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_ATTR
                                | NFS_INO_REVAL_FORCED);
 
        if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
index dd8bfc2e2464609dd7fa755afcff2b6f436f5def..0e4e8049c9f5318bed90a4ed939398fa9e47cdf8 100644 (file)
@@ -320,16 +320,14 @@ int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *)
 int nfs_file_fsync_commit(struct file *, loff_t, loff_t, int);
 loff_t nfs_file_llseek(struct file *, loff_t, int);
 int nfs_file_flush(struct file *, fl_owner_t);
-ssize_t nfs_file_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ssize_t nfs_file_read(struct kiocb *, struct iov_iter *);
 ssize_t nfs_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *,
                             size_t, unsigned int);
 int nfs_file_mmap(struct file *, struct vm_area_struct *);
-ssize_t nfs_file_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ssize_t nfs_file_write(struct kiocb *, struct iov_iter *);
 int nfs_file_release(struct inode *, struct file *);
 int nfs_lock(struct file *, int, struct file_lock *);
 int nfs_flock(struct file *, int, struct file_lock *);
-ssize_t nfs_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *,
-                             size_t, unsigned int);
 int nfs_check_flags(int);
 int nfs_setlease(struct file *, long, struct file_lock **);
 
index 8de3407e0360829dd54a1682b1f046e2f88c6001..50de2cdea082580e1020903d2aa7e1a06644704f 100644 (file)
@@ -118,10 +118,10 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 
 const struct file_operations nfs4_file_operations = {
        .llseek         = nfs_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = nfs_file_read,
-       .aio_write      = nfs_file_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = nfs_file_read,
+       .write_iter     = nfs_file_write,
        .mmap           = nfs_file_mmap,
        .open           = nfs4_file_open,
        .flush          = nfs_file_flush,
@@ -130,7 +130,7 @@ const struct file_operations nfs4_file_operations = {
        .lock           = nfs_lock,
        .flock          = nfs_flock,
        .splice_read    = nfs_file_splice_read,
-       .splice_write   = nfs_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .check_flags    = nfs_check_flags,
        .setlease       = nfs_setlease,
 };
index 9a3b6a4cd6b9581a037f2508e5b6d4aca565cd93..cd7c651f9b84fc0afc0d707c866baa2403a3308f 100644 (file)
@@ -1353,6 +1353,30 @@ static const struct rpc_call_ops nfs_write_common_ops = {
        .rpc_release = nfs_writeback_release_common,
 };
 
+/*
+ * Special version of should_remove_suid() that ignores capabilities.
+ */
+static int nfs_should_remove_suid(const struct inode *inode)
+{
+       umode_t mode = inode->i_mode;
+       int kill = 0;
+
+       /* suid always must be killed */
+       if (unlikely(mode & S_ISUID))
+               kill = ATTR_KILL_SUID;
+
+       /*
+        * sgid without any exec bits is just a mandatory locking mark; leave
+        * it alone.  If some exec bits are set, it's a real sgid; kill it.
+        */
+       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
+               kill |= ATTR_KILL_SGID;
+
+       if (unlikely(kill && S_ISREG(mode)))
+               return kill;
+
+       return 0;
+}
 
 /*
  * This function is called when the WRITE call is complete.
@@ -1401,9 +1425,16 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
                }
        }
 #endif
-       if (task->tk_status < 0)
+       if (task->tk_status < 0) {
                nfs_set_pgio_error(data->header, task->tk_status, argp->offset);
-       else if (resp->count < argp->count) {
+               return;
+       }
+
+       /* Deal with the suid/sgid bit corner case */
+       if (nfs_should_remove_suid(inode))
+               nfs_mark_for_revalidate(inode);
+
+       if (resp->count < argp->count) {
                static unsigned long    complain;
 
                /* This a short write! */
index f3a82fbcae026357431720d998b5eb6e7eafee66..24978153c0c4daefd04f2853576db34aa3e8e0fe 100644 (file)
@@ -152,10 +152,10 @@ static int nilfs_file_mmap(struct file *file, struct vm_area_struct *vma)
  */
 const struct file_operations nilfs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .unlocked_ioctl = nilfs_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = nilfs_compat_ioctl,
index b9c5726120e32acb70d20df47986433a6ca5f153..6252b173a46590225e2ba29f7e07cf13aa62eeac 100644 (file)
@@ -298,19 +298,20 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping,
 }
 
 static ssize_t
-nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
-               loff_t offset, unsigned long nr_segs)
+nilfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
+               loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = file->f_mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t size;
 
        if (rw == WRITE)
                return 0;
 
        /* Needs synchronization with the cleaner */
-       size = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
+       size = blockdev_direct_IO(rw, iocb, inode, iter, offset,
                                  nilfs_get_block);
 
        /*
@@ -319,7 +320,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
         */
        if (unlikely((rw & WRITE) && size < 0)) {
                loff_t isize = i_size_read(inode);
-               loff_t end = offset + iov_length(iov, nr_segs);
+               loff_t end = offset + count;
 
                if (end > isize)
                        nilfs_write_failed(mapping, end);
index db9bd8a31725477eb9130bb6868d25bda510aa4a..89b4d6663775276b2a0229026b6b19bff46f2a27 100644 (file)
@@ -2091,10 +2091,7 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
        size_t count;           /* after file limit checks */
        ssize_t written, err;
 
-       count = 0;
-       err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
-       if (err)
-               return err;
+       count = iov_length(iov, nr_segs);
        pos = *ppos;
        /* We can write back this queue in page reclaim. */
        current->backing_dev_info = mapping->backing_dev_info;
@@ -2203,8 +2200,8 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end,
 
 const struct file_operations ntfs_file_ops = {
        .llseek         = generic_file_llseek,   /* Seek inside file. */
-       .read           = do_sync_read,          /* Read from file. */
-       .aio_read       = generic_file_aio_read, /* Async read from file. */
+       .read           = new_sync_read,         /* Read from file. */
+       .read_iter      = generic_file_read_iter, /* Async read from file. */
 #ifdef NTFS_RW
        .write          = do_sync_write,         /* Write to file. */
        .aio_write      = ntfs_file_aio_write,   /* Async write to file. */
index d310d12a9adc481187c78fb65bffba53a16a75e7..4a231a166cf88d6f76495ab9420e7406ba10307a 100644 (file)
@@ -599,9 +599,8 @@ static int ocfs2_releasepage(struct page *page, gfp_t wait)
 
 static ssize_t ocfs2_direct_IO(int rw,
                               struct kiocb *iocb,
-                              const struct iovec *iov,
-                              loff_t offset,
-                              unsigned long nr_segs)
+                              struct iov_iter *iter,
+                              loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file)->i_mapping->host;
@@ -618,7 +617,7 @@ static ssize_t ocfs2_direct_IO(int rw,
                return 0;
 
        return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
-                                   iov, offset, nr_segs,
+                                   iter, offset,
                                    ocfs2_direct_IO_get_blocks,
                                    ocfs2_dio_end_io, NULL, 0);
 }
index 8970dcf74de53e71539e8fad7042a55f66a2c713..465c95016a39abed758984f0d360dae8c0396193 100644 (file)
@@ -2233,16 +2233,13 @@ out:
        return ret;
 }
 
-static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
-                                   const struct iovec *iov,
-                                   unsigned long nr_segs,
-                                   loff_t pos)
+static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
+                                   struct iov_iter *from)
 {
        int ret, direct_io, appending, rw_level, have_alloc_sem  = 0;
        int can_do_direct, has_refcount = 0;
        ssize_t written = 0;
-       size_t ocount;          /* original count */
-       size_t count;           /* after file limit checks */
+       size_t count = iov_iter_count(from);
        loff_t old_size, *ppos = &iocb->ki_pos;
        u32 old_clusters;
        struct file *file = iocb->ki_filp;
@@ -2256,7 +2253,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                (unsigned long long)OCFS2_I(inode)->ip_blkno,
                file->f_path.dentry->d_name.len,
                file->f_path.dentry->d_name.name,
-               (unsigned int)nr_segs);
+               (unsigned int)from->nr_segs);   /* GRRRRR */
 
        if (iocb->ki_nbytes == 0)
                return 0;
@@ -2354,29 +2351,21 @@ relock:
        /* communicate with ocfs2_dio_end_io */
        ocfs2_iocb_set_rw_locked(iocb, rw_level);
 
-       ret = generic_segment_checks(iov, &nr_segs, &ocount,
-                                    VERIFY_READ);
-       if (ret)
-               goto out_dio;
-
-       count = ocount;
        ret = generic_write_checks(file, ppos, &count,
                                   S_ISBLK(inode->i_mode));
        if (ret)
                goto out_dio;
 
+       iov_iter_truncate(from, count);
        if (direct_io) {
-               written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos,
-                                                   count, ocount);
+               written = generic_file_direct_write(iocb, from, *ppos);
                if (written < 0) {
                        ret = written;
                        goto out_dio;
                }
        } else {
-               struct iov_iter from;
-               iov_iter_init(&from, iov, nr_segs, count, 0);
                current->backing_dev_info = file->f_mapping->backing_dev_info;
-               written = generic_perform_write(file, &from, *ppos);
+               written = generic_perform_write(file, from, *ppos);
                if (likely(written >= 0))
                        iocb->ki_pos = *ppos + written;
                current->backing_dev_info = NULL;
@@ -2441,84 +2430,6 @@ out_sems:
        return ret;
 }
 
-static int ocfs2_splice_to_file(struct pipe_inode_info *pipe,
-                               struct file *out,
-                               struct splice_desc *sd)
-{
-       int ret;
-
-       ret = ocfs2_prepare_inode_for_write(out, &sd->pos,
-                                           sd->total_len, 0, NULL, NULL);
-       if (ret < 0) {
-               mlog_errno(ret);
-               return ret;
-       }
-
-       return splice_from_pipe_feed(pipe, sd, pipe_to_file);
-}
-
-static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
-                                      struct file *out,
-                                      loff_t *ppos,
-                                      size_t len,
-                                      unsigned int flags)
-{
-       int ret;
-       struct address_space *mapping = out->f_mapping;
-       struct inode *inode = mapping->host;
-       struct splice_desc sd = {
-               .total_len = len,
-               .flags = flags,
-               .pos = *ppos,
-               .u.file = out,
-       };
-
-
-       trace_ocfs2_file_splice_write(inode, out, out->f_path.dentry,
-                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
-                       out->f_path.dentry->d_name.len,
-                       out->f_path.dentry->d_name.name, len);
-
-       pipe_lock(pipe);
-
-       splice_from_pipe_begin(&sd);
-       do {
-               ret = splice_from_pipe_next(pipe, &sd);
-               if (ret <= 0)
-                       break;
-
-               mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
-               ret = ocfs2_rw_lock(inode, 1);
-               if (ret < 0)
-                       mlog_errno(ret);
-               else {
-                       ret = ocfs2_splice_to_file(pipe, out, &sd);
-                       ocfs2_rw_unlock(inode, 1);
-               }
-               mutex_unlock(&inode->i_mutex);
-       } while (ret > 0);
-       splice_from_pipe_end(pipe, &sd);
-
-       pipe_unlock(pipe);
-
-       if (sd.num_spliced)
-               ret = sd.num_spliced;
-
-       if (ret > 0) {
-               int err;
-
-               err = generic_write_sync(out, *ppos, ret);
-               if (err)
-                       ret = err;
-               else
-                       *ppos += ret;
-
-               balance_dirty_pages_ratelimited(mapping);
-       }
-
-       return ret;
-}
-
 static ssize_t ocfs2_file_splice_read(struct file *in,
                                      loff_t *ppos,
                                      struct pipe_inode_info *pipe,
@@ -2534,7 +2445,7 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
                        in->f_path.dentry->d_name.name, len);
 
        /*
-        * See the comment in ocfs2_file_aio_read()
+        * See the comment in ocfs2_file_read_iter()
         */
        ret = ocfs2_inode_lock_atime(inode, in->f_path.mnt, &lock_level);
        if (ret < 0) {
@@ -2549,10 +2460,8 @@ bail:
        return ret;
 }
 
-static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
-                                  const struct iovec *iov,
-                                  unsigned long nr_segs,
-                                  loff_t pos)
+static ssize_t ocfs2_file_read_iter(struct kiocb *iocb,
+                                  struct iov_iter *to)
 {
        int ret = 0, rw_level = -1, have_alloc_sem = 0, lock_level = 0;
        struct file *filp = iocb->ki_filp;
@@ -2561,7 +2470,8 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
        trace_ocfs2_file_aio_read(inode, filp, filp->f_path.dentry,
                        (unsigned long long)OCFS2_I(inode)->ip_blkno,
                        filp->f_path.dentry->d_name.len,
-                       filp->f_path.dentry->d_name.name, nr_segs);
+                       filp->f_path.dentry->d_name.name,
+                       to->nr_segs);   /* GRRRRR */
 
 
        if (!inode) {
@@ -2606,13 +2516,13 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
        }
        ocfs2_inode_unlock(inode, lock_level);
 
-       ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
+       ret = generic_file_read_iter(iocb, to);
        trace_generic_file_aio_read_ret(ret);
 
        /* buffered aio wouldn't have proper lock coverage today */
        BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
 
-       /* see ocfs2_file_aio_write */
+       /* see ocfs2_file_write_iter */
        if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) {
                rw_level = -1;
                have_alloc_sem = 0;
@@ -2705,14 +2615,14 @@ const struct inode_operations ocfs2_special_file_iops = {
  */
 const struct file_operations ocfs2_fops = {
        .llseek         = ocfs2_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
        .mmap           = ocfs2_mmap,
        .fsync          = ocfs2_sync_file,
        .release        = ocfs2_file_release,
        .open           = ocfs2_file_open,
-       .aio_read       = ocfs2_file_aio_read,
-       .aio_write      = ocfs2_file_aio_write,
+       .read_iter      = ocfs2_file_read_iter,
+       .write_iter     = ocfs2_file_write_iter,
        .unlocked_ioctl = ocfs2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ocfs2_compat_ioctl,
@@ -2720,7 +2630,7 @@ const struct file_operations ocfs2_fops = {
        .lock           = ocfs2_lock,
        .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
-       .splice_write   = ocfs2_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .fallocate      = ocfs2_fallocate,
 };
 
@@ -2753,21 +2663,21 @@ const struct file_operations ocfs2_dops = {
  */
 const struct file_operations ocfs2_fops_no_plocks = {
        .llseek         = ocfs2_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
        .mmap           = ocfs2_mmap,
        .fsync          = ocfs2_sync_file,
        .release        = ocfs2_file_release,
        .open           = ocfs2_file_open,
-       .aio_read       = ocfs2_file_aio_read,
-       .aio_write      = ocfs2_file_aio_write,
+       .read_iter      = ocfs2_file_read_iter,
+       .write_iter     = ocfs2_file_write_iter,
        .unlocked_ioctl = ocfs2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ocfs2_compat_ioctl,
 #endif
        .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
-       .splice_write   = ocfs2_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .fallocate      = ocfs2_fallocate,
 };
 
index 54d57d6ba68dd5b91df6cbc9269e1ccf3c05a950..902e88527fcec443244bd12a9a25e1cf895ba763 100644 (file)
@@ -337,10 +337,10 @@ static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
 
 const struct file_operations omfs_file_operations = {
        .llseek = generic_file_llseek,
-       .read = do_sync_read,
-       .write = do_sync_write,
-       .aio_read = generic_file_aio_read,
-       .aio_write = generic_file_aio_write,
+       .read = new_sync_read,
+       .write = new_sync_write,
+       .read_iter = generic_file_read_iter,
+       .write_iter = generic_file_write_iter,
        .mmap = generic_file_mmap,
        .fsync = generic_file_fsync,
        .splice_read = generic_file_splice_read,
index 9d64679cec73b00fc4685e23d69374ca122fed09..36662d0362379698fcb5764fbb142337732b3919 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -725,6 +725,12 @@ static int do_dentry_open(struct file *f,
        }
        if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
                i_readcount_inc(inode);
+       if ((f->f_mode & FMODE_READ) &&
+            likely(f->f_op->read || f->f_op->aio_read || f->f_op->read_iter))
+               f->f_mode |= FMODE_CAN_READ;
+       if ((f->f_mode & FMODE_WRITE) &&
+            likely(f->f_op->write || f->f_op->aio_write || f->f_op->write_iter))
+               f->f_mode |= FMODE_CAN_WRITE;
 
        f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
index 034bffac3f9724c6121f4635ba9740d61e106d06..21981e58e2a634c09b9ebb9b327860d849fb6b53 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -116,50 +116,6 @@ void pipe_wait(struct pipe_inode_info *pipe)
        pipe_lock(pipe);
 }
 
-static int
-pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len,
-                       int atomic)
-{
-       unsigned long copy;
-
-       while (len > 0) {
-               while (!iov->iov_len)
-                       iov++;
-               copy = min_t(unsigned long, len, iov->iov_len);
-
-               if (atomic) {
-                       if (__copy_from_user_inatomic(to, iov->iov_base, copy))
-                               return -EFAULT;
-               } else {
-                       if (copy_from_user(to, iov->iov_base, copy))
-                               return -EFAULT;
-               }
-               to += copy;
-               len -= copy;
-               iov->iov_base += copy;
-               iov->iov_len -= copy;
-       }
-       return 0;
-}
-
-/*
- * Pre-fault in the user memory, so we can use atomic copies.
- */
-static void iov_fault_in_pages_read(struct iovec *iov, unsigned long len)
-{
-       while (!iov->iov_len)
-               iov++;
-
-       while (len > 0) {
-               unsigned long this_len;
-
-               this_len = min_t(unsigned long, len, iov->iov_len);
-               fault_in_pages_readable(iov->iov_base, this_len);
-               len -= this_len;
-               iov++;
-       }
-}
-
 static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
                                  struct pipe_buffer *buf)
 {
@@ -271,24 +227,18 @@ static const struct pipe_buf_operations packet_pipe_buf_ops = {
 };
 
 static ssize_t
-pipe_read(struct kiocb *iocb, const struct iovec *_iov,
-          unsigned long nr_segs, loff_t pos)
+pipe_read(struct kiocb *iocb, struct iov_iter *to)
 {
+       size_t total_len = iov_iter_count(to);
        struct file *filp = iocb->ki_filp;
        struct pipe_inode_info *pipe = filp->private_data;
        int do_wakeup;
        ssize_t ret;
-       struct iovec *iov = (struct iovec *)_iov;
-       size_t total_len;
-       struct iov_iter iter;
 
-       total_len = iov_length(iov, nr_segs);
        /* Null read succeeds. */
        if (unlikely(total_len == 0))
                return 0;
 
-       iov_iter_init(&iter, iov, nr_segs, total_len, 0);
-
        do_wakeup = 0;
        ret = 0;
        __pipe_lock(pipe);
@@ -312,7 +262,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
                                break;
                        }
 
-                       written = copy_page_to_iter(buf->page, buf->offset, chars, &iter);
+                       written = copy_page_to_iter(buf->page, buf->offset, chars, to);
                        if (unlikely(written < chars)) {
                                if (!ret)
                                        ret = -EFAULT;
@@ -386,24 +336,19 @@ static inline int is_packetized(struct file *file)
 }
 
 static ssize_t
-pipe_write(struct kiocb *iocb, const struct iovec *_iov,
-           unsigned long nr_segs, loff_t ppos)
+pipe_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *filp = iocb->ki_filp;
        struct pipe_inode_info *pipe = filp->private_data;
-       ssize_t ret;
-       int do_wakeup;
-       struct iovec *iov = (struct iovec *)_iov;
-       size_t total_len;
+       ssize_t ret = 0;
+       int do_wakeup = 0;
+       size_t total_len = iov_iter_count(from);
        ssize_t chars;
 
-       total_len = iov_length(iov, nr_segs);
        /* Null write succeeds. */
        if (unlikely(total_len == 0))
                return 0;
 
-       do_wakeup = 0;
-       ret = 0;
        __pipe_lock(pipe);
 
        if (!pipe->readers) {
@@ -422,38 +367,19 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov,
                int offset = buf->offset + buf->len;
 
                if (ops->can_merge && offset + chars <= PAGE_SIZE) {
-                       int error, atomic = 1;
-                       void *addr;
-
-                       error = ops->confirm(pipe, buf);
+                       int error = ops->confirm(pipe, buf);
                        if (error)
                                goto out;
 
-                       iov_fault_in_pages_read(iov, chars);
-redo1:
-                       if (atomic)
-                               addr = kmap_atomic(buf->page);
-                       else
-                               addr = kmap(buf->page);
-                       error = pipe_iov_copy_from_user(offset + addr, iov,
-                                                       chars, atomic);
-                       if (atomic)
-                               kunmap_atomic(addr);
-                       else
-                               kunmap(buf->page);
-                       ret = error;
-                       do_wakeup = 1;
-                       if (error) {
-                               if (atomic) {
-                                       atomic = 0;
-                                       goto redo1;
-                               }
+                       ret = copy_page_from_iter(buf->page, offset, chars, from);
+                       if (unlikely(ret < chars)) {
+                               error = -EFAULT;
                                goto out;
                        }
+                       do_wakeup = 1;
                        buf->len += chars;
-                       total_len -= chars;
                        ret = chars;
-                       if (!total_len)
+                       if (!iov_iter_count(from))
                                goto out;
                }
        }
@@ -472,8 +398,7 @@ redo1:
                        int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1);
                        struct pipe_buffer *buf = pipe->bufs + newbuf;
                        struct page *page = pipe->tmp_page;
-                       char *src;
-                       int error, atomic = 1;
+                       int copied;
 
                        if (!page) {
                                page = alloc_page(GFP_HIGHUSER);
@@ -489,40 +414,19 @@ redo1:
                         * FIXME! Is this really true?
                         */
                        do_wakeup = 1;
-                       chars = PAGE_SIZE;
-                       if (chars > total_len)
-                               chars = total_len;
-
-                       iov_fault_in_pages_read(iov, chars);
-redo2:
-                       if (atomic)
-                               src = kmap_atomic(page);
-                       else
-                               src = kmap(page);
-
-                       error = pipe_iov_copy_from_user(src, iov, chars,
-                                                       atomic);
-                       if (atomic)
-                               kunmap_atomic(src);
-                       else
-                               kunmap(page);
-
-                       if (unlikely(error)) {
-                               if (atomic) {
-                                       atomic = 0;
-                                       goto redo2;
-                               }
+                       copied = copy_page_from_iter(page, 0, PAGE_SIZE, from);
+                       if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) {
                                if (!ret)
-                                       ret = error;
+                                       ret = -EFAULT;
                                break;
                        }
-                       ret += chars;
+                       ret += copied;
 
                        /* Insert it into the buffer array */
                        buf->page = page;
                        buf->ops = &anon_pipe_buf_ops;
                        buf->offset = 0;
-                       buf->len = chars;
+                       buf->len = copied;
                        buf->flags = 0;
                        if (is_packetized(filp)) {
                                buf->ops = &packet_pipe_buf_ops;
@@ -531,8 +435,7 @@ redo2:
                        pipe->nrbufs = ++bufs;
                        pipe->tmp_page = NULL;
 
-                       total_len -= chars;
-                       if (!total_len)
+                       if (!iov_iter_count(from))
                                break;
                }
                if (bufs < pipe->buffers)
@@ -1044,10 +947,10 @@ err:
 const struct file_operations pipefifo_fops = {
        .open           = fifo_open,
        .llseek         = no_llseek,
-       .read           = do_sync_read,
-       .aio_read       = pipe_read,
-       .write          = do_sync_write,
-       .aio_write      = pipe_write,
+       .read           = new_sync_read,
+       .read_iter      = pipe_read,
+       .write          = new_sync_write,
+       .write_iter     = pipe_write,
        .poll           = pipe_poll,
        .unlocked_ioctl = pipe_ioctl,
        .release        = pipe_release,
index 1e56a4e8cf7cd47d4886731ea063c95be9f078ee..4f56de822d2f5995b81006e0bc9783d321b1621d 100644 (file)
 #include "internal.h"
 
 const struct file_operations ramfs_file_operations = {
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .fsync          = noop_fsync,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .llseek         = generic_file_llseek,
 };
 
index 0b3d8e4cb2fa00dd8b906d1ddc811bc17a4c8e07..dda012ad4208d3192521c80a082af5ff038f5b3b 100644 (file)
@@ -37,13 +37,13 @@ static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma);
 const struct file_operations ramfs_file_operations = {
        .mmap                   = ramfs_nommu_mmap,
        .get_unmapped_area      = ramfs_nommu_get_unmapped_area,
-       .read                   = do_sync_read,
-       .aio_read               = generic_file_aio_read,
-       .write                  = do_sync_write,
-       .aio_write              = generic_file_aio_write,
+       .read                   = new_sync_read,
+       .read_iter              = generic_file_read_iter,
+       .write                  = new_sync_write,
+       .write_iter             = generic_file_write_iter,
        .fsync                  = noop_fsync,
        .splice_read            = generic_file_splice_read,
-       .splice_write           = generic_file_splice_write,
+       .splice_write           = iter_file_splice_write,
        .llseek                 = generic_file_llseek,
 };
 
index 31c6efa431839e41f4b39b314cb640dd89b68ecc..009d8542a889c7d2b4b98334f0c4868d36076739 100644 (file)
 typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
 typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
                unsigned long, loff_t);
+typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);
 
 const struct file_operations generic_ro_fops = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
        .mmap           = generic_file_readonly_mmap,
        .splice_read    = generic_file_splice_read,
 };
@@ -390,13 +391,34 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp
 
 EXPORT_SYMBOL(do_sync_read);
 
+ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+{
+       struct iovec iov = { .iov_base = buf, .iov_len = len };
+       struct kiocb kiocb;
+       struct iov_iter iter;
+       ssize_t ret;
+
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = *ppos;
+       kiocb.ki_nbytes = len;
+       iov_iter_init(&iter, READ, &iov, 1, len);
+
+       ret = filp->f_op->read_iter(&kiocb, &iter);
+       if (-EIOCBQUEUED == ret)
+               ret = wait_on_sync_kiocb(&kiocb);
+       *ppos = kiocb.ki_pos;
+       return ret;
+}
+
+EXPORT_SYMBOL(new_sync_read);
+
 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
 {
        ssize_t ret;
 
        if (!(file->f_mode & FMODE_READ))
                return -EBADF;
-       if (!file->f_op->read && !file->f_op->aio_read)
+       if (!(file->f_mode & FMODE_CAN_READ))
                return -EINVAL;
        if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
                return -EFAULT;
@@ -406,8 +428,10 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
                count = ret;
                if (file->f_op->read)
                        ret = file->f_op->read(file, buf, count, pos);
-               else
+               else if (file->f_op->aio_read)
                        ret = do_sync_read(file, buf, count, pos);
+               else
+                       ret = new_sync_read(file, buf, count, pos);
                if (ret > 0) {
                        fsnotify_access(file);
                        add_rchar(current, ret);
@@ -439,13 +463,34 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof
 
 EXPORT_SYMBOL(do_sync_write);
 
+ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
+{
+       struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
+       struct kiocb kiocb;
+       struct iov_iter iter;
+       ssize_t ret;
+
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = *ppos;
+       kiocb.ki_nbytes = len;
+       iov_iter_init(&iter, WRITE, &iov, 1, len);
+
+       ret = filp->f_op->write_iter(&kiocb, &iter);
+       if (-EIOCBQUEUED == ret)
+               ret = wait_on_sync_kiocb(&kiocb);
+       *ppos = kiocb.ki_pos;
+       return ret;
+}
+
+EXPORT_SYMBOL(new_sync_write);
+
 ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
 {
        mm_segment_t old_fs;
        const char __user *p;
        ssize_t ret;
 
-       if (!file->f_op->write && !file->f_op->aio_write)
+       if (!(file->f_mode & FMODE_CAN_WRITE))
                return -EINVAL;
 
        old_fs = get_fs();
@@ -455,8 +500,10 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t
                count =  MAX_RW_COUNT;
        if (file->f_op->write)
                ret = file->f_op->write(file, p, count, pos);
-       else
+       else if (file->f_op->aio_write)
                ret = do_sync_write(file, p, count, pos);
+       else
+               ret = new_sync_write(file, p, count, pos);
        set_fs(old_fs);
        if (ret > 0) {
                fsnotify_modify(file);
@@ -472,7 +519,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
 
        if (!(file->f_mode & FMODE_WRITE))
                return -EBADF;
-       if (!file->f_op->write && !file->f_op->aio_write)
+       if (!(file->f_mode & FMODE_CAN_WRITE))
                return -EINVAL;
        if (unlikely(!access_ok(VERIFY_READ, buf, count)))
                return -EFAULT;
@@ -483,8 +530,10 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
                file_start_write(file);
                if (file->f_op->write)
                        ret = file->f_op->write(file, buf, count, pos);
-               else
+               else if (file->f_op->aio_write)
                        ret = do_sync_write(file, buf, count, pos);
+               else
+                       ret = new_sync_write(file, buf, count, pos);
                if (ret > 0) {
                        fsnotify_modify(file);
                        add_wchar(current, ret);
@@ -601,6 +650,25 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
 }
 EXPORT_SYMBOL(iov_shorten);
 
+static ssize_t do_iter_readv_writev(struct file *filp, int rw, const struct iovec *iov,
+               unsigned long nr_segs, size_t len, loff_t *ppos, iter_fn_t fn)
+{
+       struct kiocb kiocb;
+       struct iov_iter iter;
+       ssize_t ret;
+
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = *ppos;
+       kiocb.ki_nbytes = len;
+
+       iov_iter_init(&iter, rw, iov, nr_segs, len);
+       ret = fn(&kiocb, &iter);
+       if (ret == -EIOCBQUEUED)
+               ret = wait_on_sync_kiocb(&kiocb);
+       *ppos = kiocb.ki_pos;
+       return ret;
+}
+
 static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
                unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
 {
@@ -738,6 +806,7 @@ static ssize_t do_readv_writev(int type, struct file *file,
        ssize_t ret;
        io_fn_t fn;
        iov_fn_t fnv;
+       iter_fn_t iter_fn;
 
        ret = rw_copy_check_uvector(type, uvector, nr_segs,
                                    ARRAY_SIZE(iovstack), iovstack, &iov);
@@ -753,13 +822,18 @@ static ssize_t do_readv_writev(int type, struct file *file,
        if (type == READ) {
                fn = file->f_op->read;
                fnv = file->f_op->aio_read;
+               iter_fn = file->f_op->read_iter;
        } else {
                fn = (io_fn_t)file->f_op->write;
                fnv = file->f_op->aio_write;
+               iter_fn = file->f_op->write_iter;
                file_start_write(file);
        }
 
-       if (fnv)
+       if (iter_fn)
+               ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len,
+                                               pos, iter_fn);
+       else if (fnv)
                ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
                                                pos, fnv);
        else
@@ -785,7 +859,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
 {
        if (!(file->f_mode & FMODE_READ))
                return -EBADF;
-       if (!file->f_op->aio_read && !file->f_op->read)
+       if (!(file->f_mode & FMODE_CAN_READ))
                return -EINVAL;
 
        return do_readv_writev(READ, file, vec, vlen, pos);
@@ -798,7 +872,7 @@ ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
 {
        if (!(file->f_mode & FMODE_WRITE))
                return -EBADF;
-       if (!file->f_op->aio_write && !file->f_op->write)
+       if (!(file->f_mode & FMODE_CAN_WRITE))
                return -EINVAL;
 
        return do_readv_writev(WRITE, file, vec, vlen, pos);
@@ -912,6 +986,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
        ssize_t ret;
        io_fn_t fn;
        iov_fn_t fnv;
+       iter_fn_t iter_fn;
 
        ret = compat_rw_copy_check_uvector(type, uvector, nr_segs,
                                               UIO_FASTIOV, iovstack, &iov);
@@ -927,13 +1002,18 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
        if (type == READ) {
                fn = file->f_op->read;
                fnv = file->f_op->aio_read;
+               iter_fn = file->f_op->read_iter;
        } else {
                fn = (io_fn_t)file->f_op->write;
                fnv = file->f_op->aio_write;
+               iter_fn = file->f_op->write_iter;
                file_start_write(file);
        }
 
-       if (fnv)
+       if (iter_fn)
+               ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len,
+                                               pos, iter_fn);
+       else if (fnv)
                ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
                                                pos, fnv);
        else
@@ -964,7 +1044,7 @@ static size_t compat_readv(struct file *file,
                goto out;
 
        ret = -EINVAL;
-       if (!file->f_op->aio_read && !file->f_op->read)
+       if (!(file->f_mode & FMODE_CAN_READ))
                goto out;
 
        ret = compat_do_readv_writev(READ, file, vec, vlen, pos);
@@ -1041,7 +1121,7 @@ static size_t compat_writev(struct file *file,
                goto out;
 
        ret = -EINVAL;
-       if (!file->f_op->aio_write && !file->f_op->write)
+       if (!(file->f_mode & FMODE_CAN_WRITE))
                goto out;
 
        ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);
index ed58d843d57856ac3cdc87288465d0d5156708e9..f070cc827456b68cc3dd3a79bab4009a2c5a2924 100644 (file)
@@ -235,8 +235,8 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
 }
 
 const struct file_operations reiserfs_file_operations = {
-       .read = do_sync_read,
-       .write = do_sync_write,
+       .read = new_sync_read,
+       .write = new_sync_write,
        .unlocked_ioctl = reiserfs_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = reiserfs_compat_ioctl,
@@ -245,10 +245,10 @@ const struct file_operations reiserfs_file_operations = {
        .open = reiserfs_file_open,
        .release = reiserfs_file_release,
        .fsync = reiserfs_sync_file,
-       .aio_read = generic_file_aio_read,
-       .aio_write = generic_file_aio_write,
+       .read_iter = generic_file_read_iter,
+       .write_iter = generic_file_write_iter,
        .splice_read = generic_file_splice_read,
-       .splice_write = generic_file_splice_write,
+       .splice_write = iter_file_splice_write,
        .llseek = generic_file_llseek,
 };
 
index bc8b8009897df3886bee8ed953d55fd36ec6f812..b8003e8dd1f47bf726d78a1f1a40aba7a56ecc30 100644 (file)
@@ -3083,15 +3083,15 @@ static int reiserfs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 /* We thank Mingming Cao for helping us understand in great detail what
    to do in this section of the code. */
 static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
-                                 const struct iovec *iov, loff_t offset,
-                                 unsigned long nr_segs)
+                                 struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                 reiserfs_get_blocks_direct_io);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset,
+                                reiserfs_get_blocks_direct_io);
 
        /*
         * In case of error extending write may have instantiated a few
@@ -3099,7 +3099,7 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
         */
        if (unlikely((rw & WRITE) && ret < 0)) {
                loff_t isize = i_size_read(inode);
-               loff_t end = offset + iov_length(iov, nr_segs);
+               loff_t end = offset + count;
 
                if ((end > isize) && inode_newsize_ok(inode, isize) == 0) {
                        truncate_setsize(inode, isize);
index f373bde8f545da481ba0a7caa873271dd599b30d..ea06c7554860d7ada89db9ba0a8838e17b40d3fc 100644 (file)
@@ -72,8 +72,8 @@ static int romfs_mmap(struct file *file, struct vm_area_struct *vma)
 
 const struct file_operations romfs_ro_fops = {
        .llseek                 = generic_file_llseek,
-       .read                   = do_sync_read,
-       .aio_read               = generic_file_aio_read,
+       .read                   = new_sync_read,
+       .read_iter              = generic_file_read_iter,
        .splice_read            = generic_file_splice_read,
        .mmap                   = romfs_mmap,
        .get_unmapped_area      = romfs_get_unmapped_area,
index 9bc07d2b53cf3a0e66605912386f9d2367601585..9dc23de0f146cba6d4d5423a131d59c219d6eb9c 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/gfp.h>
 #include <linux/socket.h>
 #include <linux/compat.h>
+#include <linux/aio.h>
 #include "internal.h"
 
 /*
@@ -717,63 +718,6 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe,
                                    sd->len, &pos, more);
 }
 
-/*
- * This is a little more tricky than the file -> pipe splicing. There are
- * basically three cases:
- *
- *     - Destination page already exists in the address space and there
- *       are users of it. For that case we have no other option that
- *       copying the data. Tough luck.
- *     - Destination page already exists in the address space, but there
- *       are no users of it. Make sure it's uptodate, then drop it. Fall
- *       through to last case.
- *     - Destination page does not exist, we can add the pipe page to
- *       the page cache and avoid the copy.
- *
- * If asked to move pages to the output file (SPLICE_F_MOVE is set in
- * sd->flags), we attempt to migrate pages from the pipe to the output
- * file address space page cache. This is possible if no one else has
- * the pipe page referenced outside of the pipe and page cache. If
- * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create
- * a new page in the output file page cache and fill/dirty that.
- */
-int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
-                struct splice_desc *sd)
-{
-       struct file *file = sd->u.file;
-       struct address_space *mapping = file->f_mapping;
-       unsigned int offset, this_len;
-       struct page *page;
-       void *fsdata;
-       int ret;
-
-       offset = sd->pos & ~PAGE_CACHE_MASK;
-
-       this_len = sd->len;
-       if (this_len + offset > PAGE_CACHE_SIZE)
-               this_len = PAGE_CACHE_SIZE - offset;
-
-       ret = pagecache_write_begin(file, mapping, sd->pos, this_len,
-                               AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata);
-       if (unlikely(ret))
-               goto out;
-
-       if (buf->page != page) {
-               char *src = kmap_atomic(buf->page);
-               char *dst = kmap_atomic(page);
-
-               memcpy(dst + offset, src + buf->offset, this_len);
-               flush_dcache_page(page);
-               kunmap_atomic(dst);
-               kunmap_atomic(src);
-       }
-       ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len,
-                               page, fsdata);
-out:
-       return ret;
-}
-EXPORT_SYMBOL(pipe_to_file);
-
 static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
 {
        smp_mb();
@@ -802,7 +746,7 @@ static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
  *    locking is required around copying the pipe buffers to the
  *    destination.
  */
-int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
+static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
                          splice_actor *actor)
 {
        int ret;
@@ -849,7 +793,6 @@ int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
 
        return 1;
 }
-EXPORT_SYMBOL(splice_from_pipe_feed);
 
 /**
  * splice_from_pipe_next - wait for some data to splice from
@@ -861,7 +804,7 @@ EXPORT_SYMBOL(splice_from_pipe_feed);
  *    value (one) if pipe buffers are available.  It will return zero
  *    or -errno if no more data needs to be spliced.
  */
-int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
+static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
 {
        while (!pipe->nrbufs) {
                if (!pipe->writers)
@@ -886,7 +829,6 @@ int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
 
        return 1;
 }
-EXPORT_SYMBOL(splice_from_pipe_next);
 
 /**
  * splice_from_pipe_begin - start splicing from pipe
@@ -897,12 +839,11 @@ EXPORT_SYMBOL(splice_from_pipe_next);
  *    splice_from_pipe_next() and splice_from_pipe_feed() to
  *    initialize the necessary fields of @sd.
  */
-void splice_from_pipe_begin(struct splice_desc *sd)
+static void splice_from_pipe_begin(struct splice_desc *sd)
 {
        sd->num_spliced = 0;
        sd->need_wakeup = false;
 }
-EXPORT_SYMBOL(splice_from_pipe_begin);
 
 /**
  * splice_from_pipe_end - finish splicing from pipe
@@ -914,12 +855,11 @@ EXPORT_SYMBOL(splice_from_pipe_begin);
  *    be called after a loop containing splice_from_pipe_next() and
  *    splice_from_pipe_feed().
  */
-void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)
+static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)
 {
        if (sd->need_wakeup)
                wakeup_pipe_writers(pipe);
 }
-EXPORT_SYMBOL(splice_from_pipe_end);
 
 /**
  * __splice_from_pipe - splice data from a pipe to given actor
@@ -985,7 +925,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
 }
 
 /**
- * generic_file_splice_write - splice data from a pipe to a file
+ * iter_file_splice_write - splice data from a pipe to a file
  * @pipe:      pipe info
  * @out:       file to write to
  * @ppos:      position in @out
@@ -995,40 +935,121 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
  * Description:
  *    Will either move or copy pages (determined by @flags options) from
  *    the given pipe inode to the given file.
+ *    This one is ->write_iter-based.
  *
  */
 ssize_t
-generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
+iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
                          loff_t *ppos, size_t len, unsigned int flags)
 {
-       struct address_space *mapping = out->f_mapping;
-       struct inode *inode = mapping->host;
        struct splice_desc sd = {
                .total_len = len,
                .flags = flags,
                .pos = *ppos,
                .u.file = out,
        };
+       int nbufs = pipe->buffers;
+       struct bio_vec *array = kcalloc(nbufs, sizeof(struct bio_vec),
+                                       GFP_KERNEL);
        ssize_t ret;
 
+       if (unlikely(!array))
+               return -ENOMEM;
+
        pipe_lock(pipe);
 
        splice_from_pipe_begin(&sd);
-       do {
+       while (sd.total_len) {
+               struct iov_iter from;
+               struct kiocb kiocb;
+               size_t count = 0;
+               int n, idx;
+
                ret = splice_from_pipe_next(pipe, &sd);
                if (ret <= 0)
                        break;
 
-               mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
-               ret = file_remove_suid(out);
-               if (!ret) {
-                       ret = file_update_time(out);
-                       if (!ret)
-                               ret = splice_from_pipe_feed(pipe, &sd,
-                                                           pipe_to_file);
+               if (unlikely(nbufs < pipe->buffers)) {
+                       kfree(array);
+                       nbufs = pipe->buffers;
+                       array = kcalloc(nbufs, sizeof(struct bio_vec),
+                                       GFP_KERNEL);
+                       if (!array) {
+                               ret = -ENOMEM;
+                               break;
+                       }
                }
-               mutex_unlock(&inode->i_mutex);
-       } while (ret > 0);
+                               
+               /* build the vector */
+               for (n = 0, idx = pipe->curbuf; n < pipe->nrbufs; n++, idx++) {
+                       struct pipe_buffer *buf = pipe->bufs + idx;
+                       size_t this_len = buf->len;
+
+                       if (this_len > sd.total_len)
+                               this_len = sd.total_len;
+
+                       if (idx == pipe->buffers - 1)
+                               idx = -1;
+
+                       ret = buf->ops->confirm(pipe, buf);
+                       if (unlikely(ret)) {
+                               if (ret == -ENODATA)
+                                       ret = 0;
+                               goto done;
+                       }
+
+                       array[n].bv_page = buf->page;
+                       array[n].bv_len = this_len;
+                       array[n].bv_offset = buf->offset;
+                       count += this_len;
+               }
+
+               /* ... iov_iter */
+               from.type = ITER_BVEC | WRITE;
+               from.bvec = array;
+               from.nr_segs = n;
+               from.count = count;
+               from.iov_offset = 0;
+
+               /* ... and iocb */
+               init_sync_kiocb(&kiocb, out);
+               kiocb.ki_pos = sd.pos;
+               kiocb.ki_nbytes = count;
+
+               /* now, send it */
+               ret = out->f_op->write_iter(&kiocb, &from);
+               if (-EIOCBQUEUED == ret)
+                       ret = wait_on_sync_kiocb(&kiocb);
+
+               if (ret <= 0)
+                       break;
+
+               sd.num_spliced += ret;
+               sd.total_len -= ret;
+               *ppos = sd.pos = kiocb.ki_pos;
+
+               /* dismiss the fully eaten buffers, adjust the partial one */
+               while (ret) {
+                       struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
+                       if (ret >= buf->len) {
+                               const struct pipe_buf_operations *ops = buf->ops;
+                               ret -= buf->len;
+                               buf->len = 0;
+                               buf->ops = NULL;
+                               ops->release(pipe, buf);
+                               pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
+                               pipe->nrbufs--;
+                               if (pipe->files)
+                                       sd.need_wakeup = true;
+                       } else {
+                               buf->offset += ret;
+                               buf->len -= ret;
+                               ret = 0;
+                       }
+               }
+       }
+done:
+       kfree(array);
        splice_from_pipe_end(pipe, &sd);
 
        pipe_unlock(pipe);
@@ -1036,21 +1057,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
        if (sd.num_spliced)
                ret = sd.num_spliced;
 
-       if (ret > 0) {
-               int err;
-
-               err = generic_write_sync(out, *ppos, ret);
-               if (err)
-                       ret = err;
-               else
-                       *ppos += ret;
-               balance_dirty_pages_ratelimited(mapping);
-       }
-
        return ret;
 }
 
-EXPORT_SYMBOL(generic_file_splice_write);
+EXPORT_SYMBOL(iter_file_splice_write);
 
 static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                          struct splice_desc *sd)
@@ -1548,7 +1558,7 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
        if (ret <= 0)
                return ret;
 
-       iov_iter_init(&iter, iov, nr_segs, count, 0);
+       iov_iter_init(&iter, READ, iov, nr_segs, count);
 
        sd.len = 0;
        sd.total_len = count;
index 9d4dc6831792a23270148c2d26b0423f656b505c..b00811c75b24f63acb1651991f6972f4b0b6ff54 100644 (file)
  */
 const struct file_operations sysv_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .fsync          = generic_file_fsync,
        .splice_read    = generic_file_splice_read,
index 4f34dbae823dc9930077a4599933e14b7e457de9..0888502a60415223ba9285447c9e2f4425bc4076 100644 (file)
@@ -1363,17 +1363,17 @@ static inline int mctime_update_needed(const struct inode *inode,
 
 /**
  * update_ctime - update mtime and ctime of an inode.
- * @c: UBIFS file-system description object
  * @inode: inode to update
  *
  * This function updates mtime and ctime of the inode if it is not equivalent to
  * current time. Returns zero in case of success and a negative error code in
  * case of failure.
  */
-static int update_mctime(struct ubifs_info *c, struct inode *inode)
+static int update_mctime(struct inode *inode)
 {
        struct timespec now = ubifs_current_time(inode);
        struct ubifs_inode *ui = ubifs_inode(inode);
+       struct ubifs_info *c = inode->i_sb->s_fs_info;
 
        if (mctime_update_needed(inode, &now)) {
                int err, release;
@@ -1396,18 +1396,13 @@ static int update_mctime(struct ubifs_info *c, struct inode *inode)
        return 0;
 }
 
-static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t pos)
+static ssize_t ubifs_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
-       int err;
-       struct inode *inode = iocb->ki_filp->f_mapping->host;
-       struct ubifs_info *c = inode->i_sb->s_fs_info;
-
-       err = update_mctime(c, inode);
+       int err = update_mctime(file_inode(iocb->ki_filp));
        if (err)
                return err;
 
-       return generic_file_aio_write(iocb, iov, nr_segs, pos);
+       return generic_file_write_iter(iocb, from);
 }
 
 static int ubifs_set_page_dirty(struct page *page)
@@ -1582,15 +1577,15 @@ const struct inode_operations ubifs_symlink_inode_operations = {
 
 const struct file_operations ubifs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = generic_file_aio_read,
-       .aio_write      = ubifs_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = generic_file_read_iter,
+       .write_iter     = ubifs_write_iter,
        .mmap           = ubifs_file_mmap,
        .fsync          = ubifs_fsync,
        .unlocked_ioctl = ubifs_ioctl,
        .splice_read    = generic_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ubifs_compat_ioctl,
 #endif
index a1266089eca1fc0054065dfc723e697daf5691e6..a81c7b556896115a4afbdea5452523057ccd195f 100644 (file)
@@ -1556,7 +1556,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
        if (c->space_fixup) {
                err = ubifs_fixup_free_space(c);
                if (err)
-                       return err;
+                       goto out;
        }
 
        err = check_free_space(c);
index d2c170f8b035a4b21ef6eac2274e74b137346d56..d80738fdf424cd61579a0544eab720bb8d7b0a64 100644 (file)
@@ -119,8 +119,8 @@ static int udf_adinicb_write_end(struct file *file,
 }
 
 static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb,
-                                    const struct iovec *iov,
-                                    loff_t offset, unsigned long nr_segs)
+                                    struct iov_iter *iter,
+                                    loff_t offset)
 {
        /* Fallback to buffered I/O. */
        return 0;
@@ -134,8 +134,7 @@ const struct address_space_operations udf_adinicb_aops = {
        .direct_IO      = udf_adinicb_direct_IO,
 };
 
-static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                                 unsigned long nr_segs, loff_t ppos)
+static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        ssize_t retval;
        struct file *file = iocb->ki_filp;
@@ -150,7 +149,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                if (file->f_flags & O_APPEND)
                        pos = inode->i_size;
                else
-                       pos = ppos;
+                       pos = iocb->ki_pos;
 
                if (inode->i_sb->s_blocksize <
                                (udf_file_entry_alloc_offset(inode) +
@@ -171,7 +170,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        } else
                up_write(&iinfo->i_data_sem);
 
-       retval = __generic_file_aio_write(iocb, iov, nr_segs);
+       retval = __generic_file_write_iter(iocb, from);
        mutex_unlock(&inode->i_mutex);
 
        if (retval > 0) {
@@ -252,13 +251,13 @@ static int udf_release_file(struct inode *inode, struct file *filp)
 }
 
 const struct file_operations udf_file_operations = {
-       .read                   = do_sync_read,
-       .aio_read               = generic_file_aio_read,
+       .read                   = new_sync_read,
+       .read_iter              = generic_file_read_iter,
        .unlocked_ioctl         = udf_ioctl,
        .open                   = generic_file_open,
        .mmap                   = generic_file_mmap,
-       .write                  = do_sync_write,
-       .aio_write              = udf_file_aio_write,
+       .write                  = new_sync_write,
+       .write_iter             = udf_file_write_iter,
        .release                = udf_release_file,
        .fsync                  = generic_file_fsync,
        .splice_read            = generic_file_splice_read,
index 5d643706212f411a63b0804d4c896941aecb13d8..236cd48184c2df20e75bc9fee098ded782f2560f 100644 (file)
@@ -217,18 +217,18 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,
 }
 
 static ssize_t udf_direct_IO(int rw, struct kiocb *iocb,
-                            const struct iovec *iov,
-                            loff_t offset, unsigned long nr_segs)
+                            struct iov_iter *iter,
+                            loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
-       ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
-                                 udf_get_block);
+       ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, udf_get_block);
        if (unlikely(ret < 0 && (rw & WRITE)))
-               udf_write_failed(mapping, offset + iov_length(iov, nr_segs));
+               udf_write_failed(mapping, offset + count);
        return ret;
 }
 
index 33afa20d450982eafb4e1bcc77193cce152270d1..c84ec010a6761ff683e732973bd8780d989e6531 100644 (file)
  
 const struct file_operations ufs_file_operations = {
        .llseek         = generic_file_llseek,
-       .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
-       .write          = do_sync_write,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .read_iter      = generic_file_read_iter,
+       .write          = new_sync_write,
+       .write_iter     = generic_file_write_iter,
        .mmap           = generic_file_mmap,
        .open           = generic_file_open,
        .fsync          = generic_file_fsync,
index 0fdd4109c62439b7471b46135a068148b1006d87..6e247a99f5dbce65c0b97f0261209f52e75951b7 100644 (file)
@@ -160,30 +160,38 @@ typedef struct xfs_agi {
         * still being referenced.
         */
        __be32          agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
-
+       /*
+        * This marks the end of logging region 1 and start of logging region 2.
+        */
        uuid_t          agi_uuid;       /* uuid of filesystem */
        __be32          agi_crc;        /* crc of agi sector */
        __be32          agi_pad32;
        __be64          agi_lsn;        /* last write sequence */
 
+       __be32          agi_free_root; /* root of the free inode btree */
+       __be32          agi_free_level;/* levels in free inode btree */
+
        /* structure must be padded to 64 bit alignment */
 } xfs_agi_t;
 
 #define XFS_AGI_CRC_OFF                offsetof(struct xfs_agi, agi_crc)
 
-#define        XFS_AGI_MAGICNUM        0x00000001
-#define        XFS_AGI_VERSIONNUM      0x00000002
-#define        XFS_AGI_SEQNO           0x00000004
-#define        XFS_AGI_LENGTH          0x00000008
-#define        XFS_AGI_COUNT           0x00000010
-#define        XFS_AGI_ROOT            0x00000020
-#define        XFS_AGI_LEVEL           0x00000040
-#define        XFS_AGI_FREECOUNT       0x00000080
-#define        XFS_AGI_NEWINO          0x00000100
-#define        XFS_AGI_DIRINO          0x00000200
-#define        XFS_AGI_UNLINKED        0x00000400
-#define        XFS_AGI_NUM_BITS        11
-#define        XFS_AGI_ALL_BITS        ((1 << XFS_AGI_NUM_BITS) - 1)
+#define        XFS_AGI_MAGICNUM        (1 << 0)
+#define        XFS_AGI_VERSIONNUM      (1 << 1)
+#define        XFS_AGI_SEQNO           (1 << 2)
+#define        XFS_AGI_LENGTH          (1 << 3)
+#define        XFS_AGI_COUNT           (1 << 4)
+#define        XFS_AGI_ROOT            (1 << 5)
+#define        XFS_AGI_LEVEL           (1 << 6)
+#define        XFS_AGI_FREECOUNT       (1 << 7)
+#define        XFS_AGI_NEWINO          (1 << 8)
+#define        XFS_AGI_DIRINO          (1 << 9)
+#define        XFS_AGI_UNLINKED        (1 << 10)
+#define        XFS_AGI_NUM_BITS_R1     11      /* end of the 1st agi logging region */
+#define        XFS_AGI_ALL_BITS_R1     ((1 << XFS_AGI_NUM_BITS_R1) - 1)
+#define        XFS_AGI_FREE_ROOT       (1 << 11)
+#define        XFS_AGI_FREE_LEVEL      (1 << 12)
+#define        XFS_AGI_NUM_BITS_R2     13
 
 /* disk block (xfs_daddr_t) in the AG */
 #define XFS_AGI_DADDR(mp)      ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
index cc1eadcbb0497ea6163b045dacb740481db27fe6..8358f1ded94df6a548ca5c41ca05255b719ddd59 100644 (file)
@@ -70,7 +70,6 @@ xfs_allocbt_alloc_block(
        struct xfs_btree_cur    *cur,
        union xfs_btree_ptr     *start,
        union xfs_btree_ptr     *new,
-       int                     length,
        int                     *stat)
 {
        int                     error;
index 0479c32c5eb1703ba0081f21af9b380e5a3c95cb..08d13e3952524fdfef6fea570955e51eec3824e4 100644 (file)
@@ -1449,9 +1449,8 @@ STATIC ssize_t
 xfs_vm_direct_IO(
        int                     rw,
        struct kiocb            *iocb,
-       const struct iovec      *iov,
-       loff_t                  offset,
-       unsigned long           nr_segs)
+       struct iov_iter         *iter,
+       loff_t                  offset)
 {
        struct inode            *inode = iocb->ki_filp->f_mapping->host;
        struct block_device     *bdev = xfs_find_bdev_for_inode(inode);
@@ -1459,7 +1458,7 @@ xfs_vm_direct_IO(
        ssize_t                 ret;
 
        if (rw & WRITE) {
-               size_t size = iov_length(iov, nr_segs);
+               size_t size = iov_iter_count(iter);
 
                /*
                 * We cannot preallocate a size update transaction here as we
@@ -1471,17 +1470,15 @@ xfs_vm_direct_IO(
                if (offset + size > XFS_I(inode)->i_d.di_size)
                        ioend->io_isdirect = 1;
 
-               ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
-                                           offset, nr_segs,
-                                           xfs_get_blocks_direct,
+               ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter,
+                                           offset, xfs_get_blocks_direct,
                                            xfs_end_io_direct_write, NULL,
                                            DIO_ASYNC_EXTEND);
                if (ret != -EIOCBQUEUED && iocb->private)
                        goto out_destroy_ioend;
        } else {
-               ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
-                                           offset, nr_segs,
-                                           xfs_get_blocks_direct,
+               ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter,
+                                           offset, xfs_get_blocks_direct,
                                            NULL, NULL, 0);
        }
 
index 6e37823e2932aeb45d112b55010ab627adb5bde2..41f206c82aacdab6ec367b62e4b38a37644e92e1 100644 (file)
@@ -68,7 +68,6 @@ xfs_attr3_rmt_blocks(
  */
 static bool
 xfs_attr3_rmt_hdr_ok(
-       struct xfs_mount        *mp,
        void                    *ptr,
        xfs_ino_t               ino,
        uint32_t                offset,
@@ -251,7 +250,7 @@ xfs_attr_rmtval_copyout(
                byte_cnt = min(*valuelen, byte_cnt);
 
                if (xfs_sb_version_hascrc(&mp->m_sb)) {
-                       if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset,
+                       if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
                                                  byte_cnt, bno)) {
                                xfs_alert(mp,
 "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
index f0efc7e970ef10658e01be3def9f4b55de0ac6ab..1ff0da6e2bf901159c29c6c23ba6f0b1baa0e331 100644 (file)
@@ -94,7 +94,7 @@ xfs_bmap_compute_maxlevels(
                maxleafents = MAXAEXTNUM;
                sz = XFS_BMDR_SPACE_CALC(MINABTPTRS);
        }
-       maxrootrecs = xfs_bmdr_maxrecs(mp, sz, 0);
+       maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
        minleafrecs = mp->m_bmap_dmnr[0];
        minnoderecs = mp->m_bmap_dmnr[1];
        maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
@@ -233,7 +233,6 @@ xfs_default_attroffset(
  */
 STATIC void
 xfs_bmap_forkoff_reset(
-       xfs_mount_t     *mp,
        xfs_inode_t     *ip,
        int             whichfork)
 {
@@ -905,7 +904,7 @@ xfs_bmap_local_to_extents_empty(
        ASSERT(ifp->if_bytes == 0);
        ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
 
-       xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
+       xfs_bmap_forkoff_reset(ip, whichfork);
        ifp->if_flags &= ~XFS_IFINLINE;
        ifp->if_flags |= XFS_IFEXTENTS;
        XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
@@ -1675,7 +1674,6 @@ xfs_bmap_isaeof(
  */
 int
 xfs_bmap_last_offset(
-       struct xfs_trans        *tp,
        struct xfs_inode        *ip,
        xfs_fileoff_t           *last_block,
        int                     whichfork)
@@ -3517,6 +3515,67 @@ xfs_bmap_adjacent(
 #undef ISVALID
 }
 
+static int
+xfs_bmap_longest_free_extent(
+       struct xfs_trans        *tp,
+       xfs_agnumber_t          ag,
+       xfs_extlen_t            *blen,
+       int                     *notinit)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_perag        *pag;
+       xfs_extlen_t            longest;
+       int                     error = 0;
+
+       pag = xfs_perag_get(mp, ag);
+       if (!pag->pagf_init) {
+               error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK);
+               if (error)
+                       goto out;
+
+               if (!pag->pagf_init) {
+                       *notinit = 1;
+                       goto out;
+               }
+       }
+
+       longest = xfs_alloc_longest_free_extent(mp, pag);
+       if (*blen < longest)
+               *blen = longest;
+
+out:
+       xfs_perag_put(pag);
+       return error;
+}
+
+static void
+xfs_bmap_select_minlen(
+       struct xfs_bmalloca     *ap,
+       struct xfs_alloc_arg    *args,
+       xfs_extlen_t            *blen,
+       int                     notinit)
+{
+       if (notinit || *blen < ap->minlen) {
+               /*
+                * Since we did a BUF_TRYLOCK above, it is possible that
+                * there is space for this request.
+                */
+               args->minlen = ap->minlen;
+       } else if (*blen < args->maxlen) {
+               /*
+                * If the best seen length is less than the request length,
+                * use the best as the minimum.
+                */
+               args->minlen = *blen;
+       } else {
+               /*
+                * Otherwise we've seen an extent as big as maxlen, use that
+                * as the minimum.
+                */
+               args->minlen = args->maxlen;
+       }
+}
+
 STATIC int
 xfs_bmap_btalloc_nullfb(
        struct xfs_bmalloca     *ap,
@@ -3524,111 +3583,74 @@ xfs_bmap_btalloc_nullfb(
        xfs_extlen_t            *blen)
 {
        struct xfs_mount        *mp = ap->ip->i_mount;
-       struct xfs_perag        *pag;
        xfs_agnumber_t          ag, startag;
        int                     notinit = 0;
        int                     error;
 
-       if (ap->userdata && xfs_inode_is_filestream(ap->ip))
-               args->type = XFS_ALLOCTYPE_NEAR_BNO;
-       else
-               args->type = XFS_ALLOCTYPE_START_BNO;
+       args->type = XFS_ALLOCTYPE_START_BNO;
        args->total = ap->total;
 
-       /*
-        * Search for an allocation group with a single extent large enough
-        * for the request.  If one isn't found, then adjust the minimum
-        * allocation size to the largest space found.
-        */
        startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
        if (startag == NULLAGNUMBER)
                startag = ag = 0;
 
-       pag = xfs_perag_get(mp, ag);
        while (*blen < args->maxlen) {
-               if (!pag->pagf_init) {
-                       error = xfs_alloc_pagf_init(mp, args->tp, ag,
-                                                   XFS_ALLOC_FLAG_TRYLOCK);
-                       if (error) {
-                               xfs_perag_put(pag);
-                               return error;
-                       }
-               }
-
-               /*
-                * See xfs_alloc_fix_freelist...
-                */
-               if (pag->pagf_init) {
-                       xfs_extlen_t    longest;
-                       longest = xfs_alloc_longest_free_extent(mp, pag);
-                       if (*blen < longest)
-                               *blen = longest;
-               } else
-                       notinit = 1;
-
-               if (xfs_inode_is_filestream(ap->ip)) {
-                       if (*blen >= args->maxlen)
-                               break;
-
-                       if (ap->userdata) {
-                               /*
-                                * If startag is an invalid AG, we've
-                                * come here once before and
-                                * xfs_filestream_new_ag picked the
-                                * best currently available.
-                                *
-                                * Don't continue looping, since we
-                                * could loop forever.
-                                */
-                               if (startag == NULLAGNUMBER)
-                                       break;
-
-                               error = xfs_filestream_new_ag(ap, &ag);
-                               xfs_perag_put(pag);
-                               if (error)
-                                       return error;
+               error = xfs_bmap_longest_free_extent(args->tp, ag, blen,
+                                                    &notinit);
+               if (error)
+                       return error;
 
-                               /* loop again to set 'blen'*/
-                               startag = NULLAGNUMBER;
-                               pag = xfs_perag_get(mp, ag);
-                               continue;
-                       }
-               }
                if (++ag == mp->m_sb.sb_agcount)
                        ag = 0;
                if (ag == startag)
                        break;
-               xfs_perag_put(pag);
-               pag = xfs_perag_get(mp, ag);
        }
-       xfs_perag_put(pag);
 
-       /*
-        * Since the above loop did a BUF_TRYLOCK, it is
-        * possible that there is space for this request.
-        */
-       if (notinit || *blen < ap->minlen)
-               args->minlen = ap->minlen;
-       /*
-        * If the best seen length is less than the request
-        * length, use the best as the minimum.
-        */
-       else if (*blen < args->maxlen)
-               args->minlen = *blen;
-       /*
-        * Otherwise we've seen an extent as big as maxlen,
-        * use that as the minimum.
-        */
-       else
-               args->minlen = args->maxlen;
+       xfs_bmap_select_minlen(ap, args, blen, notinit);
+       return 0;
+}
+
+STATIC int
+xfs_bmap_btalloc_filestreams(
+       struct xfs_bmalloca     *ap,
+       struct xfs_alloc_arg    *args,
+       xfs_extlen_t            *blen)
+{
+       struct xfs_mount        *mp = ap->ip->i_mount;
+       xfs_agnumber_t          ag;
+       int                     notinit = 0;
+       int                     error;
+
+       args->type = XFS_ALLOCTYPE_NEAR_BNO;
+       args->total = ap->total;
+
+       ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
+       if (ag == NULLAGNUMBER)
+               ag = 0;
+
+       error = xfs_bmap_longest_free_extent(args->tp, ag, blen, &notinit);
+       if (error)
+               return error;
+
+       if (*blen < args->maxlen) {
+               error = xfs_filestream_new_ag(ap, &ag);
+               if (error)
+                       return error;
+
+               error = xfs_bmap_longest_free_extent(args->tp, ag, blen,
+                                                    &notinit);
+               if (error)
+                       return error;
+
+       }
+
+       xfs_bmap_select_minlen(ap, args, blen, notinit);
 
        /*
-        * set the failure fallback case to look in the selected
-        * AG as the stream may have moved.
+        * Set the failure fallback case to look in the selected AG as stream
+        * may have moved.
         */
-       if (xfs_inode_is_filestream(ap->ip))
-               ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
-
+       ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
        return 0;
 }
 
@@ -3708,7 +3730,15 @@ xfs_bmap_btalloc(
        args.firstblock = *ap->firstblock;
        blen = 0;
        if (nullfb) {
-               error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
+               /*
+                * Search for an allocation group with a single extent large
+                * enough for the request.  If one isn't found, then adjust
+                * the minimum allocation size to the largest space found.
+                */
+               if (ap->userdata && xfs_inode_is_filestream(ap->ip))
+                       error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
+               else
+                       error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
                if (error)
                        return error;
        } else if (ap->flist->xbf_low) {
index f84bd7af43bec38bd4493c473f95d32e7f590337..38ba36e9b2f0c5616f018c0e5474da7ce9b42290 100644 (file)
@@ -156,8 +156,8 @@ int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork);
 int    xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_fileoff_t *last_block, int whichfork);
-int    xfs_bmap_last_offset(struct xfs_trans *tp, struct xfs_inode *ip,
-               xfs_fileoff_t *unused, int whichfork);
+int    xfs_bmap_last_offset(struct xfs_inode *ip, xfs_fileoff_t *unused,
+               int whichfork);
 int    xfs_bmap_one_block(struct xfs_inode *ip, int whichfork);
 int    xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip,
                int whichfork);
index 818d546664e7575d4affe27b3e90c178ccd85315..948836c4fd90dec4a768f33a33e63355fd1aa2ca 100644 (file)
@@ -84,7 +84,7 @@ xfs_bmdr_to_bmbt(
        rblock->bb_level = dblock->bb_level;
        ASSERT(be16_to_cpu(rblock->bb_level) > 0);
        rblock->bb_numrecs = dblock->bb_numrecs;
-       dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
+       dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
        fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
        tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
        fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
@@ -443,7 +443,7 @@ xfs_bmbt_to_bmdr(
        ASSERT(rblock->bb_level != 0);
        dblock->bb_level = rblock->bb_level;
        dblock->bb_numrecs = rblock->bb_numrecs;
-       dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
+       dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
        fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
        tkp = XFS_BMDR_KEY_ADDR(dblock, 1);
        fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
@@ -519,7 +519,6 @@ xfs_bmbt_alloc_block(
        struct xfs_btree_cur    *cur,
        union xfs_btree_ptr     *start,
        union xfs_btree_ptr     *new,
-       int                     length,
        int                     *stat)
 {
        xfs_alloc_arg_t         args;           /* block allocation args */
@@ -672,8 +671,7 @@ xfs_bmbt_get_dmaxrecs(
 {
        if (level != cur->bc_nlevels - 1)
                return cur->bc_mp->m_bmap_dmxr[level != 0];
-       return xfs_bmdr_maxrecs(cur->bc_mp, cur->bc_private.b.forksize,
-                               level == 0);
+       return xfs_bmdr_maxrecs(cur->bc_private.b.forksize, level == 0);
 }
 
 STATIC void
@@ -914,7 +912,6 @@ xfs_bmbt_maxrecs(
  */
 int
 xfs_bmdr_maxrecs(
-       struct xfs_mount        *mp,
        int                     blocklen,
        int                     leaf)
 {
index 6e42e1e50b89394e2c0a0a003c339ac03d127445..819a8a4dee952d4648ee6333a7c61ea7dff6e78f 100644 (file)
@@ -130,7 +130,7 @@ extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int,
                        xfs_bmdr_block_t *, int);
 
 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_bmdr_maxrecs(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,
index e80d59fdf89a8b222f05fd69e7bc970c7586c5b9..182bac2bb276f5bfcc89c62ab941a6116f457186 100644 (file)
@@ -43,9 +43,10 @@ kmem_zone_t  *xfs_btree_cur_zone;
  * Btree magic numbers.
  */
 static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
-       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC },
+       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
+         XFS_FIBT_MAGIC },
        { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
-         XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC }
+         XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC }
 };
 #define xfs_btree_magic(cur) \
        xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
@@ -1115,6 +1116,7 @@ xfs_btree_set_refs(
                xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF);
                break;
        case XFS_BTNUM_INO:
+       case XFS_BTNUM_FINO:
                xfs_buf_set_ref(bp, XFS_INO_BTREE_REF);
                break;
        case XFS_BTNUM_BMAP:
@@ -1159,7 +1161,6 @@ STATIC int
 xfs_btree_read_buf_block(
        struct xfs_btree_cur    *cur,
        union xfs_btree_ptr     *ptr,
-       int                     level,
        int                     flags,
        struct xfs_btree_block  **block,
        struct xfs_buf          **bpp)
@@ -1517,8 +1518,8 @@ xfs_btree_increment(
                union xfs_btree_ptr     *ptrp;
 
                ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block);
-               error = xfs_btree_read_buf_block(cur, ptrp, --lev,
-                                                       0, &block, &bp);
+               --lev;
+               error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp);
                if (error)
                        goto error0;
 
@@ -1616,8 +1617,8 @@ xfs_btree_decrement(
                union xfs_btree_ptr     *ptrp;
 
                ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block);
-               error = xfs_btree_read_buf_block(cur, ptrp, --lev,
-                                                       0, &block, &bp);
+               --lev;
+               error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp);
                if (error)
                        goto error0;
                xfs_btree_setbuf(cur, lev, bp);
@@ -1667,7 +1668,7 @@ xfs_btree_lookup_get_block(
                return 0;
        }
 
-       error = xfs_btree_read_buf_block(cur, pp, level, 0, blkp, &bp);
+       error = xfs_btree_read_buf_block(cur, pp, 0, blkp, &bp);
        if (error)
                return error;
 
@@ -2018,7 +2019,7 @@ xfs_btree_lshift(
                goto out0;
 
        /* Set up the left neighbor as "left". */
-       error = xfs_btree_read_buf_block(cur, &lptr, level, 0, &left, &lbp);
+       error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp);
        if (error)
                goto error0;
 
@@ -2202,7 +2203,7 @@ xfs_btree_rshift(
                goto out0;
 
        /* Set up the right neighbor as "right". */
-       error = xfs_btree_read_buf_block(cur, &rptr, level, 0, &right, &rbp);
+       error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp);
        if (error)
                goto error0;
 
@@ -2372,7 +2373,7 @@ xfs_btree_split(
        xfs_btree_buf_to_ptr(cur, lbp, &lptr);
 
        /* Allocate the new block. If we can't do it, we're toast. Give up. */
-       error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, 1, stat);
+       error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, stat);
        if (error)
                goto error0;
        if (*stat == 0)
@@ -2470,7 +2471,7 @@ xfs_btree_split(
         * point back to right instead of to left.
         */
        if (!xfs_btree_ptr_is_null(cur, &rrptr)) {
-               error = xfs_btree_read_buf_block(cur, &rrptr, level,
+               error = xfs_btree_read_buf_block(cur, &rrptr,
                                                        0, &rrblock, &rrbp);
                if (error)
                        goto error0;
@@ -2545,7 +2546,7 @@ xfs_btree_new_iroot(
        pp = xfs_btree_ptr_addr(cur, 1, block);
 
        /* Allocate the new block. If we can't do it, we're toast. Give up. */
-       error = cur->bc_ops->alloc_block(cur, pp, &nptr, 1, stat);
+       error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat);
        if (error)
                goto error0;
        if (*stat == 0) {
@@ -2649,7 +2650,7 @@ xfs_btree_new_root(
        cur->bc_ops->init_ptr_from_cur(cur, &rptr);
 
        /* Allocate the new block. If we can't do it, we're toast. Give up. */
-       error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, 1, stat);
+       error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, stat);
        if (error)
                goto error0;
        if (*stat == 0)
@@ -2684,8 +2685,7 @@ xfs_btree_new_root(
                lbp = bp;
                xfs_btree_buf_to_ptr(cur, lbp, &lptr);
                left = block;
-               error = xfs_btree_read_buf_block(cur, &rptr,
-                                       cur->bc_nlevels - 1, 0, &right, &rbp);
+               error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp);
                if (error)
                        goto error0;
                bp = rbp;
@@ -2696,8 +2696,7 @@ xfs_btree_new_root(
                xfs_btree_buf_to_ptr(cur, rbp, &rptr);
                right = block;
                xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB);
-               error = xfs_btree_read_buf_block(cur, &lptr,
-                                       cur->bc_nlevels - 1, 0, &left, &lbp);
+               error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp);
                if (error)
                        goto error0;
                bp = lbp;
@@ -3649,8 +3648,7 @@ xfs_btree_delrec(
                rptr = cptr;
                right = block;
                rbp = bp;
-               error = xfs_btree_read_buf_block(cur, &lptr, level,
-                                                       0, &left, &lbp);
+               error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp);
                if (error)
                        goto error0;
 
@@ -3667,8 +3665,7 @@ xfs_btree_delrec(
                lptr = cptr;
                left = block;
                lbp = bp;
-               error = xfs_btree_read_buf_block(cur, &rptr, level,
-                                                       0, &right, &rbp);
+               error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp);
                if (error)
                        goto error0;
 
@@ -3740,8 +3737,7 @@ xfs_btree_delrec(
        /* If there is a right sibling, point it to the remaining block. */
        xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB);
        if (!xfs_btree_ptr_is_null(cur, &cptr)) {
-               error = xfs_btree_read_buf_block(cur, &cptr, level,
-                                                       0, &rrblock, &rrbp);
+               error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp);
                if (error)
                        goto error0;
                xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB);
index 91e34f21bacea773eaadecfc0a3c29595e912601..a04b69422f676c990dafa22da49288b1db279071 100644 (file)
@@ -62,6 +62,7 @@ union xfs_btree_rec {
 #define        XFS_BTNUM_CNT   ((xfs_btnum_t)XFS_BTNUM_CNTi)
 #define        XFS_BTNUM_BMAP  ((xfs_btnum_t)XFS_BTNUM_BMAPi)
 #define        XFS_BTNUM_INO   ((xfs_btnum_t)XFS_BTNUM_INOi)
+#define        XFS_BTNUM_FINO  ((xfs_btnum_t)XFS_BTNUM_FINOi)
 
 /*
  * For logging record fields.
@@ -92,6 +93,7 @@ do {    \
        case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break;   \
        case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break;  \
        case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break;    \
+       case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break;  \
        case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;       \
        }       \
 } while (0)
@@ -105,6 +107,7 @@ do {    \
        case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
        case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
        case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
+       case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \
        case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;       \
        }       \
 } while (0)
@@ -129,7 +132,7 @@ struct xfs_btree_ops {
        int     (*alloc_block)(struct xfs_btree_cur *cur,
                               union xfs_btree_ptr *start_bno,
                               union xfs_btree_ptr *new_bno,
-                              int length, int *stat);
+                              int *stat);
        int     (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp);
 
        /* update last record information */
index cb10a0aaab3aa7b55f9a6735cf70500d509843f3..7a34a1ae655246e6e07fb0b71fabb3bac4c1b6c2 100644 (file)
@@ -216,8 +216,7 @@ _xfs_buf_alloc(
 STATIC int
 _xfs_buf_get_pages(
        xfs_buf_t               *bp,
-       int                     page_count,
-       xfs_buf_flags_t         flags)
+       int                     page_count)
 {
        /* Make sure that we have a page list */
        if (bp->b_pages == NULL) {
@@ -330,7 +329,7 @@ use_alloc_page:
        end = (BBTOB(bp->b_maps[0].bm_bn + bp->b_length) + PAGE_SIZE - 1)
                                                                >> PAGE_SHIFT;
        page_count = end - start;
-       error = _xfs_buf_get_pages(bp, page_count, flags);
+       error = _xfs_buf_get_pages(bp, page_count);
        if (unlikely(error))
                return error;
 
@@ -778,7 +777,7 @@ xfs_buf_associate_memory(
        bp->b_pages = NULL;
        bp->b_addr = mem;
 
-       rval = _xfs_buf_get_pages(bp, page_count, 0);
+       rval = _xfs_buf_get_pages(bp, page_count);
        if (rval)
                return rval;
 
@@ -811,7 +810,7 @@ xfs_buf_get_uncached(
                goto fail;
 
        page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT;
-       error = _xfs_buf_get_pages(bp, page_count, 0);
+       error = _xfs_buf_get_pages(bp, page_count);
        if (error)
                goto fail_free_buf;
 
@@ -1615,7 +1614,6 @@ xfs_free_buftarg(
 int
 xfs_setsize_buftarg(
        xfs_buftarg_t           *btp,
-       unsigned int            blocksize,
        unsigned int            sectorsize)
 {
        /* Set up metadata sector size info */
@@ -1650,16 +1648,13 @@ xfs_setsize_buftarg_early(
        xfs_buftarg_t           *btp,
        struct block_device     *bdev)
 {
-       return xfs_setsize_buftarg(btp, PAGE_SIZE,
-                                  bdev_logical_block_size(bdev));
+       return xfs_setsize_buftarg(btp, bdev_logical_block_size(bdev));
 }
 
 xfs_buftarg_t *
 xfs_alloc_buftarg(
        struct xfs_mount        *mp,
-       struct block_device     *bdev,
-       int                     external,
-       const char              *fsname)
+       struct block_device     *bdev)
 {
        xfs_buftarg_t           *btp;
 
index b8a3abf6cf475ee86a5d45f95d70a19a031d889f..0e47fd1fedbaa17444609c16477067c7d538ab72 100644 (file)
@@ -387,10 +387,10 @@ xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
  *     Handling of buftargs.
  */
 extern xfs_buftarg_t *xfs_alloc_buftarg(struct xfs_mount *,
-                       struct block_device *, int, const char *);
+                       struct block_device *);
 extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *);
 extern void xfs_wait_buftarg(xfs_buftarg_t *);
-extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
+extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int);
 
 #define xfs_getsize_buftarg(buftarg)   block_size((buftarg)->bt_bdev)
 #define xfs_readonly_buftarg(buftarg)  bdev_read_only((buftarg)->bt_bdev)
index 8752821443bee039bd7d1f0691afaa9e4515da84..64b17f5bed9a73d7330313309e9cb162d1998670 100644 (file)
@@ -812,7 +812,6 @@ xfs_buf_item_init(
  */
 static void
 xfs_buf_item_log_segment(
-       struct xfs_buf_log_item *bip,
        uint                    first,
        uint                    last,
        uint                    *map)
@@ -920,7 +919,7 @@ xfs_buf_item_log(
                if (end > last)
                        end = last;
 
-               xfs_buf_item_log_segment(bip, first, end,
+               xfs_buf_item_log_segment(first, end,
                                         &bip->bli_formats[i].blf_data_map[0]);
 
                start += bp->b_maps[i].bm_len;
index 6cc5f6785a774045aa5290a530cba441a71d460f..9eec594cc25a38caa2275b1bcf0cbc4f21742236 100644 (file)
@@ -2462,7 +2462,6 @@ xfs_buf_map_from_irec(
  */
 static int
 xfs_dabuf_map(
-       struct xfs_trans        *trans,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
        xfs_daddr_t             mappedbno,
@@ -2558,7 +2557,7 @@ xfs_da_get_buf(
        *bpp = NULL;
        mapp = &map;
        nmap = 1;
-       error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
+       error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
                                &mapp, &nmap);
        if (error) {
                /* mapping a hole is not an error, but we don't continue */
@@ -2606,7 +2605,7 @@ xfs_da_read_buf(
        *bpp = NULL;
        mapp = &map;
        nmap = 1;
-       error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
+       error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
                                &mapp, &nmap);
        if (error) {
                /* mapping a hole is not an error, but we don't continue */
@@ -2679,7 +2678,6 @@ out_free:
  */
 xfs_daddr_t
 xfs_da_reada_buf(
-       struct xfs_trans        *trans,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
        xfs_daddr_t             mappedbno,
@@ -2693,7 +2691,7 @@ xfs_da_reada_buf(
 
        mapp = &map;
        nmap = 1;
-       error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
+       error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
                                &mapp, &nmap);
        if (error) {
                /* mapping a hole is not an error, but we don't continue */
index 6e95ea79f5d73aa2447fc49eb0e4c7e9bb73a25d..4cc6a462252e0b4b75943f4684fd82a2e74002de 100644 (file)
@@ -183,9 +183,9 @@ int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp,
                               xfs_dablk_t bno, xfs_daddr_t mappedbno,
                               struct xfs_buf **bpp, int whichfork,
                               const struct xfs_buf_ops *ops);
-xfs_daddr_t    xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp,
-                               xfs_dablk_t bno, xfs_daddr_t mapped_bno,
-                               int whichfork, const struct xfs_buf_ops *ops);
+xfs_daddr_t    xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno,
+                               xfs_daddr_t mapped_bno, int whichfork,
+                               const struct xfs_buf_ops *ops);
 int    xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
                                          struct xfs_buf *dead_buf);
 
index a19d3f8f639cf3eb3e95d23bc52b58d5eb9b6591..1432b576b4a7794dd46848a4e5751587166ea310 100644 (file)
@@ -541,7 +541,7 @@ xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp)
  * Convert dataptr to byte in file space
  */
 static inline xfs_dir2_off_t
-xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
+xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp)
 {
        return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
 }
@@ -550,7 +550,7 @@ xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
  * Convert byte in file space to dataptr.  It had better be aligned.
  */
 static inline xfs_dir2_dataptr_t
-xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by)
+xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by)
 {
        return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG);
 }
@@ -571,7 +571,7 @@ xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by)
 static inline xfs_dir2_db_t
 xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
 {
-       return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(mp, dp));
+       return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(dp));
 }
 
 /*
@@ -590,7 +590,7 @@ xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by)
 static inline xfs_dir2_data_aoff_t
 xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
 {
-       return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(mp, dp));
+       return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(dp));
 }
 
 /*
@@ -629,7 +629,7 @@ static inline xfs_dir2_dataptr_t
 xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db,
                           xfs_dir2_data_aoff_t o)
 {
-       return xfs_dir2_byte_to_dataptr(mp, xfs_dir2_db_off_to_byte(mp, db, o));
+       return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(mp, db, o));
 }
 
 /*
index fda46253966a5cac252e593e14181da56f252700..e365c98c0f1ea93c6bcdbd38d916234088cb9743 100644 (file)
@@ -244,7 +244,7 @@ xfs_dir_createname(
                goto out_free;
        }
 
-       rval = xfs_dir2_isblock(tp, dp, &v);
+       rval = xfs_dir2_isblock(dp, &v);
        if (rval)
                goto out_free;
        if (v) {
@@ -252,7 +252,7 @@ xfs_dir_createname(
                goto out_free;
        }
 
-       rval = xfs_dir2_isleaf(tp, dp, &v);
+       rval = xfs_dir2_isleaf(dp, &v);
        if (rval)
                goto out_free;
        if (v)
@@ -336,7 +336,7 @@ xfs_dir_lookup(
                goto out_check_rval;
        }
 
-       rval = xfs_dir2_isblock(tp, dp, &v);
+       rval = xfs_dir2_isblock(dp, &v);
        if (rval)
                goto out_free;
        if (v) {
@@ -344,7 +344,7 @@ xfs_dir_lookup(
                goto out_check_rval;
        }
 
-       rval = xfs_dir2_isleaf(tp, dp, &v);
+       rval = xfs_dir2_isleaf(dp, &v);
        if (rval)
                goto out_free;
        if (v)
@@ -408,7 +408,7 @@ xfs_dir_removename(
                goto out_free;
        }
 
-       rval = xfs_dir2_isblock(tp, dp, &v);
+       rval = xfs_dir2_isblock(dp, &v);
        if (rval)
                goto out_free;
        if (v) {
@@ -416,7 +416,7 @@ xfs_dir_removename(
                goto out_free;
        }
 
-       rval = xfs_dir2_isleaf(tp, dp, &v);
+       rval = xfs_dir2_isleaf(dp, &v);
        if (rval)
                goto out_free;
        if (v)
@@ -472,7 +472,7 @@ xfs_dir_replace(
                goto out_free;
        }
 
-       rval = xfs_dir2_isblock(tp, dp, &v);
+       rval = xfs_dir2_isblock(dp, &v);
        if (rval)
                goto out_free;
        if (v) {
@@ -480,7 +480,7 @@ xfs_dir_replace(
                goto out_free;
        }
 
-       rval = xfs_dir2_isleaf(tp, dp, &v);
+       rval = xfs_dir2_isleaf(dp, &v);
        if (rval)
                goto out_free;
        if (v)
@@ -531,7 +531,7 @@ xfs_dir_canenter(
                goto out_free;
        }
 
-       rval = xfs_dir2_isblock(tp, dp, &v);
+       rval = xfs_dir2_isblock(dp, &v);
        if (rval)
                goto out_free;
        if (v) {
@@ -539,7 +539,7 @@ xfs_dir_canenter(
                goto out_free;
        }
 
-       rval = xfs_dir2_isleaf(tp, dp, &v);
+       rval = xfs_dir2_isleaf(dp, &v);
        if (rval)
                goto out_free;
        if (v)
@@ -607,7 +607,6 @@ xfs_dir2_grow_inode(
  */
 int
 xfs_dir2_isblock(
-       xfs_trans_t     *tp,
        xfs_inode_t     *dp,
        int             *vp)            /* out: 1 is block, 0 is not block */
 {
@@ -616,7 +615,7 @@ xfs_dir2_isblock(
        int             rval;
 
        mp = dp->i_mount;
-       if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
+       if ((rval = xfs_bmap_last_offset(dp, &last, XFS_DATA_FORK)))
                return rval;
        rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
        ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
@@ -629,7 +628,6 @@ xfs_dir2_isblock(
  */
 int
 xfs_dir2_isleaf(
-       xfs_trans_t     *tp,
        xfs_inode_t     *dp,
        int             *vp)            /* out: 1 is leaf, 0 is not leaf */
 {
@@ -638,7 +636,7 @@ xfs_dir2_isleaf(
        int             rval;
 
        mp = dp->i_mount;
-       if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
+       if ((rval = xfs_bmap_last_offset(dp, &last, XFS_DATA_FORK)))
                return rval;
        *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
        return 0;
index cec70e0781ab664f9238c7601d252f9fc339fa37..64a6b19c2fd0b08a486a6186d9ca08bafe994c38 100644 (file)
@@ -142,8 +142,8 @@ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
 /*
  * Interface routines used by userspace utilities
  */
-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_isblock(struct xfs_inode *dp, int *r);
+extern int xfs_dir2_isleaf(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);
 
index 4f6a38cb83a4ee9f467896deabeefb059cbe8d10..dd9d00515582e3b69beff1240db66e36514e0a29 100644 (file)
@@ -319,7 +319,6 @@ xfs_dir2_block_compact(
                (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr),
                (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)),
                needlog, &needscan);
-       blp += be32_to_cpu(btp->stale) - 1;
        btp->stale = cpu_to_be32(1);
        /*
         * If we now need to rebuild the bestfree map, do so.
@@ -537,7 +536,7 @@ xfs_dir2_block_addname(
         * Fill in the leaf entry.
         */
        blp[mid].hashval = cpu_to_be32(args->hashval);
-       blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
+       blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
                                (char *)dep - (char *)hdr));
        xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
        /*
@@ -1170,7 +1169,7 @@ xfs_dir2_sf_to_block(
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        xfs_dir2_data_log_entry(tp, dp, bp, dep);
        blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
-       blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
+       blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
                                (char *)dep - (char *)hdr));
        /*
         * Create entry for ..
@@ -1184,7 +1183,7 @@ xfs_dir2_sf_to_block(
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        xfs_dir2_data_log_entry(tp, dp, bp, dep);
        blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
-       blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
+       blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
                                (char *)dep - (char *)hdr));
        offset = dp->d_ops->data_first_offset;
        /*
@@ -1238,7 +1237,7 @@ xfs_dir2_sf_to_block(
                name.len = sfep->namelen;
                blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->
                                                        hashname(&name));
-               blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
+               blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
                                                 (char *)dep - (char *)hdr));
                offset = (int)((char *)(tagp + 1) - (char *)hdr);
                if (++i == sfp->count)
index afa4ad523f3f0278cf7de73a93a25c3b8b191e1d..bae8b5b8d1c2c7b2be62e4527b203644c018613b 100644 (file)
@@ -329,12 +329,11 @@ xfs_dir3_data_read(
 
 int
 xfs_dir3_data_readahead(
-       struct xfs_trans        *tp,
        struct xfs_inode        *dp,
        xfs_dablk_t             bno,
        xfs_daddr_t             mapped_bno)
 {
-       return xfs_da_reada_buf(tp, dp, bno, mapped_bno,
+       return xfs_da_reada_buf(dp, bno, mapped_bno,
                                XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops);
 }
 
index d36e97df1187ebc866e9c3885d6f848ca3373c5a..f571723e2378554e3a7ed532cbfa7b457d458b9e 100644 (file)
@@ -1708,7 +1708,7 @@ xfs_dir2_node_to_leaf(
        /*
         * Get the last offset in the file.
         */
-       if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) {
+       if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) {
                return error;
        }
        fo -= mp->m_dirblkfsbs;
index cb434d732681a33e9e798278670b0b2ba99bdfbc..9cb91ee0914b8c7a7420965440eb4fcf17b42f89 100644 (file)
@@ -1727,7 +1727,7 @@ xfs_dir2_node_addname_int(
        if (dbno == -1) {
                xfs_fileoff_t   fo;             /* freespace block number */
 
-               if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK)))
+               if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK)))
                        return error;
                lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo);
                fbno = ifbno;
index 8b9d2281f85b3c6efdec0a6906a1506074871320..2429960739e9843aae46dbf28dd96ccdc0b50458 100644 (file)
@@ -54,8 +54,8 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
 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);
-extern int xfs_dir3_data_readahead(struct xfs_trans *tp, struct xfs_inode *dp,
-               xfs_dablk_t bno, xfs_daddr_t mapped_bno);
+extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno,
+               xfs_daddr_t mapped_bno);
 
 extern struct xfs_dir2_data_free *
 xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr,
index aead369e1c30471f5b176661afc4e2ee7beb5afa..50b72f7b8787fcb5058b4378df3ca6600436d0bc 100644 (file)
@@ -434,7 +434,7 @@ xfs_dir2_leaf_readbuf(
                 */
                if (i > mip->ra_current &&
                    map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
-                       xfs_dir3_data_readahead(NULL, dp,
+                       xfs_dir3_data_readahead(dp,
                                map[mip->ra_index].br_startoff + mip->ra_offset,
                                XFS_FSB_TO_DADDR(mp,
                                        map[mip->ra_index].br_startblock +
@@ -447,7 +447,7 @@ xfs_dir2_leaf_readbuf(
                 * use our mapping, but this is a very rare case.
                 */
                else if (i > mip->ra_current) {
-                       xfs_dir3_data_readahead(NULL, dp,
+                       xfs_dir3_data_readahead(dp,
                                        map[mip->ra_index].br_startoff +
                                                        mip->ra_offset, -1);
                        mip->ra_current = i;
@@ -531,7 +531,7 @@ xfs_dir2_leaf_getdents(
         * 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);
+       curoff = xfs_dir2_dataptr_to_byte(ctx->pos);
 
        /*
         * Force this conversion through db so we truncate the offset
@@ -635,7 +635,7 @@ xfs_dir2_leaf_getdents(
                length = dp->d_ops->data_entsize(dep->namelen);
                filetype = dp->d_ops->data_get_ftype(dep);
 
-               ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
+               ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
                            be64_to_cpu(dep->inumber),
                            xfs_dir3_get_dtype(mp, filetype)))
@@ -653,10 +653,10 @@ xfs_dir2_leaf_getdents(
        /*
         * All done.  Set output offset value to current offset.
         */
-       if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
+       if (curoff > xfs_dir2_dataptr_to_byte(XFS_DIR2_MAX_DATAPTR))
                ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
        else
-               ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
+               ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
        kmem_free(map_info);
        if (bp)
                xfs_trans_brelse(NULL, bp);
@@ -687,7 +687,7 @@ xfs_readdir(
        lock_mode = xfs_ilock_data_map_shared(dp);
        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 ((rval = xfs_dir2_isblock(dp, &v)))
                ;
        else if (v)
                rval = xfs_dir2_block_getdents(dp, ctx);
index 3725fb1b902b8becf5f594524fd8143026aee03e..7aab8ec117ad65f9b558889e5434f929cb6dad63 100644 (file)
@@ -285,14 +285,12 @@ int                                               /* error */
 xfs_dir2_sf_addname(
        xfs_da_args_t           *args)          /* operation arguments */
 {
-       int                     add_entsize;    /* size of the new entry */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return value */
        int                     incr_isize;     /* total change in size */
        int                     new_isize;      /* di_size after adding name */
        int                     objchange;      /* changing to 8-byte inodes */
        xfs_dir2_data_aoff_t    offset = 0;     /* offset for new entry */
-       int                     old_isize;      /* di_size before adding name */
        int                     pick;           /* which algorithm to use */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
        xfs_dir2_sf_entry_t     *sfep = NULL;   /* shortform entry */
@@ -316,8 +314,7 @@ xfs_dir2_sf_addname(
        /*
         * Compute entry (and change in) size.
         */
-       add_entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
-       incr_isize = add_entsize;
+       incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen);
        objchange = 0;
 #if XFS_BIG_INUMS
        /*
@@ -325,11 +322,8 @@ xfs_dir2_sf_addname(
         */
        if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
                /*
-                * Yes, adjust the entry size and the total size.
+                * Yes, adjust the inode size.  old count + (parent + new)
                 */
-               add_entsize +=
-                       (uint)sizeof(xfs_dir2_ino8_t) -
-                       (uint)sizeof(xfs_dir2_ino4_t);
                incr_isize +=
                        (sfp->count + 2) *
                        ((uint)sizeof(xfs_dir2_ino8_t) -
@@ -337,8 +331,7 @@ xfs_dir2_sf_addname(
                objchange = 1;
        }
 #endif
-       old_isize = (int)dp->i_d.di_size;
-       new_isize = old_isize + incr_isize;
+       new_isize = (int)dp->i_d.di_size + incr_isize;
        /*
         * Won't fit as shortform any more (due to size),
         * or the pick routine says it won't (due to offset values).
@@ -1110,9 +1103,9 @@ xfs_dir2_sf_toino4(
 }
 
 /*
- * Convert from 4-byte inode numbers to 8-byte inode numbers.
- * The new 8-byte inode number is not there yet, we leave with the
- * count 1 but no corresponding entry.
+ * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers.
+ * The new entry w/ an 8-byte inode number is not there yet; we leave with
+ * i8count set to 1, but no corresponding 8-byte entry.
  */
 static void
 xfs_dir2_sf_toino8(
@@ -1145,7 +1138,7 @@ xfs_dir2_sf_toino8(
        ASSERT(oldsfp->i8count == 0);
        memcpy(buf, oldsfp, oldsize);
        /*
-        * Compute the new inode size.
+        * Compute the new inode size (nb: entry count + 1 for parent)
         */
        newsize =
                oldsize +
index 610da81777374587e75c1333435590fe3651c92f..c2ac0c611ad877f3a6321e15bf899c1bf520386a 100644 (file)
@@ -35,7 +35,6 @@
 
 int
 xfs_calc_dquots_per_chunk(
-       struct xfs_mount        *mp,
        unsigned int            nbblks) /* basic block units */
 {
        unsigned int    ndquots;
@@ -194,7 +193,7 @@ xfs_dquot_buf_verify_crc(
        if (mp->m_quotainfo)
                ndquots = mp->m_quotainfo->qi_dqperchunk;
        else
-               ndquots = xfs_calc_dquots_per_chunk(mp,
+               ndquots = xfs_calc_dquots_per_chunk(
                                        XFS_BB_TO_FSB(mp, bp->b_length));
 
        for (i = 0; i < ndquots; i++, d++) {
@@ -225,7 +224,7 @@ xfs_dquot_buf_verify(
        if (mp->m_quotainfo)
                ndquots = mp->m_quotainfo->qi_dqperchunk;
        else
-               ndquots = xfs_calc_dquots_per_chunk(mp, bp->b_length);
+               ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
 
        /*
         * On the first read of the buffer, verify that each dquot is valid.
index 951a2321ee010f35c1d3395c09d0830d74197cfd..97855c559bcbae86a78385dd1074cb21e4d93021 100644 (file)
@@ -229,34 +229,27 @@ xfs_file_fsync(
 }
 
 STATIC ssize_t
-xfs_file_aio_read(
+xfs_file_read_iter(
        struct kiocb            *iocb,
-       const struct iovec      *iovp,
-       unsigned long           nr_segs,
-       loff_t                  pos)
+       struct iov_iter         *to)
 {
        struct file             *file = iocb->ki_filp;
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       size_t                  size = 0;
+       size_t                  size = iov_iter_count(to);
        ssize_t                 ret = 0;
        int                     ioflags = 0;
        xfs_fsize_t             n;
+       loff_t                  pos = iocb->ki_pos;
 
        XFS_STATS_INC(xs_read_calls);
 
-       BUG_ON(iocb->ki_pos != pos);
-
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
        if (file->f_mode & FMODE_NOCMTIME)
                ioflags |= IO_INVIS;
 
-       ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
-       if (ret < 0)
-               return ret;
-
        if (unlikely(ioflags & IO_ISDIRECT)) {
                xfs_buftarg_t   *target =
                        XFS_IS_REALTIME_INODE(ip) ?
@@ -309,7 +302,7 @@ xfs_file_aio_read(
 
        trace_xfs_file_read(ip, size, pos, ioflags);
 
-       ret = generic_file_aio_read(iocb, iovp, nr_segs, pos);
+       ret = generic_file_read_iter(iocb, to);
        if (ret > 0)
                XFS_STATS_ADD(xs_read_bytes, ret);
 
@@ -349,47 +342,6 @@ xfs_file_splice_read(
        return ret;
 }
 
-/*
- * xfs_file_splice_write() does not use xfs_rw_ilock() because
- * generic_file_splice_write() takes the i_mutex itself. This, in theory,
- * couuld cause lock inversions between the aio_write path and the splice path
- * if someone is doing concurrent splice(2) based writes and write(2) based
- * writes to the same inode. The only real way to fix this is to re-implement
- * the generic code here with correct locking orders.
- */
-STATIC ssize_t
-xfs_file_splice_write(
-       struct pipe_inode_info  *pipe,
-       struct file             *outfilp,
-       loff_t                  *ppos,
-       size_t                  count,
-       unsigned int            flags)
-{
-       struct inode            *inode = outfilp->f_mapping->host;
-       struct xfs_inode        *ip = XFS_I(inode);
-       int                     ioflags = 0;
-       ssize_t                 ret;
-
-       XFS_STATS_INC(xs_write_calls);
-
-       if (outfilp->f_mode & FMODE_NOCMTIME)
-               ioflags |= IO_INVIS;
-
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return -EIO;
-
-       xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
-       trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
-
-       ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
-       if (ret > 0)
-               XFS_STATS_ADD(xs_write_bytes, ret);
-
-       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-       return ret;
-}
-
 /*
  * This routine is called to handle zeroing any space in the last block of the
  * file that is beyond the EOF.  We do this since the size is being increased
@@ -625,10 +577,7 @@ restart:
 STATIC ssize_t
 xfs_file_dio_aio_write(
        struct kiocb            *iocb,
-       const struct iovec      *iovp,
-       unsigned long           nr_segs,
-       loff_t                  pos,
-       size_t                  ocount)
+       struct iov_iter         *from)
 {
        struct file             *file = iocb->ki_filp;
        struct address_space    *mapping = file->f_mapping;
@@ -636,9 +585,10 @@ xfs_file_dio_aio_write(
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
        ssize_t                 ret = 0;
-       size_t                  count = ocount;
        int                     unaligned_io = 0;
        int                     iolock;
+       size_t                  count = iov_iter_count(from);
+       loff_t                  pos = iocb->ki_pos;
        struct xfs_buftarg      *target = XFS_IS_REALTIME_INODE(ip) ?
                                        mp->m_rtdev_targp : mp->m_ddev_targp;
 
@@ -677,6 +627,7 @@ xfs_file_dio_aio_write(
        ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock);
        if (ret)
                goto out;
+       iov_iter_truncate(from, count);
 
        if (mapping->nrpages) {
                ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
@@ -698,8 +649,7 @@ xfs_file_dio_aio_write(
        }
 
        trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0);
-       ret = generic_file_direct_write(iocb, iovp,
-                       &nr_segs, pos, count, ocount);
+       ret = generic_file_direct_write(iocb, from, pos);
 
 out:
        xfs_rw_iunlock(ip, iolock);
@@ -712,10 +662,7 @@ out:
 STATIC ssize_t
 xfs_file_buffered_aio_write(
        struct kiocb            *iocb,
-       const struct iovec      *iovp,
-       unsigned long           nr_segs,
-       loff_t                  pos,
-       size_t                  count)
+       struct iov_iter         *from)
 {
        struct file             *file = iocb->ki_filp;
        struct address_space    *mapping = file->f_mapping;
@@ -724,7 +671,8 @@ xfs_file_buffered_aio_write(
        ssize_t                 ret;
        int                     enospc = 0;
        int                     iolock = XFS_IOLOCK_EXCL;
-       struct iov_iter         from;
+       loff_t                  pos = iocb->ki_pos;
+       size_t                  count = iov_iter_count(from);
 
        xfs_rw_ilock(ip, iolock);
 
@@ -732,13 +680,13 @@ xfs_file_buffered_aio_write(
        if (ret)
                goto out;
 
-       iov_iter_init(&from, iovp, nr_segs, count, 0);
+       iov_iter_truncate(from, count);
        /* We can write back this queue in page reclaim */
        current->backing_dev_info = mapping->backing_dev_info;
 
 write_retry:
        trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, 0);
-       ret = generic_perform_write(file, &from, pos);
+       ret = generic_perform_write(file, from, pos);
        if (likely(ret >= 0))
                iocb->ki_pos = pos + ret;
        /*
@@ -759,40 +707,29 @@ out:
 }
 
 STATIC ssize_t
-xfs_file_aio_write(
+xfs_file_write_iter(
        struct kiocb            *iocb,
-       const struct iovec      *iovp,
-       unsigned long           nr_segs,
-       loff_t                  pos)
+       struct iov_iter         *from)
 {
        struct file             *file = iocb->ki_filp;
        struct address_space    *mapping = file->f_mapping;
        struct inode            *inode = mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
        ssize_t                 ret;
-       size_t                  ocount = 0;
+       size_t                  ocount = iov_iter_count(from);
 
        XFS_STATS_INC(xs_write_calls);
 
-       BUG_ON(iocb->ki_pos != pos);
-
-       ret = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ);
-       if (ret)
-               return ret;
-
        if (ocount == 0)
                return 0;
 
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-               ret = -EIO;
-               goto out;
-       }
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+               return -EIO;
 
        if (unlikely(file->f_flags & O_DIRECT))
-               ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount);
+               ret = xfs_file_dio_aio_write(iocb, from);
        else
-               ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
-                                                 ocount);
+               ret = xfs_file_buffered_aio_write(iocb, from);
 
        if (ret > 0) {
                ssize_t err;
@@ -804,8 +741,6 @@ xfs_file_aio_write(
                if (err < 0)
                        ret = err;
        }
-
-out:
        return ret;
 }
 
@@ -944,7 +879,7 @@ xfs_dir_open(
         */
        mode = xfs_ilock_data_map_shared(ip);
        if (ip->i_d.di_nextents > 0)
-               xfs_dir3_data_readahead(NULL, ip, 0, -1);
+               xfs_dir3_data_readahead(ip, 0, -1);
        xfs_iunlock(ip, mode);
        return 0;
 }
@@ -1461,12 +1396,12 @@ xfs_file_llseek(
 
 const struct file_operations xfs_file_operations = {
        .llseek         = xfs_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = xfs_file_aio_read,
-       .aio_write      = xfs_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = xfs_file_read_iter,
+       .write_iter     = xfs_file_write_iter,
        .splice_read    = xfs_file_splice_read,
-       .splice_write   = xfs_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .unlocked_ioctl = xfs_file_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = xfs_file_compat_ioctl,
index 12b6e7701985378e56f619dfd58f79be0d45c94c..8ec81bed7992149420efd5781cfb12c9596633f5 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * Copyright (c) 2014 Christoph Hellwig.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include "xfs_filestream.h"
 #include "xfs_trace.h"
 
-#ifdef XFS_FILESTREAMS_TRACE
-
-ktrace_t *xfs_filestreams_trace_buf;
-
-STATIC void
-xfs_filestreams_trace(
-       xfs_mount_t     *mp,    /* mount point */
-       int             type,   /* type of trace */
-       const char      *func,  /* source function */
-       int             line,   /* source line number */
-       __psunsigned_t  arg0,
-       __psunsigned_t  arg1,
-       __psunsigned_t  arg2,
-       __psunsigned_t  arg3,
-       __psunsigned_t  arg4,
-       __psunsigned_t  arg5)
-{
-       ktrace_enter(xfs_filestreams_trace_buf,
-               (void *)(__psint_t)(type | (line << 16)),
-               (void *)func,
-               (void *)(__psunsigned_t)current_pid(),
-               (void *)mp,
-               (void *)(__psunsigned_t)arg0,
-               (void *)(__psunsigned_t)arg1,
-               (void *)(__psunsigned_t)arg2,
-               (void *)(__psunsigned_t)arg3,
-               (void *)(__psunsigned_t)arg4,
-               (void *)(__psunsigned_t)arg5,
-               NULL, NULL, NULL, NULL, NULL, NULL);
-}
-
-#define TRACE0(mp,t)                   TRACE6(mp,t,0,0,0,0,0,0)
-#define TRACE1(mp,t,a0)                        TRACE6(mp,t,a0,0,0,0,0,0)
-#define TRACE2(mp,t,a0,a1)             TRACE6(mp,t,a0,a1,0,0,0,0)
-#define TRACE3(mp,t,a0,a1,a2)          TRACE6(mp,t,a0,a1,a2,0,0,0)
-#define TRACE4(mp,t,a0,a1,a2,a3)       TRACE6(mp,t,a0,a1,a2,a3,0,0)
-#define TRACE5(mp,t,a0,a1,a2,a3,a4)    TRACE6(mp,t,a0,a1,a2,a3,a4,0)
-#define TRACE6(mp,t,a0,a1,a2,a3,a4,a5) \
-       xfs_filestreams_trace(mp, t, __func__, __LINE__, \
-                               (__psunsigned_t)a0, (__psunsigned_t)a1, \
-                               (__psunsigned_t)a2, (__psunsigned_t)a3, \
-                               (__psunsigned_t)a4, (__psunsigned_t)a5)
-
-#define TRACE_AG_SCAN(mp, ag, ag2) \
-               TRACE2(mp, XFS_FSTRM_KTRACE_AGSCAN, ag, ag2);
-#define TRACE_AG_PICK1(mp, max_ag, maxfree) \
-               TRACE2(mp, XFS_FSTRM_KTRACE_AGPICK1, max_ag, maxfree);
-#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) \
-               TRACE6(mp, XFS_FSTRM_KTRACE_AGPICK2, ag, ag2, \
-                        cnt, free, scan, flag)
-#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) \
-               TRACE5(mp, XFS_FSTRM_KTRACE_UPDATE, ip, ag, cnt, ag2, cnt2)
-#define TRACE_FREE(mp, ip, pip, ag, cnt) \
-               TRACE4(mp, XFS_FSTRM_KTRACE_FREE, ip, pip, ag, cnt)
-#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) \
-               TRACE4(mp, XFS_FSTRM_KTRACE_ITEM_LOOKUP, ip, pip, ag, cnt)
-#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) \
-               TRACE4(mp, XFS_FSTRM_KTRACE_ASSOCIATE, ip, pip, ag, cnt)
-#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) \
-               TRACE6(mp, XFS_FSTRM_KTRACE_MOVEAG, ip, pip, oag, ocnt, nag, ncnt)
-#define TRACE_ORPHAN(mp, ip, ag) \
-               TRACE2(mp, XFS_FSTRM_KTRACE_ORPHAN, ip, ag);
-
-
-#else
-#define TRACE_AG_SCAN(mp, ag, ag2)
-#define TRACE_AG_PICK1(mp, max_ag, maxfree)
-#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag)
-#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2)
-#define TRACE_FREE(mp, ip, pip, ag, cnt)
-#define TRACE_LOOKUP(mp, ip, pip, ag, cnt)
-#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt)
-#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt)
-#define TRACE_ORPHAN(mp, ip, ag)
-#endif
-
-static kmem_zone_t *item_zone;
+struct xfs_fstrm_item {
+       struct xfs_mru_cache_elem       mru;
+       struct xfs_inode                *ip;
+       xfs_agnumber_t                  ag; /* AG in use for this directory */
+};
 
-/*
- * Structure for associating a file or a directory with an allocation group.
- * The parent directory pointer is only needed for files, but since there will
- * generally be vastly more files than directories in the cache, using the same
- * data structure simplifies the code with very little memory overhead.
- */
-typedef struct fstrm_item
-{
-       xfs_agnumber_t  ag;     /* AG currently in use for the file/directory. */
-       xfs_inode_t     *ip;    /* inode self-pointer. */
-       xfs_inode_t     *pip;   /* Parent directory inode pointer. */
-} fstrm_item_t;
+enum xfs_fstrm_alloc {
+       XFS_PICK_USERDATA = 1,
+       XFS_PICK_LOWSPACE = 2,
+};
 
 /*
  * Allocation group filestream associations are tracked with per-ag atomic
- * counters.  These counters allow _xfs_filestream_pick_ag() to tell whether a
+ * counters.  These counters allow xfs_filestream_pick_ag() to tell whether a
  * particular AG already has active filestreams associated with it. The mount
  * point's m_peraglock is used to protect these counters from per-ag array
  * re-allocation during a growfs operation.  When xfs_growfs_data_private() is
@@ -160,7 +81,7 @@ typedef struct fstrm_item
  * the cache that reference per-ag array elements that have since been
  * reallocated.
  */
-static int
+int
 xfs_filestream_peek_ag(
        xfs_mount_t     *mp,
        xfs_agnumber_t  agno)
@@ -200,23 +121,40 @@ xfs_filestream_put_ag(
        xfs_perag_put(pag);
 }
 
+static void
+xfs_fstrm_free_func(
+       struct xfs_mru_cache_elem *mru)
+{
+       struct xfs_fstrm_item   *item =
+               container_of(mru, struct xfs_fstrm_item, mru);
+
+       xfs_filestream_put_ag(item->ip->i_mount, item->ag);
+
+       trace_xfs_filestream_free(item->ip, item->ag);
+
+       kmem_free(item);
+}
+
 /*
  * Scan the AGs starting at startag looking for an AG that isn't in use and has
  * at least minlen blocks free.
  */
 static int
-_xfs_filestream_pick_ag(
-       xfs_mount_t     *mp,
-       xfs_agnumber_t  startag,
-       xfs_agnumber_t  *agp,
-       int             flags,
-       xfs_extlen_t    minlen)
+xfs_filestream_pick_ag(
+       struct xfs_inode        *ip,
+       xfs_agnumber_t          startag,
+       xfs_agnumber_t          *agp,
+       int                     flags,
+       xfs_extlen_t            minlen)
 {
-       int             streams, max_streams;
-       int             err, trylock, nscan;
-       xfs_extlen_t    longest, free, minfree, maxfree = 0;
-       xfs_agnumber_t  ag, max_ag = NULLAGNUMBER;
-       struct xfs_perag *pag;
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_fstrm_item   *item;
+       struct xfs_perag        *pag;
+       xfs_extlen_t            longest, free = 0, minfree, maxfree = 0;
+       xfs_agnumber_t          ag, max_ag = NULLAGNUMBER;
+       int                     err, trylock, nscan;
+
+       ASSERT(S_ISDIR(ip->i_d.di_mode));
 
        /* 2% of an AG's blocks must be free for it to be chosen. */
        minfree = mp->m_sb.sb_agblocks / 50;
@@ -228,8 +166,9 @@ _xfs_filestream_pick_ag(
        trylock = XFS_ALLOC_FLAG_TRYLOCK;
 
        for (nscan = 0; 1; nscan++) {
+               trace_xfs_filestream_scan(ip, ag);
+
                pag = xfs_perag_get(mp, ag);
-               TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms));
 
                if (!pag->pagf_init) {
                        err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
@@ -246,7 +185,6 @@ _xfs_filestream_pick_ag(
                /* Keep track of the AG with the most free blocks. */
                if (pag->pagf_freeblks > maxfree) {
                        maxfree = pag->pagf_freeblks;
-                       max_streams = atomic_read(&pag->pagf_fstrms);
                        max_ag = ag;
                }
 
@@ -269,7 +207,6 @@ _xfs_filestream_pick_ag(
 
                        /* Break out, retaining the reference on the AG. */
                        free = pag->pagf_freeblks;
-                       streams = atomic_read(&pag->pagf_fstrms);
                        xfs_perag_put(pag);
                        *agp = ag;
                        break;
@@ -305,317 +242,98 @@ next_ag:
                 */
                if (max_ag != NULLAGNUMBER) {
                        xfs_filestream_get_ag(mp, max_ag);
-                       TRACE_AG_PICK1(mp, max_ag, maxfree);
-                       streams = max_streams;
                        free = maxfree;
                        *agp = max_ag;
                        break;
                }
 
                /* take AG 0 if none matched */
-               TRACE_AG_PICK1(mp, max_ag, maxfree);
+               trace_xfs_filestream_pick(ip, *agp, free, nscan);
                *agp = 0;
                return 0;
        }
 
-       TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags);
-
-       return 0;
-}
+       trace_xfs_filestream_pick(ip, *agp, free, nscan);
 
-/*
- * Set the allocation group number for a file or a directory, updating inode
- * references and per-AG references as appropriate.
- */
-static int
-_xfs_filestream_update_ag(
-       xfs_inode_t     *ip,
-       xfs_inode_t     *pip,
-       xfs_agnumber_t  ag)
-{
-       int             err = 0;
-       xfs_mount_t     *mp;
-       xfs_mru_cache_t *cache;
-       fstrm_item_t    *item;
-       xfs_agnumber_t  old_ag;
-       xfs_inode_t     *old_pip;
-
-       /*
-        * Either ip is a regular file and pip is a directory, or ip is a
-        * directory and pip is NULL.
-        */
-       ASSERT(ip && ((S_ISREG(ip->i_d.di_mode) && pip &&
-                      S_ISDIR(pip->i_d.di_mode)) ||
-                     (S_ISDIR(ip->i_d.di_mode) && !pip)));
-
-       mp = ip->i_mount;
-       cache = mp->m_filestream;
-
-       item = xfs_mru_cache_lookup(cache, ip->i_ino);
-       if (item) {
-               ASSERT(item->ip == ip);
-               old_ag = item->ag;
-               item->ag = ag;
-               old_pip = item->pip;
-               item->pip = pip;
-               xfs_mru_cache_done(cache);
-
-               /*
-                * If the AG has changed, drop the old ref and take a new one,
-                * effectively transferring the reference from old to new AG.
-                */
-               if (ag != old_ag) {
-                       xfs_filestream_put_ag(mp, old_ag);
-                       xfs_filestream_get_ag(mp, ag);
-               }
-
-               /*
-                * If ip is a file and its pip has changed, drop the old ref and
-                * take a new one.
-                */
-               if (pip && pip != old_pip) {
-                       IRELE(old_pip);
-                       IHOLD(pip);
-               }
-
-               TRACE_UPDATE(mp, ip, old_ag, xfs_filestream_peek_ag(mp, old_ag),
-                               ag, xfs_filestream_peek_ag(mp, ag));
+       if (*agp == NULLAGNUMBER)
                return 0;
-       }
 
-       item = kmem_zone_zalloc(item_zone, KM_MAYFAIL);
+       err = ENOMEM;
+       item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
        if (!item)
-               return ENOMEM;
+               goto out_put_ag;
 
-       item->ag = ag;
+       item->ag = *agp;
        item->ip = ip;
-       item->pip = pip;
 
-       err = xfs_mru_cache_insert(cache, ip->i_ino, item);
+       err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
        if (err) {
-               kmem_zone_free(item_zone, item);
-               return err;
+               if (err == EEXIST)
+                       err = 0;
+               goto out_free_item;
        }
 
-       /* Take a reference on the AG. */
-       xfs_filestream_get_ag(mp, ag);
-
-       /*
-        * Take a reference on the inode itself regardless of whether it's a
-        * regular file or a directory.
-        */
-       IHOLD(ip);
-
-       /*
-        * In the case of a regular file, take a reference on the parent inode
-        * as well to ensure it remains in-core.
-        */
-       if (pip)
-               IHOLD(pip);
-
-       TRACE_UPDATE(mp, ip, ag, xfs_filestream_peek_ag(mp, ag),
-                       ag, xfs_filestream_peek_ag(mp, ag));
-
        return 0;
-}
-
-/* xfs_fstrm_free_func(): callback for freeing cached stream items. */
-STATIC void
-xfs_fstrm_free_func(
-       unsigned long   ino,
-       void            *data)
-{
-       fstrm_item_t    *item  = (fstrm_item_t *)data;
-       xfs_inode_t     *ip = item->ip;
-
-       ASSERT(ip->i_ino == ino);
-
-       xfs_iflags_clear(ip, XFS_IFILESTREAM);
-
-       /* Drop the reference taken on the AG when the item was added. */
-       xfs_filestream_put_ag(ip->i_mount, item->ag);
-
-       TRACE_FREE(ip->i_mount, ip, item->pip, item->ag,
-               xfs_filestream_peek_ag(ip->i_mount, item->ag));
-
-       /*
-        * _xfs_filestream_update_ag() always takes a reference on the inode
-        * itself, whether it's a file or a directory.  Release it here.
-        * This can result in the inode being freed and so we must
-        * not hold any inode locks when freeing filesstreams objects
-        * otherwise we can deadlock here.
-        */
-       IRELE(ip);
-
-       /*
-        * In the case of a regular file, _xfs_filestream_update_ag() also
-        * takes a ref on the parent inode to keep it in-core.  Release that
-        * too.
-        */
-       if (item->pip)
-               IRELE(item->pip);
-
-       /* Finally, free the memory allocated for the item. */
-       kmem_zone_free(item_zone, item);
-}
-
-/*
- * xfs_filestream_init() is called at xfs initialisation time to set up the
- * memory zone that will be used for filestream data structure allocation.
- */
-int
-xfs_filestream_init(void)
-{
-       item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item");
-       if (!item_zone)
-               return -ENOMEM;
-
-       return 0;
-}
-
-/*
- * xfs_filestream_uninit() is called at xfs termination time to destroy the
- * memory zone that was used for filestream data structure allocation.
- */
-void
-xfs_filestream_uninit(void)
-{
-       kmem_zone_destroy(item_zone);
-}
-
-/*
- * xfs_filestream_mount() is called when a file system is mounted with the
- * filestream option.  It is responsible for allocating the data structures
- * needed to track the new file system's file streams.
- */
-int
-xfs_filestream_mount(
-       xfs_mount_t     *mp)
-{
-       int             err;
-       unsigned int    lifetime, grp_count;
-
-       /*
-        * The filestream timer tunable is currently fixed within the range of
-        * one second to four minutes, with five seconds being the default.  The
-        * group count is somewhat arbitrary, but it'd be nice to adhere to the
-        * timer tunable to within about 10 percent.  This requires at least 10
-        * groups.
-        */
-       lifetime  = xfs_fstrm_centisecs * 10;
-       grp_count = 10;
-
-       err = xfs_mru_cache_create(&mp->m_filestream, lifetime, grp_count,
-                            xfs_fstrm_free_func);
 
+out_free_item:
+       kmem_free(item);
+out_put_ag:
+       xfs_filestream_put_ag(mp, *agp);
        return err;
 }
 
-/*
- * xfs_filestream_unmount() is called when a file system that was mounted with
- * the filestream option is unmounted.  It drains the data structures created
- * to track the file system's file streams and frees all the memory that was
- * allocated.
- */
-void
-xfs_filestream_unmount(
-       xfs_mount_t     *mp)
+static struct xfs_inode *
+xfs_filestream_get_parent(
+       struct xfs_inode        *ip)
 {
-       xfs_mru_cache_destroy(mp->m_filestream);
-}
+       struct inode            *inode = VFS_I(ip), *dir = NULL;
+       struct dentry           *dentry, *parent;
 
-/*
- * Return the AG of the filestream the file or directory belongs to, or
- * NULLAGNUMBER otherwise.
- */
-xfs_agnumber_t
-xfs_filestream_lookup_ag(
-       xfs_inode_t     *ip)
-{
-       xfs_mru_cache_t *cache;
-       fstrm_item_t    *item;
-       xfs_agnumber_t  ag;
-       int             ref;
-
-       if (!S_ISREG(ip->i_d.di_mode) && !S_ISDIR(ip->i_d.di_mode)) {
-               ASSERT(0);
-               return NULLAGNUMBER;
-       }
+       dentry = d_find_alias(inode);
+       if (!dentry)
+               goto out;
 
-       cache = ip->i_mount->m_filestream;
-       item = xfs_mru_cache_lookup(cache, ip->i_ino);
-       if (!item) {
-               TRACE_LOOKUP(ip->i_mount, ip, NULL, NULLAGNUMBER, 0);
-               return NULLAGNUMBER;
-       }
+       parent = dget_parent(dentry);
+       if (!parent)
+               goto out_dput;
 
-       ASSERT(ip == item->ip);
-       ag = item->ag;
-       ref = xfs_filestream_peek_ag(ip->i_mount, ag);
-       xfs_mru_cache_done(cache);
+       dir = igrab(parent->d_inode);
+       dput(parent);
 
-       TRACE_LOOKUP(ip->i_mount, ip, item->pip, ag, ref);
-       return ag;
+out_dput:
+       dput(dentry);
+out:
+       return dir ? XFS_I(dir) : NULL;
 }
 
 /*
- * xfs_filestream_associate() should only be called to associate a regular file
- * with its parent directory.  Calling it with a child directory isn't
- * appropriate because filestreams don't apply to entire directory hierarchies.
- * Creating a file in a child directory of an existing filestream directory
- * starts a new filestream with its own allocation group association.
+ * Find the right allocation group for a file, either by finding an
+ * existing file stream or creating a new one.
  *
- * Returns < 0 on error, 0 if successful association occurred, > 0 if
- * we failed to get an association because of locking issues.
+ * Returns NULLAGNUMBER in case of an error.
  */
-int
-xfs_filestream_associate(
-       xfs_inode_t     *pip,
-       xfs_inode_t     *ip)
+xfs_agnumber_t
+xfs_filestream_lookup_ag(
+       struct xfs_inode        *ip)
 {
-       xfs_mount_t     *mp;
-       xfs_mru_cache_t *cache;
-       fstrm_item_t    *item;
-       xfs_agnumber_t  ag, rotorstep, startag;
-       int             err = 0;
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_inode        *pip = NULL;
+       xfs_agnumber_t          startag, ag = NULLAGNUMBER;
+       struct xfs_mru_cache_elem *mru;
 
-       ASSERT(S_ISDIR(pip->i_d.di_mode));
        ASSERT(S_ISREG(ip->i_d.di_mode));
-       if (!S_ISDIR(pip->i_d.di_mode) || !S_ISREG(ip->i_d.di_mode))
-               return -EINVAL;
 
-       mp = pip->i_mount;
-       cache = mp->m_filestream;
+       pip = xfs_filestream_get_parent(ip);
+       if (!pip)
+               goto out;
 
-       /*
-        * We have a problem, Houston.
-        *
-        * Taking the iolock here violates inode locking order - we already
-        * hold the ilock. Hence if we block getting this lock we may never
-        * wake. Unfortunately, that means if we can't get the lock, we're
-        * screwed in terms of getting a stream association - we can't spin
-        * waiting for the lock because someone else is waiting on the lock we
-        * hold and we cannot drop that as we are in a transaction here.
-        *
-        * Lucky for us, this inversion is not a problem because it's a
-        * directory inode that we are trying to lock here.
-        *
-        * So, if we can't get the iolock without sleeping then just give up
-        */
-       if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL))
-               return 1;
-
-       /* If the parent directory is already in the cache, use its AG. */
-       item = xfs_mru_cache_lookup(cache, pip->i_ino);
-       if (item) {
-               ASSERT(item->ip == pip);
-               ag = item->ag;
-               xfs_mru_cache_done(cache);
-
-               TRACE_LOOKUP(mp, pip, pip, ag, xfs_filestream_peek_ag(mp, ag));
-               err = _xfs_filestream_update_ag(ip, pip, ag);
+       mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
+       if (mru) {
+               ag = container_of(mru, struct xfs_fstrm_item, mru)->ag;
+               xfs_mru_cache_done(mp->m_filestream);
 
-               goto exit;
+               trace_xfs_filestream_lookup(ip, ag);
+               goto out;
        }
 
        /*
@@ -623,202 +341,94 @@ xfs_filestream_associate(
         * use the directory inode's AG.
         */
        if (mp->m_flags & XFS_MOUNT_32BITINODES) {
-               rotorstep = xfs_rotorstep;
+               xfs_agnumber_t   rotorstep = xfs_rotorstep;
                startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
                mp->m_agfrotor = (mp->m_agfrotor + 1) %
                                 (mp->m_sb.sb_agcount * rotorstep);
        } else
                startag = XFS_INO_TO_AGNO(mp, pip->i_ino);
 
-       /* Pick a new AG for the parent inode starting at startag. */
-       err = _xfs_filestream_pick_ag(mp, startag, &ag, 0, 0);
-       if (err || ag == NULLAGNUMBER)
-               goto exit_did_pick;
-
-       /* Associate the parent inode with the AG. */
-       err = _xfs_filestream_update_ag(pip, NULL, ag);
-       if (err)
-               goto exit_did_pick;
-
-       /* Associate the file inode with the AG. */
-       err = _xfs_filestream_update_ag(ip, pip, ag);
-       if (err)
-               goto exit_did_pick;
-
-       TRACE_ASSOCIATE(mp, ip, pip, ag, xfs_filestream_peek_ag(mp, ag));
-
-exit_did_pick:
-       /*
-        * If _xfs_filestream_pick_ag() returned a valid AG, remove the
-        * reference it took on it, since the file and directory will have taken
-        * their own now if they were successfully cached.
-        */
-       if (ag != NULLAGNUMBER)
-               xfs_filestream_put_ag(mp, ag);
-
-exit:
-       xfs_iunlock(pip, XFS_IOLOCK_EXCL);
-       return -err;
+       if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0))
+               ag = NULLAGNUMBER;
+out:
+       IRELE(pip);
+       return ag;
 }
 
 /*
- * Pick a new allocation group for the current file and its file stream.  This
- * function is called by xfs_bmap_filestreams() with the mount point's per-ag
- * lock held.
+ * Pick a new allocation group for the current file and its file stream.
+ *
+ * This is called when the allocator can't find a suitable extent in the
+ * current AG, and we have to move the stream into a new AG with more space.
  */
 int
 xfs_filestream_new_ag(
        struct xfs_bmalloca     *ap,
        xfs_agnumber_t          *agp)
 {
-       int             flags, err;
-       xfs_inode_t     *ip, *pip = NULL;
-       xfs_mount_t     *mp;
-       xfs_mru_cache_t *cache;
-       xfs_extlen_t    minlen;
-       fstrm_item_t    *dir, *file;
-       xfs_agnumber_t  ag = NULLAGNUMBER;
-
-       ip = ap->ip;
-       mp = ip->i_mount;
-       cache = mp->m_filestream;
-       minlen = ap->length;
-       *agp = NULLAGNUMBER;
+       struct xfs_inode        *ip = ap->ip, *pip;
+       struct xfs_mount        *mp = ip->i_mount;
+       xfs_extlen_t            minlen = ap->length;
+       xfs_agnumber_t          startag = 0;
+       int                     flags, err = 0;
+       struct xfs_mru_cache_elem *mru;
 
-       /*
-        * Look for the file in the cache, removing it if it's found.  Doing
-        * this allows it to be held across the dir lookup that follows.
-        */
-       file = xfs_mru_cache_remove(cache, ip->i_ino);
-       if (file) {
-               ASSERT(ip == file->ip);
-
-               /* Save the file's parent inode and old AG number for later. */
-               pip = file->pip;
-               ag = file->ag;
-
-               /* Look for the file's directory in the cache. */
-               dir = xfs_mru_cache_lookup(cache, pip->i_ino);
-               if (dir) {
-                       ASSERT(pip == dir->ip);
-
-                       /*
-                        * If the directory has already moved on to a new AG,
-                        * use that AG as the new AG for the file. Don't
-                        * forget to twiddle the AG refcounts to match the
-                        * movement.
-                        */
-                       if (dir->ag != file->ag) {
-                               xfs_filestream_put_ag(mp, file->ag);
-                               xfs_filestream_get_ag(mp, dir->ag);
-                               *agp = file->ag = dir->ag;
-                       }
-
-                       xfs_mru_cache_done(cache);
-               }
+       *agp = NULLAGNUMBER;
 
-               /*
-                * Put the file back in the cache.  If this fails, the free
-                * function needs to be called to tidy up in the same way as if
-                * the item had simply expired from the cache.
-                */
-               err = xfs_mru_cache_insert(cache, ip->i_ino, file);
-               if (err) {
-                       xfs_fstrm_free_func(ip->i_ino, file);
-                       return err;
-               }
+       pip = xfs_filestream_get_parent(ip);
+       if (!pip)
+               goto exit;
 
-               /*
-                * If the file's AG was moved to the directory's new AG, there's
-                * nothing more to be done.
-                */
-               if (*agp != NULLAGNUMBER) {
-                       TRACE_MOVEAG(mp, ip, pip,
-                                       ag, xfs_filestream_peek_ag(mp, ag),
-                                       *agp, xfs_filestream_peek_ag(mp, *agp));
-                       return 0;
-               }
+       mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
+       if (mru) {
+               struct xfs_fstrm_item *item =
+                       container_of(mru, struct xfs_fstrm_item, mru);
+               startag = (item->ag + 1) % mp->m_sb.sb_agcount;
        }
 
-       /*
-        * If the file's parent directory is known, take its iolock in exclusive
-        * mode to prevent two sibling files from racing each other to migrate
-        * themselves and their parent to different AGs.
-        *
-        * Note that we lock the parent directory iolock inside the child
-        * iolock here.  That's fine as we never hold both parent and child
-        * iolock in any other place.  This is different from the ilock,
-        * which requires locking of the child after the parent for namespace
-        * operations.
-        */
-       if (pip)
-               xfs_ilock(pip, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
-
-       /*
-        * A new AG needs to be found for the file.  If the file's parent
-        * directory is also known, it will be moved to the new AG as well to
-        * ensure that files created inside it in future use the new AG.
-        */
-       ag = (ag == NULLAGNUMBER) ? 0 : (ag + 1) % mp->m_sb.sb_agcount;
        flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
                (ap->flist->xbf_low ? XFS_PICK_LOWSPACE : 0);
 
-       err = _xfs_filestream_pick_ag(mp, ag, agp, flags, minlen);
-       if (err || *agp == NULLAGNUMBER)
-               goto exit;
+       err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
 
        /*
-        * If the file wasn't found in the file cache, then its parent directory
-        * inode isn't known.  For this to have happened, the file must either
-        * be pre-existing, or it was created long enough ago that its cache
-        * entry has expired.  This isn't the sort of usage that the filestreams
-        * allocator is trying to optimise, so there's no point trying to track
-        * its new AG somehow in the filestream data structures.
+        * Only free the item here so we skip over the old AG earlier.
         */
-       if (!pip) {
-               TRACE_ORPHAN(mp, ip, *agp);
-               goto exit;
-       }
-
-       /* Associate the parent inode with the AG. */
-       err = _xfs_filestream_update_ag(pip, NULL, *agp);
-       if (err)
-               goto exit;
-
-       /* Associate the file inode with the AG. */
-       err = _xfs_filestream_update_ag(ip, pip, *agp);
-       if (err)
-               goto exit;
-
-       TRACE_MOVEAG(mp, ip, pip, NULLAGNUMBER, 0,
-                       *agp, xfs_filestream_peek_ag(mp, *agp));
+       if (mru)
+               xfs_fstrm_free_func(mru);
 
+       IRELE(pip);
 exit:
-       /*
-        * If _xfs_filestream_pick_ag() returned a valid AG, remove the
-        * reference it took on it, since the file and directory will have taken
-        * their own now if they were successfully cached.
-        */
-       if (*agp != NULLAGNUMBER)
-               xfs_filestream_put_ag(mp, *agp);
-       else
+       if (*agp == NULLAGNUMBER)
                *agp = 0;
-
-       if (pip)
-               xfs_iunlock(pip, XFS_IOLOCK_EXCL);
-
        return err;
 }
 
-/*
- * Remove an association between an inode and a filestream object.
- * Typically this is done on last close of an unlinked file.
- */
 void
 xfs_filestream_deassociate(
-       xfs_inode_t     *ip)
+       struct xfs_inode        *ip)
 {
-       xfs_mru_cache_t *cache = ip->i_mount->m_filestream;
+       xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
+}
+
+int
+xfs_filestream_mount(
+       xfs_mount_t     *mp)
+{
+       /*
+        * The filestream timer tunable is currently fixed within the range of
+        * one second to four minutes, with five seconds being the default.  The
+        * group count is somewhat arbitrary, but it'd be nice to adhere to the
+        * timer tunable to within about 10 percent.  This requires at least 10
+        * groups.
+        */
+       return xfs_mru_cache_create(&mp->m_filestream, xfs_fstrm_centisecs * 10,
+                                   10, xfs_fstrm_free_func);
+}
 
-       xfs_mru_cache_delete(cache, ip->i_ino);
+void
+xfs_filestream_unmount(
+       xfs_mount_t     *mp)
+{
+       xfs_mru_cache_destroy(mp->m_filestream);
 }
index 6d61dbee8564b12cca254721bf78685975799a74..2ef43406e53bd91cba503fb73527d2604136386a 100644 (file)
 
 struct xfs_mount;
 struct xfs_inode;
-struct xfs_perag;
 struct xfs_bmalloca;
 
-#ifdef XFS_FILESTREAMS_TRACE
-#define XFS_FSTRM_KTRACE_INFO          1
-#define XFS_FSTRM_KTRACE_AGSCAN                2
-#define XFS_FSTRM_KTRACE_AGPICK1       3
-#define XFS_FSTRM_KTRACE_AGPICK2       4
-#define XFS_FSTRM_KTRACE_UPDATE                5
-#define XFS_FSTRM_KTRACE_FREE          6
-#define        XFS_FSTRM_KTRACE_ITEM_LOOKUP    7
-#define        XFS_FSTRM_KTRACE_ASSOCIATE      8
-#define        XFS_FSTRM_KTRACE_MOVEAG         9
-#define        XFS_FSTRM_KTRACE_ORPHAN         10
-
-#define XFS_FSTRM_KTRACE_SIZE  16384
-extern ktrace_t *xfs_filestreams_trace_buf;
-
-#endif
-
-/* allocation selection flags */
-typedef enum xfs_fstrm_alloc {
-       XFS_PICK_USERDATA = 1,
-       XFS_PICK_LOWSPACE = 2,
-} xfs_fstrm_alloc_t;
-
-/* prototypes for filestream.c */
-int xfs_filestream_init(void);
-void xfs_filestream_uninit(void);
 int xfs_filestream_mount(struct xfs_mount *mp);
 void xfs_filestream_unmount(struct xfs_mount *mp);
-xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
-int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip);
 void xfs_filestream_deassociate(struct xfs_inode *ip);
+xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
 int xfs_filestream_new_ag(struct xfs_bmalloca *ap, xfs_agnumber_t *agp);
+int xfs_filestream_peek_ag(struct xfs_mount *mp, xfs_agnumber_t agno);
 
-
-/* filestreams for the inode? */
 static inline int
 xfs_inode_is_filestream(
        struct xfs_inode        *ip)
 {
        return (ip->i_mount->m_flags & XFS_MOUNT_FILESTREAMS) ||
-               xfs_iflags_test(ip, XFS_IFILESTREAM) ||
                (ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM);
 }
 
index 9898f31d05d8c2f7096647b8750ede07808b5a54..34d85aca305801ea3b1e982bab49305099dac465 100644 (file)
@@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t;
  */
 #define        XFS_IBT_MAGIC           0x49414254      /* 'IABT' */
 #define        XFS_IBT_CRC_MAGIC       0x49414233      /* 'IAB3' */
+#define        XFS_FIBT_MAGIC          0x46494254      /* 'FIBT' */
+#define        XFS_FIBT_CRC_MAGIC      0x46494233      /* 'FIB3' */
 
 typedef        __uint64_t      xfs_inofree_t;
 #define        XFS_INODES_PER_CHUNK            (NBBY * sizeof(xfs_inofree_t))
@@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t;
  * block numbers in the AG.
  */
 #define        XFS_IBT_BLOCK(mp)               ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1))
-#define        XFS_PREALLOC_BLOCKS(mp)         ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
+#define        XFS_FIBT_BLOCK(mp)              ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
+
+/*
+ * The first data block of an AG depends on whether the filesystem was formatted
+ * with the finobt feature. If so, account for the finobt reserved root btree
+ * block.
+ */
+#define XFS_PREALLOC_BLOCKS(mp) \
+       (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
+        XFS_FIBT_BLOCK(mp) + 1 : \
+        XFS_IBT_BLOCK(mp) + 1)
 
 
 
index c5fc116dfaa307b156e0b652bfffd4f80c173b89..d34703dbcb423b7fdbb52438b2525dd74417f1eb 100644 (file)
@@ -238,6 +238,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_LAZYSB     0x4000  /* lazy superblock counters */
 #define XFS_FSOP_GEOM_FLAGS_V5SB       0x8000  /* version 5 superblock */
 #define XFS_FSOP_GEOM_FLAGS_FTYPE      0x10000 /* inode directory types */
+#define XFS_FSOP_GEOM_FLAGS_FINOBT     0x20000 /* free inode btree */
 
 /*
  * Minimum and maximum sizes need for growth checks.
index 02fb943cbf22b36b4e6da8c66b03be8839dc03d4..3445ead7c1fcfb63611d018ec38cb78a68ae1fcf 100644 (file)
@@ -104,7 +104,9 @@ xfs_fs_geometry(
                        (xfs_sb_version_hascrc(&mp->m_sb) ?
                                XFS_FSOP_GEOM_FLAGS_V5SB : 0) |
                        (xfs_sb_version_hasftype(&mp->m_sb) ?
-                               XFS_FSOP_GEOM_FLAGS_FTYPE : 0);
+                               XFS_FSOP_GEOM_FLAGS_FTYPE : 0) |
+                       (xfs_sb_version_hasfinobt(&mp->m_sb) ?
+                               XFS_FSOP_GEOM_FLAGS_FINOBT : 0);
                geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
                                mp->m_sb.sb_logsectsize : BBSIZE;
                geo->rtsectsize = mp->m_sb.sb_blocksize;
@@ -316,6 +318,10 @@ xfs_growfs_data_private(
                agi->agi_dirino = cpu_to_be32(NULLAGINO);
                if (xfs_sb_version_hascrc(&mp->m_sb))
                        uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+               if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+                       agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
+                       agi->agi_free_level = cpu_to_be32(1);
+               }
                for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
                        agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
 
@@ -407,6 +413,34 @@ xfs_growfs_data_private(
                xfs_buf_relse(bp);
                if (error)
                        goto error0;
+
+               /*
+                * FINO btree root block
+                */
+               if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+                       bp = xfs_growfs_get_hdr_buf(mp,
+                               XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
+                               BTOBB(mp->m_sb.sb_blocksize), 0,
+                               &xfs_inobt_buf_ops);
+                       if (!bp) {
+                               error = ENOMEM;
+                               goto error0;
+                       }
+
+                       if (xfs_sb_version_hascrc(&mp->m_sb))
+                               xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC,
+                                                    0, 0, agno,
+                                                    XFS_BTREE_CRC_BLOCKS);
+                       else
+                               xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0,
+                                                    0, agno, 0);
+
+                       error = xfs_bwrite(bp);
+                       xfs_buf_relse(bp);
+                       if (error)
+                               goto error0;
+               }
+
        }
        xfs_trans_agblocks_delta(tp, nfree);
        /*
index 8f711db61a0c2148ecfd98c22bed1509fa437e11..6ac0c2986c32ef28e7143e7516cd92ad703f7352 100644 (file)
@@ -111,6 +111,66 @@ xfs_inobt_get_rec(
        return error;
 }
 
+/*
+ * Insert a single inobt record. Cursor must already point to desired location.
+ */
+STATIC int
+xfs_inobt_insert_rec(
+       struct xfs_btree_cur    *cur,
+       __int32_t               freecount,
+       xfs_inofree_t           free,
+       int                     *stat)
+{
+       cur->bc_rec.i.ir_freecount = freecount;
+       cur->bc_rec.i.ir_free = free;
+       return xfs_btree_insert(cur, stat);
+}
+
+/*
+ * Insert records describing a newly allocated inode chunk into the inobt.
+ */
+STATIC int
+xfs_inobt_insert(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       xfs_agino_t             newino,
+       xfs_agino_t             newlen,
+       xfs_btnum_t             btnum)
+{
+       struct xfs_btree_cur    *cur;
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
+       xfs_agnumber_t          agno = be32_to_cpu(agi->agi_seqno);
+       xfs_agino_t             thisino;
+       int                     i;
+       int                     error;
+
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
+
+       for (thisino = newino;
+            thisino < newino + newlen;
+            thisino += XFS_INODES_PER_CHUNK) {
+               error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i);
+               if (error) {
+                       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+                       return error;
+               }
+               ASSERT(i == 0);
+
+               error = xfs_inobt_insert_rec(cur, XFS_INODES_PER_CHUNK,
+                                            XFS_INOBT_ALL_FREE, &i);
+               if (error) {
+                       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+                       return error;
+               }
+               ASSERT(i == 1);
+       }
+
+       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+
+       return 0;
+}
+
 /*
  * Verify that the number of free inodes in the AGI is correct.
  */
@@ -303,13 +363,10 @@ xfs_ialloc_ag_alloc(
 {
        xfs_agi_t       *agi;           /* allocation group header */
        xfs_alloc_arg_t args;           /* allocation argument structure */
-       xfs_btree_cur_t *cur;           /* inode btree cursor */
        xfs_agnumber_t  agno;
        int             error;
-       int             i;
        xfs_agino_t     newino;         /* new first inode's number */
        xfs_agino_t     newlen;         /* new number of inodes */
-       xfs_agino_t     thisino;        /* current inode number, for loop */
        int             isaligned = 0;  /* inode allocation at stripe unit */
                                        /* boundary */
        struct xfs_perag *pag;
@@ -459,29 +516,19 @@ xfs_ialloc_ag_alloc(
        agi->agi_newino = cpu_to_be32(newino);
 
        /*
-        * Insert records describing the new inode chunk into the btree.
+        * Insert records describing the new inode chunk into the btrees.
         */
-       cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno);
-       for (thisino = newino;
-            thisino < newino + newlen;
-            thisino += XFS_INODES_PER_CHUNK) {
-               cur->bc_rec.i.ir_startino = thisino;
-               cur->bc_rec.i.ir_freecount = XFS_INODES_PER_CHUNK;
-               cur->bc_rec.i.ir_free = XFS_INOBT_ALL_FREE;
-               error = xfs_btree_lookup(cur, XFS_LOOKUP_EQ, &i);
-               if (error) {
-                       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
-                       return error;
-               }
-               ASSERT(i == 0);
-               error = xfs_btree_insert(cur, &i);
-               if (error) {
-                       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
+                                XFS_BTNUM_INO);
+       if (error)
+               return error;
+
+       if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
+               error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
+                                        XFS_BTNUM_FINO);
+               if (error)
                        return error;
-               }
-               ASSERT(i == 1);
        }
-       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
        /*
         * Log allocation group header fields
         */
@@ -675,13 +722,10 @@ xfs_ialloc_get_rec(
 }
 
 /*
- * Allocate an inode.
- *
- * The caller selected an AG for us, and made sure that free inodes are
- * available.
+ * Allocate an inode using the inobt-only algorithm.
  */
 STATIC int
-xfs_dialloc_ag(
+xfs_dialloc_ag_inobt(
        struct xfs_trans        *tp,
        struct xfs_buf          *agbp,
        xfs_ino_t               parent,
@@ -707,7 +751,7 @@ xfs_dialloc_ag(
        ASSERT(pag->pagi_freecount > 0);
 
  restart_pagno:
-       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
        /*
         * If pagino is 0 (this is the root inode allocation) use newino.
         * This must work because we've just allocated some.
@@ -939,6 +983,294 @@ error0:
        return error;
 }
 
+/*
+ * Use the free inode btree to allocate an inode based on distance from the
+ * parent. Note that the provided cursor may be deleted and replaced.
+ */
+STATIC int
+xfs_dialloc_ag_finobt_near(
+       xfs_agino_t                     pagino,
+       struct xfs_btree_cur            **ocur,
+       struct xfs_inobt_rec_incore     *rec)
+{
+       struct xfs_btree_cur            *lcur = *ocur;  /* left search cursor */
+       struct xfs_btree_cur            *rcur;  /* right search cursor */
+       struct xfs_inobt_rec_incore     rrec;
+       int                             error;
+       int                             i, j;
+
+       error = xfs_inobt_lookup(lcur, pagino, XFS_LOOKUP_LE, &i);
+       if (error)
+               return error;
+
+       if (i == 1) {
+               error = xfs_inobt_get_rec(lcur, rec, &i);
+               if (error)
+                       return error;
+               XFS_WANT_CORRUPTED_RETURN(i == 1);
+
+               /*
+                * See if we've landed in the parent inode record. The finobt
+                * only tracks chunks with at least one free inode, so record
+                * existence is enough.
+                */
+               if (pagino >= rec->ir_startino &&
+                   pagino < (rec->ir_startino + XFS_INODES_PER_CHUNK))
+                       return 0;
+       }
+
+       error = xfs_btree_dup_cursor(lcur, &rcur);
+       if (error)
+               return error;
+
+       error = xfs_inobt_lookup(rcur, pagino, XFS_LOOKUP_GE, &j);
+       if (error)
+               goto error_rcur;
+       if (j == 1) {
+               error = xfs_inobt_get_rec(rcur, &rrec, &j);
+               if (error)
+                       goto error_rcur;
+               XFS_WANT_CORRUPTED_GOTO(j == 1, error_rcur);
+       }
+
+       XFS_WANT_CORRUPTED_GOTO(i == 1 || j == 1, error_rcur);
+       if (i == 1 && j == 1) {
+               /*
+                * Both the left and right records are valid. Choose the closer
+                * inode chunk to the target.
+                */
+               if ((pagino - rec->ir_startino + XFS_INODES_PER_CHUNK - 1) >
+                   (rrec.ir_startino - pagino)) {
+                       *rec = rrec;
+                       xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR);
+                       *ocur = rcur;
+               } else {
+                       xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR);
+               }
+       } else if (j == 1) {
+               /* only the right record is valid */
+               *rec = rrec;
+               xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR);
+               *ocur = rcur;
+       } else if (i == 1) {
+               /* only the left record is valid */
+               xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR);
+       }
+
+       return 0;
+
+error_rcur:
+       xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR);
+       return error;
+}
+
+/*
+ * Use the free inode btree to find a free inode based on a newino hint. If
+ * the hint is NULL, find the first free inode in the AG.
+ */
+STATIC int
+xfs_dialloc_ag_finobt_newino(
+       struct xfs_agi                  *agi,
+       struct xfs_btree_cur            *cur,
+       struct xfs_inobt_rec_incore     *rec)
+{
+       int error;
+       int i;
+
+       if (agi->agi_newino != cpu_to_be32(NULLAGINO)) {
+               error = xfs_inobt_lookup(cur, agi->agi_newino, XFS_LOOKUP_EQ,
+                                        &i);
+               if (error)
+                       return error;
+               if (i == 1) {
+                       error = xfs_inobt_get_rec(cur, rec, &i);
+                       if (error)
+                               return error;
+                       XFS_WANT_CORRUPTED_RETURN(i == 1);
+
+                       return 0;
+               }
+       }
+
+       /*
+        * Find the first inode available in the AG.
+        */
+       error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
+       if (error)
+               return error;
+       XFS_WANT_CORRUPTED_RETURN(i == 1);
+
+       error = xfs_inobt_get_rec(cur, rec, &i);
+       if (error)
+               return error;
+       XFS_WANT_CORRUPTED_RETURN(i == 1);
+
+       return 0;
+}
+
+/*
+ * Update the inobt based on a modification made to the finobt. Also ensure that
+ * the records from both trees are equivalent post-modification.
+ */
+STATIC int
+xfs_dialloc_ag_update_inobt(
+       struct xfs_btree_cur            *cur,   /* inobt cursor */
+       struct xfs_inobt_rec_incore     *frec,  /* finobt record */
+       int                             offset) /* inode offset */
+{
+       struct xfs_inobt_rec_incore     rec;
+       int                             error;
+       int                             i;
+
+       error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i);
+       if (error)
+               return error;
+       XFS_WANT_CORRUPTED_RETURN(i == 1);
+
+       error = xfs_inobt_get_rec(cur, &rec, &i);
+       if (error)
+               return error;
+       XFS_WANT_CORRUPTED_RETURN(i == 1);
+       ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) %
+                                  XFS_INODES_PER_CHUNK) == 0);
+
+       rec.ir_free &= ~XFS_INOBT_MASK(offset);
+       rec.ir_freecount--;
+
+       XFS_WANT_CORRUPTED_RETURN((rec.ir_free == frec->ir_free) &&
+                                 (rec.ir_freecount == frec->ir_freecount));
+
+       error = xfs_inobt_update(cur, &rec);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+/*
+ * Allocate an inode using the free inode btree, if available. Otherwise, fall
+ * back to the inobt search algorithm.
+ *
+ * The caller selected an AG for us, and made sure that free inodes are
+ * available.
+ */
+STATIC int
+xfs_dialloc_ag(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       xfs_ino_t               parent,
+       xfs_ino_t               *inop)
+{
+       struct xfs_mount                *mp = tp->t_mountp;
+       struct xfs_agi                  *agi = XFS_BUF_TO_AGI(agbp);
+       xfs_agnumber_t                  agno = be32_to_cpu(agi->agi_seqno);
+       xfs_agnumber_t                  pagno = XFS_INO_TO_AGNO(mp, parent);
+       xfs_agino_t                     pagino = XFS_INO_TO_AGINO(mp, parent);
+       struct xfs_perag                *pag;
+       struct xfs_btree_cur            *cur;   /* finobt cursor */
+       struct xfs_btree_cur            *icur;  /* inobt cursor */
+       struct xfs_inobt_rec_incore     rec;
+       xfs_ino_t                       ino;
+       int                             error;
+       int                             offset;
+       int                             i;
+
+       if (!xfs_sb_version_hasfinobt(&mp->m_sb))
+               return xfs_dialloc_ag_inobt(tp, agbp, parent, inop);
+
+       pag = xfs_perag_get(mp, agno);
+
+       /*
+        * If pagino is 0 (this is the root inode allocation) use newino.
+        * This must work because we've just allocated some.
+        */
+       if (!pagino)
+               pagino = be32_to_cpu(agi->agi_newino);
+
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
+
+       error = xfs_check_agi_freecount(cur, agi);
+       if (error)
+               goto error_cur;
+
+       /*
+        * The search algorithm depends on whether we're in the same AG as the
+        * parent. If so, find the closest available inode to the parent. If
+        * not, consider the agi hint or find the first free inode in the AG.
+        */
+       if (agno == pagno)
+               error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec);
+       else
+               error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec);
+       if (error)
+               goto error_cur;
+
+       offset = xfs_lowbit64(rec.ir_free);
+       ASSERT(offset >= 0);
+       ASSERT(offset < XFS_INODES_PER_CHUNK);
+       ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
+                                  XFS_INODES_PER_CHUNK) == 0);
+       ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
+
+       /*
+        * Modify or remove the finobt record.
+        */
+       rec.ir_free &= ~XFS_INOBT_MASK(offset);
+       rec.ir_freecount--;
+       if (rec.ir_freecount)
+               error = xfs_inobt_update(cur, &rec);
+       else
+               error = xfs_btree_delete(cur, &i);
+       if (error)
+               goto error_cur;
+
+       /*
+        * The finobt has now been updated appropriately. We haven't updated the
+        * agi and superblock yet, so we can create an inobt cursor and validate
+        * the original freecount. If all is well, make the equivalent update to
+        * the inobt using the finobt record and offset information.
+        */
+       icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+
+       error = xfs_check_agi_freecount(icur, agi);
+       if (error)
+               goto error_icur;
+
+       error = xfs_dialloc_ag_update_inobt(icur, &rec, offset);
+       if (error)
+               goto error_icur;
+
+       /*
+        * Both trees have now been updated. We must update the perag and
+        * superblock before we can check the freecount for each btree.
+        */
+       be32_add_cpu(&agi->agi_freecount, -1);
+       xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
+       pag->pagi_freecount--;
+
+       xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
+
+       error = xfs_check_agi_freecount(icur, agi);
+       if (error)
+               goto error_icur;
+       error = xfs_check_agi_freecount(cur, agi);
+       if (error)
+               goto error_icur;
+
+       xfs_btree_del_cursor(icur, XFS_BTREE_NOERROR);
+       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+       xfs_perag_put(pag);
+       *inop = ino;
+       return 0;
+
+error_icur:
+       xfs_btree_del_cursor(icur, XFS_BTREE_ERROR);
+error_cur:
+       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       xfs_perag_put(pag);
+       return error;
+}
+
 /*
  * Allocate an inode on disk.
  *
@@ -1098,78 +1430,34 @@ out_error:
        return XFS_ERROR(error);
 }
 
-/*
- * Free disk inode.  Carefully avoids touching the incore inode, all
- * manipulations incore are the caller's responsibility.
- * The on-disk inode is not changed by this operation, only the
- * btree (free inode mask) is changed.
- */
-int
-xfs_difree(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_ino_t       inode,          /* inode to be freed */
-       xfs_bmap_free_t *flist,         /* extents to free */
-       int             *delete,        /* set if inode cluster was deleted */
-       xfs_ino_t       *first_ino)     /* first inode in deleted cluster */
+STATIC int
+xfs_difree_inobt(
+       struct xfs_mount                *mp,
+       struct xfs_trans                *tp,
+       struct xfs_buf                  *agbp,
+       xfs_agino_t                     agino,
+       struct xfs_bmap_free            *flist,
+       int                             *delete,
+       xfs_ino_t                       *first_ino,
+       struct xfs_inobt_rec_incore     *orec)
 {
-       /* REFERENCED */
-       xfs_agblock_t   agbno;  /* block number containing inode */
-       xfs_buf_t       *agbp;  /* buffer containing allocation group header */
-       xfs_agino_t     agino;  /* inode number relative to allocation group */
-       xfs_agnumber_t  agno;   /* allocation group number */
-       xfs_agi_t       *agi;   /* allocation group header */
-       xfs_btree_cur_t *cur;   /* inode btree cursor */
-       int             error;  /* error return value */
-       int             i;      /* result code */
-       int             ilen;   /* inodes in an inode cluster */
-       xfs_mount_t     *mp;    /* mount structure for filesystem */
-       int             off;    /* offset of inode in inode chunk */
-       xfs_inobt_rec_incore_t rec;     /* btree record */
-       struct xfs_perag *pag;
-
-       mp = tp->t_mountp;
+       struct xfs_agi                  *agi = XFS_BUF_TO_AGI(agbp);
+       xfs_agnumber_t                  agno = be32_to_cpu(agi->agi_seqno);
+       struct xfs_perag                *pag;
+       struct xfs_btree_cur            *cur;
+       struct xfs_inobt_rec_incore     rec;
+       int                             ilen;
+       int                             error;
+       int                             i;
+       int                             off;
 
-       /*
-        * Break up inode number into its components.
-        */
-       agno = XFS_INO_TO_AGNO(mp, inode);
-       if (agno >= mp->m_sb.sb_agcount)  {
-               xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
-                       __func__, agno, mp->m_sb.sb_agcount);
-               ASSERT(0);
-               return XFS_ERROR(EINVAL);
-       }
-       agino = XFS_INO_TO_AGINO(mp, inode);
-       if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
-               xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
-                       __func__, (unsigned long long)inode,
-                       (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
-               ASSERT(0);
-               return XFS_ERROR(EINVAL);
-       }
-       agbno = XFS_AGINO_TO_AGBNO(mp, agino);
-       if (agbno >= mp->m_sb.sb_agblocks)  {
-               xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
-                       __func__, agbno, mp->m_sb.sb_agblocks);
-               ASSERT(0);
-               return XFS_ERROR(EINVAL);
-       }
-       /*
-        * Get the allocation group header.
-        */
-       error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
-       if (error) {
-               xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
-                       __func__, error);
-               return error;
-       }
-       agi = XFS_BUF_TO_AGI(agbp);
        ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
-       ASSERT(agbno < be32_to_cpu(agi->agi_length));
+       ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length));
+
        /*
         * Initialize the cursor.
         */
-       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
 
        error = xfs_check_agi_freecount(cur, agi);
        if (error)
@@ -1261,6 +1549,7 @@ xfs_difree(
        if (error)
                goto error0;
 
+       *orec = rec;
        xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
        return 0;
 
@@ -1269,6 +1558,182 @@ error0:
        return error;
 }
 
+/*
+ * Free an inode in the free inode btree.
+ */
+STATIC int
+xfs_difree_finobt(
+       struct xfs_mount                *mp,
+       struct xfs_trans                *tp,
+       struct xfs_buf                  *agbp,
+       xfs_agino_t                     agino,
+       struct xfs_inobt_rec_incore     *ibtrec) /* inobt record */
+{
+       struct xfs_agi                  *agi = XFS_BUF_TO_AGI(agbp);
+       xfs_agnumber_t                  agno = be32_to_cpu(agi->agi_seqno);
+       struct xfs_btree_cur            *cur;
+       struct xfs_inobt_rec_incore     rec;
+       int                             offset = agino - ibtrec->ir_startino;
+       int                             error;
+       int                             i;
+
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
+
+       error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
+       if (error)
+               goto error;
+       if (i == 0) {
+               /*
+                * If the record does not exist in the finobt, we must have just
+                * freed an inode in a previously fully allocated chunk. If not,
+                * something is out of sync.
+                */
+               XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error);
+
+               error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount,
+                                            ibtrec->ir_free, &i);
+               if (error)
+                       goto error;
+               ASSERT(i == 1);
+
+               goto out;
+       }
+
+       /*
+        * Read and update the existing record. We could just copy the ibtrec
+        * across here, but that would defeat the purpose of having redundant
+        * metadata. By making the modifications independently, we can catch
+        * corruptions that we wouldn't see if we just copied from one record
+        * to another.
+        */
+       error = xfs_inobt_get_rec(cur, &rec, &i);
+       if (error)
+               goto error;
+       XFS_WANT_CORRUPTED_GOTO(i == 1, error);
+
+       rec.ir_free |= XFS_INOBT_MASK(offset);
+       rec.ir_freecount++;
+
+       XFS_WANT_CORRUPTED_GOTO((rec.ir_free == ibtrec->ir_free) &&
+                               (rec.ir_freecount == ibtrec->ir_freecount),
+                               error);
+
+       /*
+        * The content of inobt records should always match between the inobt
+        * and finobt. The lifecycle of records in the finobt is different from
+        * the inobt in that the finobt only tracks records with at least one
+        * free inode. Hence, if all of the inodes are free and we aren't
+        * keeping inode chunks permanently on disk, remove the record.
+        * Otherwise, update the record with the new information.
+        */
+       if (rec.ir_freecount == mp->m_ialloc_inos &&
+           !(mp->m_flags & XFS_MOUNT_IKEEP)) {
+               error = xfs_btree_delete(cur, &i);
+               if (error)
+                       goto error;
+               ASSERT(i == 1);
+       } else {
+               error = xfs_inobt_update(cur, &rec);
+               if (error)
+                       goto error;
+       }
+
+out:
+       error = xfs_check_agi_freecount(cur, agi);
+       if (error)
+               goto error;
+
+       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+       return 0;
+
+error:
+       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       return error;
+}
+
+/*
+ * Free disk inode.  Carefully avoids touching the incore inode, all
+ * manipulations incore are the caller's responsibility.
+ * The on-disk inode is not changed by this operation, only the
+ * btree (free inode mask) is changed.
+ */
+int
+xfs_difree(
+       struct xfs_trans        *tp,            /* transaction pointer */
+       xfs_ino_t               inode,          /* inode to be freed */
+       struct xfs_bmap_free    *flist,         /* extents to free */
+       int                     *delete,/* set if inode cluster was deleted */
+       xfs_ino_t               *first_ino)/* first inode in deleted cluster */
+{
+       /* REFERENCED */
+       xfs_agblock_t           agbno;  /* block number containing inode */
+       struct xfs_buf          *agbp;  /* buffer for allocation group header */
+       xfs_agino_t             agino;  /* allocation group inode number */
+       xfs_agnumber_t          agno;   /* allocation group number */
+       int                     error;  /* error return value */
+       struct xfs_mount        *mp;    /* mount structure for filesystem */
+       struct xfs_inobt_rec_incore rec;/* btree record */
+
+       mp = tp->t_mountp;
+
+       /*
+        * Break up inode number into its components.
+        */
+       agno = XFS_INO_TO_AGNO(mp, inode);
+       if (agno >= mp->m_sb.sb_agcount)  {
+               xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
+                       __func__, agno, mp->m_sb.sb_agcount);
+               ASSERT(0);
+               return XFS_ERROR(EINVAL);
+       }
+       agino = XFS_INO_TO_AGINO(mp, inode);
+       if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
+               xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
+                       __func__, (unsigned long long)inode,
+                       (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
+               ASSERT(0);
+               return XFS_ERROR(EINVAL);
+       }
+       agbno = XFS_AGINO_TO_AGBNO(mp, agino);
+       if (agbno >= mp->m_sb.sb_agblocks)  {
+               xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
+                       __func__, agbno, mp->m_sb.sb_agblocks);
+               ASSERT(0);
+               return XFS_ERROR(EINVAL);
+       }
+       /*
+        * Get the allocation group header.
+        */
+       error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+       if (error) {
+               xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
+                       __func__, error);
+               return error;
+       }
+
+       /*
+        * Fix up the inode allocation btree.
+        */
+       error = xfs_difree_inobt(mp, tp, agbp, agino, flist, delete, first_ino,
+                                &rec);
+       if (error)
+               goto error0;
+
+       /*
+        * Fix up the free inode btree.
+        */
+       if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+               error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
+               if (error)
+                       goto error0;
+       }
+
+       return 0;
+
+error0:
+       return error;
+}
+
 STATIC int
 xfs_imap_lookup(
        struct xfs_mount        *mp,
@@ -1300,7 +1765,7 @@ xfs_imap_lookup(
         * we have a record, we need to ensure it contains the inode number
         * we are looking up.
         */
-       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
        error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
        if (!error) {
                if (i)
@@ -1488,7 +1953,16 @@ xfs_ialloc_compute_maxlevels(
 }
 
 /*
- * Log specified fields for the ag hdr (inode section)
+ * Log specified fields for the ag hdr (inode section). The growth of the agi
+ * structure over time requires that we interpret the buffer as two logical
+ * regions delineated by the end of the unlinked list. This is due to the size
+ * of the hash table and its location in the middle of the agi.
+ *
+ * For example, a request to log a field before agi_unlinked and a field after
+ * agi_unlinked could cause us to log the entire hash table and use an excessive
+ * amount of log space. To avoid this behavior, log the region up through
+ * agi_unlinked in one call and the region after agi_unlinked through the end of
+ * the structure in another.
  */
 void
 xfs_ialloc_log_agi(
@@ -1511,6 +1985,8 @@ xfs_ialloc_log_agi(
                offsetof(xfs_agi_t, agi_newino),
                offsetof(xfs_agi_t, agi_dirino),
                offsetof(xfs_agi_t, agi_unlinked),
+               offsetof(xfs_agi_t, agi_free_root),
+               offsetof(xfs_agi_t, agi_free_level),
                sizeof(xfs_agi_t)
        };
 #ifdef DEBUG
@@ -1519,15 +1995,30 @@ xfs_ialloc_log_agi(
        agi = XFS_BUF_TO_AGI(bp);
        ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
 #endif
+
+       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
+
        /*
-        * Compute byte offsets for the first and last fields.
+        * Compute byte offsets for the first and last fields in the first
+        * region and log the agi buffer. This only logs up through
+        * agi_unlinked.
         */
-       xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last);
+       if (fields & XFS_AGI_ALL_BITS_R1) {
+               xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1,
+                                 &first, &last);
+               xfs_trans_log_buf(tp, bp, first, last);
+       }
+
        /*
-        * Log the allocation group inode header buffer.
+        * Mask off the bits in the first region and calculate the first and
+        * last field offsets for any bits in the second region.
         */
-       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
-       xfs_trans_log_buf(tp, bp, first, last);
+       fields &= ~XFS_AGI_ALL_BITS_R1;
+       if (fields) {
+               xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2,
+                                 &first, &last);
+               xfs_trans_log_buf(tp, bp, first, last);
+       }
 }
 
 #ifdef DEBUG
index 7e309b11e87d75240cfdb41428d1f13dc7d470b8..726f83a681a59412817e7281774f7fa7ca77a3d2 100644 (file)
@@ -49,7 +49,8 @@ xfs_inobt_dup_cursor(
        struct xfs_btree_cur    *cur)
 {
        return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
-                       cur->bc_private.a.agbp, cur->bc_private.a.agno);
+                       cur->bc_private.a.agbp, cur->bc_private.a.agno,
+                       cur->bc_btnum);
 }
 
 STATIC void
@@ -66,12 +67,26 @@ xfs_inobt_set_root(
        xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
 }
 
+STATIC void
+xfs_finobt_set_root(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *nptr,
+       int                     inc)    /* level change */
+{
+       struct xfs_buf          *agbp = cur->bc_private.a.agbp;
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
+
+       agi->agi_free_root = nptr->s;
+       be32_add_cpu(&agi->agi_free_level, inc);
+       xfs_ialloc_log_agi(cur->bc_tp, agbp,
+                          XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL);
+}
+
 STATIC int
 xfs_inobt_alloc_block(
        struct xfs_btree_cur    *cur,
        union xfs_btree_ptr     *start,
        union xfs_btree_ptr     *new,
-       int                     length,
        int                     *stat)
 {
        xfs_alloc_arg_t         args;           /* block allocation args */
@@ -173,6 +188,17 @@ xfs_inobt_init_ptr_from_cur(
        ptr->s = agi->agi_root;
 }
 
+STATIC void
+xfs_finobt_init_ptr_from_cur(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr)
+{
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
+
+       ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
+       ptr->s = agi->agi_free_root;
+}
+
 STATIC __int64_t
 xfs_inobt_key_diff(
        struct xfs_btree_cur    *cur,
@@ -203,6 +229,7 @@ xfs_inobt_verify(
         */
        switch (block->bb_magic) {
        case cpu_to_be32(XFS_IBT_CRC_MAGIC):
+       case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
                if (!xfs_sb_version_hascrc(&mp->m_sb))
                        return false;
                if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
@@ -214,6 +241,7 @@ xfs_inobt_verify(
                        return false;
                /* fall through */
        case cpu_to_be32(XFS_IBT_MAGIC):
+       case cpu_to_be32(XFS_FIBT_MAGIC):
                break;
        default:
                return 0;
@@ -317,6 +345,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
 #endif
 };
 
+static const struct xfs_btree_ops xfs_finobt_ops = {
+       .rec_len                = sizeof(xfs_inobt_rec_t),
+       .key_len                = sizeof(xfs_inobt_key_t),
+
+       .dup_cursor             = xfs_inobt_dup_cursor,
+       .set_root               = xfs_finobt_set_root,
+       .alloc_block            = xfs_inobt_alloc_block,
+       .free_block             = xfs_inobt_free_block,
+       .get_minrecs            = xfs_inobt_get_minrecs,
+       .get_maxrecs            = xfs_inobt_get_maxrecs,
+       .init_key_from_rec      = xfs_inobt_init_key_from_rec,
+       .init_rec_from_key      = xfs_inobt_init_rec_from_key,
+       .init_rec_from_cur      = xfs_inobt_init_rec_from_cur,
+       .init_ptr_from_cur      = xfs_finobt_init_ptr_from_cur,
+       .key_diff               = xfs_inobt_key_diff,
+       .buf_ops                = &xfs_inobt_buf_ops,
+#if defined(DEBUG) || defined(XFS_WARN)
+       .keys_inorder           = xfs_inobt_keys_inorder,
+       .recs_inorder           = xfs_inobt_recs_inorder,
+#endif
+};
+
 /*
  * Allocate a new inode btree cursor.
  */
@@ -325,7 +375,8 @@ xfs_inobt_init_cursor(
        struct xfs_mount        *mp,            /* file system mount point */
        struct xfs_trans        *tp,            /* transaction pointer */
        struct xfs_buf          *agbp,          /* buffer for agi structure */
-       xfs_agnumber_t          agno)           /* allocation group number */
+       xfs_agnumber_t          agno,           /* allocation group number */
+       xfs_btnum_t             btnum)          /* ialloc or free ino btree */
 {
        struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
        struct xfs_btree_cur    *cur;
@@ -334,11 +385,17 @@ xfs_inobt_init_cursor(
 
        cur->bc_tp = tp;
        cur->bc_mp = mp;
-       cur->bc_nlevels = be32_to_cpu(agi->agi_level);
-       cur->bc_btnum = XFS_BTNUM_INO;
+       cur->bc_btnum = btnum;
+       if (btnum == XFS_BTNUM_INO) {
+               cur->bc_nlevels = be32_to_cpu(agi->agi_level);
+               cur->bc_ops = &xfs_inobt_ops;
+       } else {
+               cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
+               cur->bc_ops = &xfs_finobt_ops;
+       }
+
        cur->bc_blocklog = mp->m_sb.sb_blocklog;
 
-       cur->bc_ops = &xfs_inobt_ops;
        if (xfs_sb_version_hascrc(&mp->m_sb))
                cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
 
index f38b22011c4e4604a5e9e74ec9f4afe344dccfdb..d7ebea72c2d0127c588c2e19b5168eebe364ff50 100644 (file)
@@ -58,7 +58,8 @@ struct xfs_mount;
                 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
 
 extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
-               struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t);
+               struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
+               xfs_btnum_t);
 extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
 
 #endif /* __XFS_IALLOC_BTREE_H__ */
index 98d35244eecc936bdb0a9702ae70a9de1d980de8..c48df5f25b9f460e2fd312c9557b69d1db4209a9 100644 (file)
@@ -507,8 +507,7 @@ STATIC int
 xfs_inode_ag_walk(
        struct xfs_mount        *mp,
        struct xfs_perag        *pag,
-       int                     (*execute)(struct xfs_inode *ip,
-                                          struct xfs_perag *pag, int flags,
+       int                     (*execute)(struct xfs_inode *ip, int flags,
                                           void *args),
        int                     flags,
        void                    *args,
@@ -582,7 +581,7 @@ restart:
                for (i = 0; i < nr_found; i++) {
                        if (!batch[i])
                                continue;
-                       error = execute(batch[i], pag, flags, args);
+                       error = execute(batch[i], flags, args);
                        IRELE(batch[i]);
                        if (error == EAGAIN) {
                                skipped++;
@@ -636,8 +635,7 @@ xfs_eofblocks_worker(
 int
 xfs_inode_ag_iterator(
        struct xfs_mount        *mp,
-       int                     (*execute)(struct xfs_inode *ip,
-                                          struct xfs_perag *pag, int flags,
+       int                     (*execute)(struct xfs_inode *ip, int flags,
                                           void *args),
        int                     flags,
        void                    *args)
@@ -664,8 +662,7 @@ xfs_inode_ag_iterator(
 int
 xfs_inode_ag_iterator_tag(
        struct xfs_mount        *mp,
-       int                     (*execute)(struct xfs_inode *ip,
-                                          struct xfs_perag *pag, int flags,
+       int                     (*execute)(struct xfs_inode *ip, int flags,
                                           void *args),
        int                     flags,
        void                    *args,
@@ -1209,7 +1206,6 @@ xfs_inode_match_id(
 STATIC int
 xfs_inode_free_eofblocks(
        struct xfs_inode        *ip,
-       struct xfs_perag        *pag,
        int                     flags,
        void                    *args)
 {
index 9ed68bb750f50871a1ba17a4a67e24a8b4d4829b..9cf017b899be9d531e46d6d7b33a3a110c051cb8 100644 (file)
@@ -60,12 +60,10 @@ int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
 void xfs_eofblocks_worker(struct work_struct *);
 
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
-       int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag,
-               int flags, void *args),
+       int (*execute)(struct xfs_inode *ip, int flags, void *args),
        int flags, void *args);
 int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
-       int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag,
-               int flags, void *args),
+       int (*execute)(struct xfs_inode *ip, int flags, void *args),
        int flags, void *args, int tag);
 
 static inline int
index 768087bedbac58f9dea71b8f534c303e65972b42..6d6b44a508f951071fb3cc5fb46ef40ddb0011d8 100644 (file)
@@ -655,7 +655,6 @@ xfs_ialloc(
        uint            flags;
        int             error;
        timespec_t      tv;
-       int             filestreams = 0;
 
        /*
         * Call the space management code to pick
@@ -772,13 +771,6 @@ xfs_ialloc(
                flags |= XFS_ILOG_DEV;
                break;
        case S_IFREG:
-               /*
-                * we can't set up filestreams until after the VFS inode
-                * is set up properly.
-                */
-               if (pip && xfs_inode_is_filestream(pip))
-                       filestreams = 1;
-               /* fall through */
        case S_IFDIR:
                if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
                        uint    di_flags = 0;
@@ -844,15 +836,6 @@ xfs_ialloc(
        /* now that we have an i_mode we can setup inode ops and unlock */
        xfs_setup_inode(ip);
 
-       /* now we have set up the vfs inode we can associate the filestream */
-       if (filestreams) {
-               error = xfs_filestream_associate(pip, ip);
-               if (error < 0)
-                       return -error;
-               if (!error)
-                       xfs_iflags_set(ip, XFS_IFILESTREAM);
-       }
-
        *ipp = ip;
        return 0;
 }
@@ -1698,16 +1681,6 @@ xfs_release(
        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
@@ -1838,9 +1811,33 @@ xfs_inactive_ifree(
        int                     error;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
+
+       /*
+        * The ifree transaction might need to allocate blocks for record
+        * insertion to the finobt. We don't want to fail here at ENOSPC, so
+        * allow ifree to dip into the reserved block pool if necessary.
+        *
+        * Freeing large sets of inodes generally means freeing inode chunks,
+        * directory and file data blocks, so this should be relatively safe.
+        * Only under severe circumstances should it be possible to free enough
+        * inodes to exhaust the reserve block pool via finobt expansion while
+        * at the same time not creating free space in the filesystem.
+        *
+        * Send a warning if the reservation does happen to fail, as the inode
+        * now remains allocated and sits on the unlinked list until the fs is
+        * repaired.
+        */
+       tp->t_flags |= XFS_TRANS_RESERVE;
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
+                                 XFS_IFREE_SPACE_RES(mp), 0);
        if (error) {
-               ASSERT(XFS_FORCED_SHUTDOWN(mp));
+               if (error == ENOSPC) {
+                       xfs_warn_ratelimited(mp,
+                       "Failed to remove inode(s) from unlinked list. "
+                       "Please free space, unmount and run xfs_repair.");
+               } else {
+                       ASSERT(XFS_FORCED_SHUTDOWN(mp));
+               }
                xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
                return error;
        }
@@ -2664,13 +2661,7 @@ xfs_remove(
        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))
+       if (is_dir && xfs_inode_is_filestream(ip))
                xfs_filestream_deassociate(ip);
 
        return 0;
@@ -3372,9 +3363,9 @@ xfs_iflush_int(
                }
        }
 
-       xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp);
+       xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK);
        if (XFS_IFORK_Q(ip))
-               xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp);
+               xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK);
        xfs_inobp_check(mp, bp);
 
        /*
index f2fcde52b66db98c26286682796e341bca751b33..13aea548206c50dffef65f9d912326ac1e211369 100644 (file)
@@ -209,7 +209,6 @@ xfs_get_initial_prid(struct xfs_inode *dp)
 #define XFS_ISTALE             (1 << 1) /* inode has been staled */
 #define XFS_IRECLAIMABLE       (1 << 2) /* inode can be reclaimed */
 #define XFS_INEW               (1 << 3) /* inode has just been allocated */
-#define XFS_IFILESTREAM                (1 << 4) /* inode is in a filestream dir. */
 #define XFS_ITRUNCATED         (1 << 5) /* truncated down so flush-on-close */
 #define XFS_IDIRTY_RELEASE     (1 << 6) /* dirty release already seen */
 #define __XFS_IFLOCK_BIT       7        /* inode is being flushed right now */
@@ -225,8 +224,7 @@ xfs_get_initial_prid(struct xfs_inode *dp)
  */
 #define XFS_IRECLAIM_RESET_FLAGS       \
        (XFS_IRECLAIMABLE | XFS_IRECLAIM | \
-        XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | \
-        XFS_IFILESTREAM);
+        XFS_IDIRTY_RELEASE | XFS_ITRUNCATED)
 
 /*
  * Synchronize processes attempting to flush the in-core inode back to disk.
index 73514c0486b710fdfcbcc53a2a5683498cf782fc..b031e8d0d9287d096e0742310d66405f829389e7 100644 (file)
@@ -798,8 +798,7 @@ xfs_iflush_fork(
        xfs_inode_t             *ip,
        xfs_dinode_t            *dip,
        xfs_inode_log_item_t    *iip,
-       int                     whichfork,
-       xfs_buf_t               *bp)
+       int                     whichfork)
 {
        char                    *cp;
        xfs_ifork_t             *ifp;
index eb329a1ea8886a3d878489765bc5d13dbbf26068..7d3b1ed6dcbe934dcea8d7b92ccb3342f784bff6 100644 (file)
@@ -127,8 +127,7 @@ typedef struct xfs_ifork {
 
 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 *);
+                               struct xfs_inode_log_item *, int);
 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);
index 3b80ebae05f52eb7d3593b0df92ec834f319948c..6c5eb4c551e3f562e1aba435ceb9a0df438b9e08 100644 (file)
@@ -730,7 +730,7 @@ xfs_iomap_write_allocate(
                         */
                        nimaps = 1;
                        end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
-                       error = xfs_bmap_last_offset(NULL, ip, &last_block,
+                       error = xfs_bmap_last_offset(ip, &last_block,
                                                        XFS_DATA_FORK);
                        if (error)
                                goto trans_cancel;
index f463382851524204edd37f9fd67c7e42efbcf9d9..cb64f222d607438e4b6f8d6bfe4c627e3bda4d22 100644 (file)
@@ -270,7 +270,8 @@ xfs_bulkstat(
                /*
                 * Allocate and initialize a btree cursor for ialloc btree.
                 */
-               cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
+               cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
+                                           XFS_BTNUM_INO);
                irbp = irbuf;
                irbufend = irbuf + nirbuf;
                end_of_ag = 0;
@@ -621,7 +622,8 @@ xfs_inumbers(
                                agino = 0;
                                continue;
                        }
-                       cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
+                       cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
+                                                   XFS_BTNUM_INO);
                        error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
                                                 &tmp);
                        if (error) {
index bce53ac81096afc3e559a7317c149918290bab34..981af0f6504b1e5b5e171ea3ea207e8759913b2c 100644 (file)
@@ -2138,7 +2138,9 @@ xlog_recover_validate_buf_type(
                        bp->b_ops = &xfs_allocbt_buf_ops;
                        break;
                case XFS_IBT_CRC_MAGIC:
+               case XFS_FIBT_CRC_MAGIC:
                case XFS_IBT_MAGIC:
+               case XFS_FIBT_MAGIC:
                        bp->b_ops = &xfs_inobt_buf_ops;
                        break;
                case XFS_BMAP_CRC_MAGIC:
@@ -3145,7 +3147,7 @@ xlog_recover_efd_pass2(
                }
                lip = xfs_trans_ail_cursor_next(ailp, &cur);
        }
-       xfs_trans_ail_cursor_done(ailp, &cur);
+       xfs_trans_ail_cursor_done(&cur);
        spin_unlock(&ailp->xa_lock);
 
        return 0;
@@ -3520,8 +3522,7 @@ out:
 
 STATIC int
 xlog_recover_unmount_trans(
-       struct xlog             *log,
-       struct xlog_recover     *trans)
+       struct xlog             *log)
 {
        /* Do nothing now */
        xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
@@ -3595,7 +3596,7 @@ xlog_recover_process_data(
                                                                trans, pass);
                                break;
                        case XLOG_UNMOUNT_TRANS:
-                               error = xlog_recover_unmount_trans(log, trans);
+                               error = xlog_recover_unmount_trans(log);
                                break;
                        case XLOG_WAS_CONT_TRANS:
                                error = xlog_recover_add_to_cont_trans(log,
@@ -3757,7 +3758,7 @@ xlog_recover_process_efis(
                lip = xfs_trans_ail_cursor_next(ailp, &cur);
        }
 out:
-       xfs_trans_ail_cursor_done(ailp, &cur);
+       xfs_trans_ail_cursor_done(&cur);
        spin_unlock(&ailp->xa_lock);
        return error;
 }
index 4aff56395732591e6d06b8e95d4e6b89ddb59b70..f99b4933dc226267935493cacd0ba103a38cef30 100644 (file)
  * likely result in a loop in one of the lists.  That's a sure-fire recipe for
  * an infinite loop in the code.
  */
-typedef struct xfs_mru_cache_elem
-{
-       struct list_head list_node;
-       unsigned long   key;
-       void            *value;
-} xfs_mru_cache_elem_t;
+struct xfs_mru_cache {
+       struct radix_tree_root  store;     /* Core storage data structure.  */
+       struct list_head        *lists;    /* Array of lists, one per grp.  */
+       struct list_head        reap_list; /* Elements overdue for reaping. */
+       spinlock_t              lock;      /* Lock to protect this struct.  */
+       unsigned int            grp_count; /* Number of discrete groups.    */
+       unsigned int            grp_time;  /* Time period spanned by grps.  */
+       unsigned int            lru_grp;   /* Group containing time zero.   */
+       unsigned long           time_zero; /* Time first element was added. */
+       xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
+       struct delayed_work     work;      /* Workqueue data for reaping.   */
+       unsigned int            queued;    /* work has been queued */
+};
 
-static kmem_zone_t             *xfs_mru_elem_zone;
 static struct workqueue_struct *xfs_mru_reap_wq;
 
 /*
@@ -129,12 +135,12 @@ static struct workqueue_struct    *xfs_mru_reap_wq;
  */
 STATIC unsigned long
 _xfs_mru_cache_migrate(
-       xfs_mru_cache_t *mru,
-       unsigned long   now)
+       struct xfs_mru_cache    *mru,
+       unsigned long           now)
 {
-       unsigned int    grp;
-       unsigned int    migrated = 0;
-       struct list_head *lru_list;
+       unsigned int            grp;
+       unsigned int            migrated = 0;
+       struct list_head        *lru_list;
 
        /* Nothing to do if the data store is empty. */
        if (!mru->time_zero)
@@ -193,11 +199,11 @@ _xfs_mru_cache_migrate(
  */
 STATIC void
 _xfs_mru_cache_list_insert(
-       xfs_mru_cache_t         *mru,
-       xfs_mru_cache_elem_t    *elem)
+       struct xfs_mru_cache    *mru,
+       struct xfs_mru_cache_elem *elem)
 {
-       unsigned int    grp = 0;
-       unsigned long   now = jiffies;
+       unsigned int            grp = 0;
+       unsigned long           now = jiffies;
 
        /*
         * If the data store is empty, initialise time zero, leave grp set to
@@ -231,10 +237,10 @@ _xfs_mru_cache_list_insert(
  */
 STATIC void
 _xfs_mru_cache_clear_reap_list(
-       xfs_mru_cache_t         *mru) __releases(mru->lock) __acquires(mru->lock)
-
+       struct xfs_mru_cache    *mru)
+               __releases(mru->lock) __acquires(mru->lock)
 {
-       xfs_mru_cache_elem_t    *elem, *next;
+       struct xfs_mru_cache_elem *elem, *next;
        struct list_head        tmp;
 
        INIT_LIST_HEAD(&tmp);
@@ -252,15 +258,8 @@ _xfs_mru_cache_clear_reap_list(
        spin_unlock(&mru->lock);
 
        list_for_each_entry_safe(elem, next, &tmp, list_node) {
-
-               /* Remove the element from the reap list. */
                list_del_init(&elem->list_node);
-
-               /* Call the client's free function with the key and value pointer. */
-               mru->free_func(elem->key, elem->value);
-
-               /* Free the element structure. */
-               kmem_zone_free(xfs_mru_elem_zone, elem);
+               mru->free_func(elem);
        }
 
        spin_lock(&mru->lock);
@@ -277,7 +276,8 @@ STATIC void
 _xfs_mru_cache_reap(
        struct work_struct      *work)
 {
-       xfs_mru_cache_t         *mru = container_of(work, xfs_mru_cache_t, work.work);
+       struct xfs_mru_cache    *mru =
+               container_of(work, struct xfs_mru_cache, work.work);
        unsigned long           now, next;
 
        ASSERT(mru && mru->lists);
@@ -304,28 +304,16 @@ _xfs_mru_cache_reap(
 int
 xfs_mru_cache_init(void)
 {
-       xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t),
-                                        "xfs_mru_cache_elem");
-       if (!xfs_mru_elem_zone)
-               goto out;
-
        xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);
        if (!xfs_mru_reap_wq)
-               goto out_destroy_mru_elem_zone;
-
+               return -ENOMEM;
        return 0;
-
- out_destroy_mru_elem_zone:
-       kmem_zone_destroy(xfs_mru_elem_zone);
- out:
-       return -ENOMEM;
 }
 
 void
 xfs_mru_cache_uninit(void)
 {
        destroy_workqueue(xfs_mru_reap_wq);
-       kmem_zone_destroy(xfs_mru_elem_zone);
 }
 
 /*
@@ -336,14 +324,14 @@ xfs_mru_cache_uninit(void)
  */
 int
 xfs_mru_cache_create(
-       xfs_mru_cache_t         **mrup,
+       struct xfs_mru_cache    **mrup,
        unsigned int            lifetime_ms,
        unsigned int            grp_count,
        xfs_mru_cache_free_func_t free_func)
 {
-       xfs_mru_cache_t *mru = NULL;
-       int             err = 0, grp;
-       unsigned int    grp_time;
+       struct xfs_mru_cache    *mru = NULL;
+       int                     err = 0, grp;
+       unsigned int            grp_time;
 
        if (mrup)
                *mrup = NULL;
@@ -400,7 +388,7 @@ exit:
  */
 static void
 xfs_mru_cache_flush(
-       xfs_mru_cache_t         *mru)
+       struct xfs_mru_cache    *mru)
 {
        if (!mru || !mru->lists)
                return;
@@ -420,7 +408,7 @@ xfs_mru_cache_flush(
 
 void
 xfs_mru_cache_destroy(
-       xfs_mru_cache_t         *mru)
+       struct xfs_mru_cache    *mru)
 {
        if (!mru || !mru->lists)
                return;
@@ -438,38 +426,30 @@ xfs_mru_cache_destroy(
  */
 int
 xfs_mru_cache_insert(
-       xfs_mru_cache_t *mru,
-       unsigned long   key,
-       void            *value)
+       struct xfs_mru_cache    *mru,
+       unsigned long           key,
+       struct xfs_mru_cache_elem *elem)
 {
-       xfs_mru_cache_elem_t *elem;
+       int                     error;
 
        ASSERT(mru && mru->lists);
        if (!mru || !mru->lists)
                return EINVAL;
 
-       elem = kmem_zone_zalloc(xfs_mru_elem_zone, KM_SLEEP);
-       if (!elem)
+       if (radix_tree_preload(GFP_KERNEL))
                return ENOMEM;
 
-       if (radix_tree_preload(GFP_KERNEL)) {
-               kmem_zone_free(xfs_mru_elem_zone, elem);
-               return ENOMEM;
-       }
-
        INIT_LIST_HEAD(&elem->list_node);
        elem->key = key;
-       elem->value = value;
 
        spin_lock(&mru->lock);
-
-       radix_tree_insert(&mru->store, key, elem);
+       error = -radix_tree_insert(&mru->store, key, elem);
        radix_tree_preload_end();
-       _xfs_mru_cache_list_insert(mru, elem);
-
+       if (!error)
+               _xfs_mru_cache_list_insert(mru, elem);
        spin_unlock(&mru->lock);
 
-       return 0;
+       return error;
 }
 
 /*
@@ -478,13 +458,12 @@ xfs_mru_cache_insert(
  * the client data pointer for the removed element is returned, otherwise this
  * function will return a NULL pointer.
  */
-void *
+struct xfs_mru_cache_elem *
 xfs_mru_cache_remove(
-       xfs_mru_cache_t *mru,
-       unsigned long   key)
+       struct xfs_mru_cache    *mru,
+       unsigned long           key)
 {
-       xfs_mru_cache_elem_t *elem;
-       void            *value = NULL;
+       struct xfs_mru_cache_elem *elem;
 
        ASSERT(mru && mru->lists);
        if (!mru || !mru->lists)
@@ -492,17 +471,11 @@ xfs_mru_cache_remove(
 
        spin_lock(&mru->lock);
        elem = radix_tree_delete(&mru->store, key);
-       if (elem) {
-               value = elem->value;
+       if (elem)
                list_del(&elem->list_node);
-       }
-
        spin_unlock(&mru->lock);
 
-       if (elem)
-               kmem_zone_free(xfs_mru_elem_zone, elem);
-
-       return value;
+       return elem;
 }
 
 /*
@@ -511,13 +484,14 @@ xfs_mru_cache_remove(
  */
 void
 xfs_mru_cache_delete(
-       xfs_mru_cache_t *mru,
-       unsigned long   key)
+       struct xfs_mru_cache    *mru,
+       unsigned long           key)
 {
-       void            *value = xfs_mru_cache_remove(mru, key);
+       struct xfs_mru_cache_elem *elem;
 
-       if (value)
-               mru->free_func(key, value);
+       elem = xfs_mru_cache_remove(mru, key);
+       if (elem)
+               mru->free_func(elem);
 }
 
 /*
@@ -540,12 +514,12 @@ xfs_mru_cache_delete(
  * status, we need to help it get it right by annotating the path that does
  * not release the lock.
  */
-void *
+struct xfs_mru_cache_elem *
 xfs_mru_cache_lookup(
-       xfs_mru_cache_t *mru,
-       unsigned long   key)
+       struct xfs_mru_cache    *mru,
+       unsigned long           key)
 {
-       xfs_mru_cache_elem_t *elem;
+       struct xfs_mru_cache_elem *elem;
 
        ASSERT(mru && mru->lists);
        if (!mru || !mru->lists)
@@ -560,7 +534,7 @@ xfs_mru_cache_lookup(
        } else
                spin_unlock(&mru->lock);
 
-       return elem ? elem->value : NULL;
+       return elem;
 }
 
 /*
@@ -570,7 +544,8 @@ xfs_mru_cache_lookup(
  */
 void
 xfs_mru_cache_done(
-       xfs_mru_cache_t *mru) __releases(mru->lock)
+       struct xfs_mru_cache    *mru)
+               __releases(mru->lock)
 {
        spin_unlock(&mru->lock);
 }
index 36dd3ec8b4eb17fdbdf83dfd8496e46a1409c30b..fb5245ba5ff744990978b1b69885cc7903698858 100644 (file)
 #ifndef __XFS_MRU_CACHE_H__
 #define __XFS_MRU_CACHE_H__
 
+struct xfs_mru_cache;
 
-/* Function pointer type for callback to free a client's data pointer. */
-typedef void (*xfs_mru_cache_free_func_t)(unsigned long, void*);
+struct xfs_mru_cache_elem {
+       struct list_head list_node;
+       unsigned long   key;
+};
 
-typedef struct xfs_mru_cache
-{
-       struct radix_tree_root  store;     /* Core storage data structure.  */
-       struct list_head        *lists;    /* Array of lists, one per grp.  */
-       struct list_head        reap_list; /* Elements overdue for reaping. */
-       spinlock_t              lock;      /* Lock to protect this struct.  */
-       unsigned int            grp_count; /* Number of discrete groups.    */
-       unsigned int            grp_time;  /* Time period spanned by grps.  */
-       unsigned int            lru_grp;   /* Group containing time zero.   */
-       unsigned long           time_zero; /* Time first element was added. */
-       xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
-       struct delayed_work     work;      /* Workqueue data for reaping.   */
-       unsigned int            queued;    /* work has been queued */
-} xfs_mru_cache_t;
+/* Function pointer type for callback to free a client's data pointer. */
+typedef void (*xfs_mru_cache_free_func_t)(struct xfs_mru_cache_elem *elem);
 
 int xfs_mru_cache_init(void);
 void xfs_mru_cache_uninit(void);
@@ -44,10 +35,12 @@ int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
                             xfs_mru_cache_free_func_t free_func);
 void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
 int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
-                               void *value);
-void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
+               struct xfs_mru_cache_elem *elem);
+struct xfs_mru_cache_elem *
+xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
 void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key);
-void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
+struct xfs_mru_cache_elem *
+xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
 void xfs_mru_cache_done(struct xfs_mru_cache *mru);
 
 #endif /* __XFS_MRU_CACHE_H__ */
index 348e4d2ed6e6e9621b82c535212e32093b51da0c..23cc8dce477d44c3c87bf55803798795fefb5b4a 100644 (file)
@@ -870,8 +870,7 @@ xfs_qm_init_quotainfo(
 
        /* Precalc some constants */
        qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
-       qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(mp,
-                                                       qinf->qi_dqchunklen);
+       qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
 
        mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
index 3daf5ea1eb8d73989a4e199aaee4dd2364a98290..72cbe65e5e75ed05b97f9aeab294d394713dc9da 100644 (file)
@@ -959,7 +959,6 @@ xfs_qm_export_flags(
 STATIC int
 xfs_dqrele_inode(
        struct xfs_inode        *ip,
-       struct xfs_perag        *pag,
        int                     flags,
        void                    *args)
 {
index b3b2b1065c0f4db8a6c972880b2dc8601e189e03..137e20937077a0923d7095b02094172e4992ec55 100644 (file)
@@ -156,6 +156,6 @@ typedef __uint16_t  xfs_qwarncnt_t;
 
 extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq,
                       xfs_dqid_t id, uint type, uint flags, char *str);
-extern int xfs_calc_dquots_per_chunk(struct xfs_mount *mp, unsigned int nbblks);
+extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
 
 #endif /* __XFS_QUOTA_H__ */
index f7b2fe77c5a5bf095a8b01e793fda242c2968cc4..950d1ea058b23653f3940f3a0fbdf259888d64df 100644 (file)
@@ -587,7 +587,9 @@ xfs_sb_has_compat_feature(
        return (sbp->sb_features_compat & feature) != 0;
 }
 
-#define XFS_SB_FEAT_RO_COMPAT_ALL 0
+#define XFS_SB_FEAT_RO_COMPAT_FINOBT   (1 << 0)                /* free inode btree */
+#define XFS_SB_FEAT_RO_COMPAT_ALL \
+               (XFS_SB_FEAT_RO_COMPAT_FINOBT)
 #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN  ~XFS_SB_FEAT_RO_COMPAT_ALL
 static inline bool
 xfs_sb_has_ro_compat_feature(
@@ -641,6 +643,12 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp)
                 (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE));
 }
 
+static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
+{
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+               (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT);
+}
+
 /*
  * end of superblock version macros
  */
index 4484e515139507fe9e69912da6eb9df6c50e7402..82404da2ca6747c010a4c666132ebede1c9c7f90 100644 (file)
@@ -238,7 +238,7 @@ int xfs_log_calc_minimum_size(struct xfs_mount *);
 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,
+bool xfs_symlink_hdr_ok(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);
index ce372b7d5644600ec6e52a23f8ec00584e1f2e9c..f2240383d4bba79b75f78f7d45803c76728457c5 100644 (file)
@@ -59,6 +59,7 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v)
                { "abtc2",              XFSSTAT_END_ABTC_V2             },
                { "bmbt2",              XFSSTAT_END_BMBT_V2             },
                { "ibt2",               XFSSTAT_END_IBT_V2              },
+               { "fibt2",              XFSSTAT_END_FIBT_V2             },
                /* we print both series of quota information together */
                { "qm",                 XFSSTAT_END_QM                  },
        };
index c03ad38ceaebaeb8b82a2e0fae785cc592e9adaf..c8f238b8299a1bc96ce11ff0c20b9be1bb0044a9 100644 (file)
@@ -183,7 +183,23 @@ struct xfsstats {
        __uint32_t              xs_ibt_2_alloc;
        __uint32_t              xs_ibt_2_free;
        __uint32_t              xs_ibt_2_moves;
-#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_IBT_V2+6)
+#define XFSSTAT_END_FIBT_V2            (XFSSTAT_END_IBT_V2+15)
+       __uint32_t              xs_fibt_2_lookup;
+       __uint32_t              xs_fibt_2_compare;
+       __uint32_t              xs_fibt_2_insrec;
+       __uint32_t              xs_fibt_2_delrec;
+       __uint32_t              xs_fibt_2_newroot;
+       __uint32_t              xs_fibt_2_killroot;
+       __uint32_t              xs_fibt_2_increment;
+       __uint32_t              xs_fibt_2_decrement;
+       __uint32_t              xs_fibt_2_lshift;
+       __uint32_t              xs_fibt_2_rshift;
+       __uint32_t              xs_fibt_2_split;
+       __uint32_t              xs_fibt_2_join;
+       __uint32_t              xs_fibt_2_alloc;
+       __uint32_t              xs_fibt_2_free;
+       __uint32_t              xs_fibt_2_moves;
+#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_FIBT_V2+6)
        __uint32_t              xs_qm_dqreclaims;
        __uint32_t              xs_qm_dqreclaim_misses;
        __uint32_t              xs_qm_dquot_dups;
index 2053767763773b60d7b7f8aca31f3b31a9219785..ac24372a607f607dce7fc539ed10f4cff3a2d2ce 100644 (file)
@@ -765,20 +765,18 @@ xfs_open_devices(
         * Setup xfs_mount buffer target pointers
         */
        error = ENOMEM;
-       mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev, 0, mp->m_fsname);
+       mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev);
        if (!mp->m_ddev_targp)
                goto out_close_rtdev;
 
        if (rtdev) {
-               mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev, 1,
-                                                       mp->m_fsname);
+               mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev);
                if (!mp->m_rtdev_targp)
                        goto out_free_ddev_targ;
        }
 
        if (logdev && logdev != ddev) {
-               mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev, 1,
-                                                       mp->m_fsname);
+               mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev);
                if (!mp->m_logdev_targp)
                        goto out_free_rtdev_targ;
        } else {
@@ -811,8 +809,7 @@ xfs_setup_devices(
 {
        int                     error;
 
-       error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize,
-                                   mp->m_sb.sb_sectsize);
+       error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize);
        if (error)
                return error;
 
@@ -822,14 +819,12 @@ xfs_setup_devices(
                if (xfs_sb_version_hassector(&mp->m_sb))
                        log_sector_size = mp->m_sb.sb_logsectsize;
                error = xfs_setsize_buftarg(mp->m_logdev_targp,
-                                           mp->m_sb.sb_blocksize,
                                            log_sector_size);
                if (error)
                        return error;
        }
        if (mp->m_rtdev_targp) {
                error = xfs_setsize_buftarg(mp->m_rtdev_targp,
-                                           mp->m_sb.sb_blocksize,
                                            mp->m_sb.sb_sectsize);
                if (error)
                        return error;
@@ -1754,13 +1749,9 @@ init_xfs_fs(void)
        if (error)
                goto out_destroy_wq;
 
-       error = xfs_filestream_init();
-       if (error)
-               goto out_mru_cache_uninit;
-
        error = xfs_buf_init();
        if (error)
-               goto out_filestream_uninit;
+               goto out_mru_cache_uninit;
 
        error = xfs_init_procfs();
        if (error)
@@ -1787,8 +1778,6 @@ init_xfs_fs(void)
        xfs_cleanup_procfs();
  out_buf_terminate:
        xfs_buf_terminate();
- out_filestream_uninit:
-       xfs_filestream_uninit();
  out_mru_cache_uninit:
        xfs_mru_cache_uninit();
  out_destroy_wq:
@@ -1807,7 +1796,6 @@ exit_xfs_fs(void)
        xfs_sysctl_unregister();
        xfs_cleanup_procfs();
        xfs_buf_terminate();
-       xfs_filestream_uninit();
        xfs_mru_cache_uninit();
        xfs_destroy_workqueues();
        xfs_destroy_zones();
index 52979aa90986ca3a1a6caada967a460567245265..0816b4018dfcd73ae5fdabafe5f9dc4bfaef44f3 100644 (file)
@@ -92,7 +92,7 @@ xfs_readlink_bmap(
 
                cur_chunk = bp->b_addr;
                if (xfs_sb_version_hascrc(&mp->m_sb)) {
-                       if (!xfs_symlink_hdr_ok(mp, ip->i_ino, offset,
+                       if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
                                                        byte_cnt, bp)) {
                                error = EFSCORRUPTED;
                                xfs_alert(mp,
index 9b32052ff65e771c55814afa8dcb26a8d2f0e42c..23c2f2577c8d75fdd85660cb0aac0524318cd384 100644 (file)
@@ -80,7 +80,6 @@ xfs_symlink_hdr_set(
  */
 bool
 xfs_symlink_hdr_ok(
-       struct xfs_mount        *mp,
        xfs_ino_t               ino,
        uint32_t                offset,
        uint32_t                size,
index dee3279c095e6a32dcf460ca58acda0aa924bb2d..1e85bcd0e418629871bb2bd37d869447212c7dbf 100644 (file)
@@ -46,6 +46,7 @@
 #include "xfs_log_recover.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap_btree.h"
+#include "xfs_filestream.h"
 
 /*
  * We include this last to have the helpers above available for the trace
index 65d8c793a25cb10c5ded9bfb89fcfda725c58b5f..152f82782630222321bcd234b20c0ffb0a626e34 100644 (file)
@@ -538,6 +538,64 @@ DEFINE_BUF_ITEM_EVENT(xfs_trans_bhold_release);
 DEFINE_BUF_ITEM_EVENT(xfs_trans_binval);
 DEFINE_BUF_ITEM_EVENT(xfs_trans_buf_ordered);
 
+DECLARE_EVENT_CLASS(xfs_filestream_class,
+       TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno),
+       TP_ARGS(ip, agno),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_ino_t, ino)
+               __field(xfs_agnumber_t, agno)
+               __field(int, streams)
+       ),
+       TP_fast_assign(
+               __entry->dev = VFS_I(ip)->i_sb->s_dev;
+               __entry->ino = ip->i_ino;
+               __entry->agno = agno;
+               __entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno);
+       ),
+       TP_printk("dev %d:%d ino 0x%llx agno %u streams %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->ino,
+                 __entry->agno,
+                 __entry->streams)
+)
+#define DEFINE_FILESTREAM_EVENT(name) \
+DEFINE_EVENT(xfs_filestream_class, name, \
+       TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno), \
+       TP_ARGS(ip, agno))
+DEFINE_FILESTREAM_EVENT(xfs_filestream_free);
+DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup);
+DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
+
+TRACE_EVENT(xfs_filestream_pick,
+       TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno,
+                xfs_extlen_t free, int nscan),
+       TP_ARGS(ip, agno, free, nscan),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_ino_t, ino)
+               __field(xfs_agnumber_t, agno)
+               __field(int, streams)
+               __field(xfs_extlen_t, free)
+               __field(int, nscan)
+       ),
+       TP_fast_assign(
+               __entry->dev = VFS_I(ip)->i_sb->s_dev;
+               __entry->ino = ip->i_ino;
+               __entry->agno = agno;
+               __entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno);
+               __entry->free = free;
+               __entry->nscan = nscan;
+       ),
+       TP_printk("dev %d:%d ino 0x%llx agno %u streams %d free %d nscan %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->ino,
+                 __entry->agno,
+                 __entry->streams,
+                 __entry->free,
+                 __entry->nscan)
+);
+
 DECLARE_EVENT_CLASS(xfs_lock_class,
        TP_PROTO(struct xfs_inode *ip, unsigned lock_flags,
                 unsigned long caller_ip),
@@ -1060,7 +1118,6 @@ DEFINE_RW_EVENT(xfs_file_read);
 DEFINE_RW_EVENT(xfs_file_buffered_write);
 DEFINE_RW_EVENT(xfs_file_direct_write);
 DEFINE_RW_EVENT(xfs_file_splice_read);
-DEFINE_RW_EVENT(xfs_file_splice_write);
 
 DECLARE_EVENT_CLASS(xfs_page_class,
        TP_PROTO(struct inode *inode, struct page *page, unsigned long off,
index 54a57326d85b1e7b2fc84b5761773453a6c02eaf..d03932564ccb3a3e75efc3e39b3991ba6f27d8c9 100644 (file)
@@ -827,7 +827,7 @@ xfs_trans_committed_bulk(
                xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn);
 
        spin_lock(&ailp->xa_lock);
-       xfs_trans_ail_cursor_done(ailp, &cur);
+       xfs_trans_ail_cursor_done(&cur);
        spin_unlock(&ailp->xa_lock);
 }
 
index a7287354e53534b06e1816b189633d063f9e1548..cb0f3a84cc68452155b36c6b4a754edd450aa619 100644 (file)
@@ -173,7 +173,6 @@ xfs_trans_ail_cursor_next(
  */
 void
 xfs_trans_ail_cursor_done(
-       struct xfs_ail          *ailp,
        struct xfs_ail_cursor   *cur)
 {
        cur->item = NULL;
@@ -368,7 +367,7 @@ xfsaild_push(
                 * If the AIL is empty or our push has reached the end we are
                 * done now.
                 */
-               xfs_trans_ail_cursor_done(ailp, &cur);
+               xfs_trans_ail_cursor_done(&cur);
                spin_unlock(&ailp->xa_lock);
                goto out_done;
        }
@@ -453,7 +452,7 @@ xfsaild_push(
                        break;
                lsn = lip->li_lsn;
        }
-       xfs_trans_ail_cursor_done(ailp, &cur);
+       xfs_trans_ail_cursor_done(&cur);
        spin_unlock(&ailp->xa_lock);
 
        if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list))
index 12e86af9d9b94327ea13384fe4a6c2018bf84e1d..bd1281862ad795c8a4b4536d377341403b388c65 100644 (file)
@@ -133,8 +133,7 @@ struct xfs_log_item *       xfs_trans_ail_cursor_last(struct xfs_ail *ailp,
                                        xfs_lsn_t lsn);
 struct xfs_log_item *  xfs_trans_ail_cursor_next(struct xfs_ail *ailp,
                                        struct xfs_ail_cursor *cur);
-void                   xfs_trans_ail_cursor_done(struct xfs_ail *ailp,
-                                       struct xfs_ail_cursor *cur);
+void                   xfs_trans_ail_cursor_done(struct xfs_ail_cursor *cur);
 
 #if BITS_PER_LONG != 64
 static inline void
index ae368165244d49458bd4db2cc4688d196f2e2098..52b6c3e3203e167200750e7766870692dbb7d2bc 100644 (file)
@@ -105,6 +105,47 @@ xfs_calc_inode_res(
                 2 * XFS_BMBT_BLOCK_LEN(mp));
 }
 
+/*
+ * The free inode btree is a conditional feature and the log reservation
+ * requirements differ slightly from that of the traditional inode allocation
+ * btree. The finobt tracks records for inode chunks with at least one free
+ * inode. A record can be removed from the tree for an inode allocation
+ * or free and thus the finobt reservation is unconditional across:
+ *
+ *     - inode allocation
+ *     - inode free
+ *     - inode chunk allocation
+ *
+ * The 'modify' param indicates to include the record modification scenario. The
+ * 'alloc' param indicates to include the reservation for free space btree
+ * modifications on behalf of finobt modifications. This is required only for
+ * transactions that do not already account for free space btree modifications.
+ *
+ * the free inode btree: max depth * block size
+ * the allocation btrees: 2 trees * (max depth - 1) * block size
+ * the free inode btree entry: block size
+ */
+STATIC uint
+xfs_calc_finobt_res(
+       struct xfs_mount        *mp,
+       int                     alloc,
+       int                     modify)
+{
+       uint res;
+
+       if (!xfs_sb_version_hasfinobt(&mp->m_sb))
+               return 0;
+
+       res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
+       if (alloc)
+               res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), 
+                                       XFS_FSB_TO_B(mp, 1));
+       if (modify)
+               res += (uint)XFS_FSB_TO_B(mp, 1);
+
+       return res;
+}
+
 /*
  * Various log reservation values.
  *
@@ -302,6 +343,7 @@ xfs_calc_remove_reservation(
  *    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
+ *    the finobt (record modification and allocation btrees)
  */
 STATIC uint
 xfs_calc_create_resv_modify(
@@ -310,7 +352,8 @@ xfs_calc_create_resv_modify(
        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));
+               xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_finobt_res(mp, 1, 1);
 }
 
 /*
@@ -348,6 +391,7 @@ __xfs_calc_create_reservation(
  *    the superblock for the nlink flag: sector size
  *    the inode btree: max depth * blocksize
  *    the allocation btrees: 2 trees * (max depth - 1) * block size
+ *    the finobt (record insertion)
  */
 STATIC uint
 xfs_calc_icreate_resv_alloc(
@@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc(
                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));
+                                XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_finobt_res(mp, 0, 0);
 }
 
 STATIC uint
@@ -425,6 +470,7 @@ xfs_calc_symlink_reservation(
  *    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
+ *    the finobt (record insertion, removal or modification)
  */
 STATIC uint
 xfs_calc_ifree_reservation(
@@ -439,7 +485,8 @@ xfs_calc_ifree_reservation(
                xfs_calc_buf_res(2 + mp->m_ialloc_blks +
                                 mp->m_in_maxlevels, 0) +
                xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
+                                XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_finobt_res(mp, 0, 1);
 }
 
 /*
index af5dbe06cb65886482c522269107853bec4249fb..df4c1f81884cbd4583598c450942feaf414bdd2d 100644 (file)
@@ -47,7 +47,9 @@
 #define        XFS_DIRREMOVE_SPACE_RES(mp)     \
        XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
 #define        XFS_IALLOC_SPACE_RES(mp)        \
-       ((mp)->m_ialloc_blks + (mp)->m_in_maxlevels - 1)
+       ((mp)->m_ialloc_blks + \
+        (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
+         ((mp)->m_in_maxlevels - 1)))
 
 /*
  * Space reservation values for various transactions.
@@ -82,5 +84,8 @@
        (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
 #define        XFS_SYMLINK_SPACE_RES(mp,nl,b)  \
        (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
+#define XFS_IFREE_SPACE_RES(mp)                \
+       (xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
+
 
 #endif /* __XFS_TRANS_SPACE_H__ */
index 82bbc34d54a3b344559379a665365bb2bab9b903..65c6e6650b1a5e86f586d7bbbc7b352758dd842b 100644 (file)
@@ -134,7 +134,7 @@ typedef enum {
 
 typedef enum {
        XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
-       XFS_BTNUM_MAX
+       XFS_BTNUM_FINOi, XFS_BTNUM_MAX
 } xfs_btnum_t;
 
 struct xfs_name {
index 44f5e97496015092e07314c56c5f8933a2aac8da..913d0765adbea055a53fe3582d3fb3d90d6a1156 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20140214
+#define ACPI_CA_VERSION                 0x20140325
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -75,7 +75,7 @@ extern u8 acpi_gbl_auto_serialize_methods;
 extern u8 acpi_gbl_copy_dsdt_locally;
 extern u8 acpi_gbl_create_osi_method;
 extern u8 acpi_gbl_disable_auto_repair;
-extern u8 acpi_gbl_disable_ssdt_table_load;
+extern u8 acpi_gbl_disable_ssdt_table_install;
 extern u8 acpi_gbl_do_not_use_xsdt;
 extern u8 acpi_gbl_enable_aml_debug_object;
 extern u8 acpi_gbl_enable_interpreter_slack;
@@ -164,6 +164,9 @@ acpi_decode_pld_buffer(u8 *in_buffer,
 /*
  * ACPI table load/unload interfaces
  */
+acpi_status __init
+acpi_install_table(acpi_physical_address address, u8 physical);
+
 acpi_status acpi_load_table(struct acpi_table_header *table);
 
 acpi_status acpi_unload_parent_table(acpi_handle object);
index 3b30e36b53b509d92fc5c00f88bb7c07c5a4f3cc..1cc7ef13c01a661334f924dd6b546e20cf0d0fb6 100644 (file)
@@ -367,12 +367,11 @@ struct acpi_table_desc {
 
 /* Masks for Flags field above */
 
-#define ACPI_TABLE_ORIGIN_UNKNOWN       (0)
-#define ACPI_TABLE_ORIGIN_MAPPED        (1)
-#define ACPI_TABLE_ORIGIN_ALLOCATED     (2)
-#define ACPI_TABLE_ORIGIN_OVERRIDE      (4)
-#define ACPI_TABLE_ORIGIN_MASK          (7)
-#define ACPI_TABLE_IS_LOADED            (8)
+#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL  (0)        /* Virtual address, external maintained */
+#define ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL (1)        /* Physical address, internally mapped */
+#define ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL  (2)        /* Virtual address, internallly allocated */
+#define ACPI_TABLE_ORIGIN_MASK              (3)
+#define ACPI_TABLE_IS_LOADED                (8)
 
 /*
  * Get the remaining ACPI tables
index a476b9118b49bbe064def5eb5897ffb1e1b5c3d1..384875da37137be7f24c9c1474d7cbe60dc0e318 100644 (file)
  */
 #define ACPI_UNUSED_VAR __attribute__ ((unused))
 
+/*
+ * Some versions of gcc implement strchr() with a buggy macro. So,
+ * undef it here. Prevents error messages of this form (usually from the
+ * file getopt.c):
+ *
+ * error: logical '&&' with non-zero constant will always evaluate as true
+ */
+#ifdef strchr
+#undef strchr
+#endif
+
 #endif                         /* __ACGCC_H__ */
index 93c55ed7c53d88ec500123d361987478d975d11e..f2429094b9b9e062a8c33765140417ae95ecaa62 100644 (file)
@@ -91,7 +91,7 @@
 #include <ctype.h>
 #include <unistd.h>
 
-/* Disable kernel specific declarators */
+/* Define/disable kernel-specific declarators */
 
 #ifndef __init
 #define __init
 #define ACPI_FLUSH_CPU_CACHE()
 #define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread))
 
-#if defined(__ia64__) || defined(__x86_64__) || defined(__aarch64__)
+#if defined(__ia64__)    || defined(__x86_64__) ||\
+       defined(__aarch64__) || defined(__PPC64__)
 #define ACPI_MACHINE_WIDTH          64
 #define COMPILER_DEPENDENT_INT64    long
 #define COMPILER_DEPENDENT_UINT64   unsigned long
index 5a64ca4621f3f650e3c6718137a8ea549198d171..f23174fb9ec4340378df59b5cc89b43ecf342bec 100644 (file)
@@ -93,5 +93,8 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
 #define set_fixmap_io(idx, phys) \
        __set_fixmap(idx, phys, FIXMAP_PAGE_IO)
 
+#define set_fixmap_offset_io(idx, phys) \
+       __set_fixmap_offset(idx, phys, FIXMAP_PAGE_IO)
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_GENERIC_FIXMAP_H */
index d96deb443f18403d50e813f7a82a478e92a6d064..94f9ea8abcae35af8ca36560403fbd25facb7c65 100644 (file)
@@ -50,7 +50,7 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
 }
 
 #ifndef zero_bytemask
-#define zero_bytemask(mask) (~0ul << __fls(mask) << 1)
+#define zero_bytemask(mask) (~1ul << __fls(mask))
 #endif
 
 #endif /* _ASM_WORD_AT_A_TIME_H */
index a7c2a862b4f48ab286f20b3860ea8eeb442bd1a9..12f10bc2395f9abcb931938b0915bfac211c7bc2 100644 (file)
@@ -143,11 +143,6 @@ int drm_err(const char *func, const char *format, ...);
 #define DRIVER_PRIME       0x4000
 #define DRIVER_RENDER      0x8000
 
-#define DRIVER_BUS_PCI 0x1
-#define DRIVER_BUS_PLATFORM 0x2
-#define DRIVER_BUS_USB 0x3
-#define DRIVER_BUS_HOST1X 0x4
-
 /***********************************************************************/
 /** \name Begin the DRM... */
 /*@{*/
@@ -731,13 +726,7 @@ struct drm_master {
 #define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
 
 struct drm_bus {
-       int bus_type;
-       int (*get_irq)(struct drm_device *dev);
-       const char *(*get_name)(struct drm_device *dev);
        int (*set_busid)(struct drm_device *dev, struct drm_master *master);
-       int (*set_unique)(struct drm_device *dev, struct drm_master *master,
-                         struct drm_unique *unique);
-       int (*irq_by_busid)(struct drm_device *dev, struct drm_irq_busid *p);
 };
 
 /**
@@ -974,11 +963,6 @@ struct drm_driver {
        const struct drm_ioctl_desc *ioctls;
        int num_ioctls;
        const struct file_operations *fops;
-       union {
-               struct pci_driver *pci;
-               struct platform_device *platform_device;
-               struct usb_driver *usb;
-       } kdriver;
        struct drm_bus *bus;
 
        /* List of devices hanging off this driver with stealth attach. */
@@ -1058,7 +1042,6 @@ struct drm_vblank_crtc {
  */
 struct drm_device {
        struct list_head legacy_dev_list;/**< list of devices per driver for stealth attach cleanup */
-       char *devname;                  /**< For /proc/interrupts */
        int if_version;                 /**< Highest interface version set */
 
        /** \name Lifetime Management */
@@ -1076,14 +1059,14 @@ struct drm_device {
 
        /** \name Locks */
        /*@{ */
-       spinlock_t count_lock;          /**< For inuse, drm_device::open_count, drm_device::buf_use */
        struct mutex struct_mutex;      /**< For others */
        struct mutex master_mutex;      /**< For drm_minor::master and drm_file::is_master */
        /*@} */
 
        /** \name Usage Counters */
        /*@{ */
-       int open_count;                 /**< Outstanding files open */
+       int open_count;                 /**< Outstanding files open, protected by drm_global_mutex. */
+       spinlock_t buf_lock;            /**< For drm_device::buf_use and a few other things. */
        int buf_use;                    /**< Buffers in use -- cannot alloc */
        atomic_t buf_alloc;             /**< Buffer allocation in progress */
        /*@} */
@@ -1114,6 +1097,8 @@ struct drm_device {
        /** \name Context support */
        /*@{ */
        bool irq_enabled;               /**< True if irq handler is enabled */
+       int irq;
+
        __volatile__ long context_flag; /**< Context swapping flag */
        int last_context;               /**< Last current context */
        /*@} */
@@ -1186,11 +1171,6 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
        return ((dev->driver->driver_features & feature) ? 1 : 0);
 }
 
-static inline int drm_dev_to_irq(struct drm_device *dev)
-{
-       return dev->driver->bus->get_irq(dev);
-}
-
 static inline void drm_device_set_unplugged(struct drm_device *dev)
 {
        smp_wmb();
@@ -1310,7 +1290,7 @@ extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
 /* Cache management (drm_cache.c) */
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
 void drm_clflush_sg(struct sg_table *st);
-void drm_clflush_virt_range(char *addr, unsigned long length);
+void drm_clflush_virt_range(void *addr, unsigned long length);
 
                                /* Locking IOCTL support (drm_lock.h) */
 extern int drm_lock(struct drm_device *dev, void *data,
@@ -1363,7 +1343,7 @@ extern void drm_core_reclaim_buffers(struct drm_device *dev,
                                /* IRQ support (drm_irq.h) */
 extern int drm_control(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
-extern int drm_irq_install(struct drm_device *dev);
+extern int drm_irq_install(struct drm_device *dev, int irq);
 extern int drm_irq_uninstall(struct drm_device *dev);
 
 extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
@@ -1522,6 +1502,9 @@ extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,
                                       size_t align);
 extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
 extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
+extern int drm_pci_set_unique(struct drm_device *dev,
+                             struct drm_master *master,
+                             struct drm_unique *u);
 
                               /* sysfs support (drm_sysfs.c) */
 struct drm_sysfs_class;
index 36a5febac2a600927d6915642baf62179ff9266c..f51c8393e9a81a68105a60152d5e4323288bc096 100644 (file)
@@ -165,6 +165,10 @@ extern void drm_helper_resume_force_mode(struct drm_device *dev);
 extern int drm_helper_probe_single_connector_modes(struct drm_connector
                                                   *connector, uint32_t maxX,
                                                   uint32_t maxY);
+extern int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector
+                                                          *connector,
+                                                          uint32_t maxX,
+                                                          uint32_t maxY);
 extern void drm_kms_helper_poll_init(struct drm_device *dev);
 extern void drm_kms_helper_poll_fini(struct drm_device *dev);
 extern bool drm_helper_hpd_irq_event(struct drm_device *dev);
index 2dbbf997666937fc3a4efb57519d87ccb85c59cf..91d0582f924e3e90539f0373b4daaaa2b20ae9cb 100644 (file)
@@ -223,7 +223,7 @@ void drm_mode_validate_size(struct drm_device *dev,
 void drm_mode_prune_invalid(struct drm_device *dev,
                            struct list_head *mode_list, bool verbose);
 void drm_mode_sort(struct list_head *mode_list);
-void drm_mode_connector_list_update(struct drm_connector *connector);
+void drm_mode_connector_list_update(struct drm_connector *connector, bool merge_type_bits);
 
 /* parsing cmdline modes */
 bool
index 940ece4934bab0e0c17f491b28da059454967621..24f3cad045db074fb88cfaf52dbd1a91b866b732 100644 (file)
        _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \
        _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */
 
-#define INTEL_BDW_M_IDS(info) \
+#define INTEL_BDW_GT12M_IDS(info) \
        _INTEL_BDW_M_IDS(1, info), \
-       _INTEL_BDW_M_IDS(2, info), \
-       _INTEL_BDW_M_IDS(3, info)
+       _INTEL_BDW_M_IDS(2, info)
 
-#define INTEL_BDW_D_IDS(info) \
+#define INTEL_BDW_GT12D_IDS(info) \
        _INTEL_BDW_D_IDS(1, info), \
-       _INTEL_BDW_D_IDS(2, info), \
+       _INTEL_BDW_D_IDS(2, info)
+
+#define INTEL_BDW_GT3M_IDS(info) \
+       _INTEL_BDW_M_IDS(3, info)
+
+#define INTEL_BDW_GT3D_IDS(info) \
        _INTEL_BDW_D_IDS(3, info)
 
+#define INTEL_BDW_M_IDS(info) \
+       INTEL_BDW_GT12M_IDS(info), \
+       INTEL_BDW_GT3M_IDS(info)
+
+#define INTEL_BDW_D_IDS(info) \
+       INTEL_BDW_GT12D_IDS(info), \
+       INTEL_BDW_GT3D_IDS(info)
+
 #endif /* _I915_PCIIDS_H */
index 6548a5fbcf4a4854ec3afec3c8d1be5cf19952a1..1118f7a4bca611ee6e46d7d4d3f356f65822658a 100644 (file)
@@ -33,8 +33,8 @@
 #define R8A7790_CLK_TMU0               25
 #define R8A7790_CLK_VSP1_DU1           27
 #define R8A7790_CLK_VSP1_DU0           28
-#define R8A7790_CLK_VSP1_RT            30
-#define R8A7790_CLK_VSP1_SY            31
+#define R8A7790_CLK_VSP1_R             30
+#define R8A7790_CLK_VSP1_S             31
 
 /* MSTP2 */
 #define R8A7790_CLK_SCIFA2             2
@@ -50,6 +50,7 @@
 #define R8A7790_CLK_SYS_DMAC0          19
 
 /* MSTP3 */
+#define R8A7790_CLK_IIC2               0
 #define R8A7790_CLK_TPU0               4
 #define R8A7790_CLK_MMCIF1             5
 #define R8A7790_CLK_SDHI3              11
@@ -57,6 +58,8 @@
 #define R8A7790_CLK_SDHI1              13
 #define R8A7790_CLK_SDHI0              14
 #define R8A7790_CLK_MMCIF0             15
+#define R8A7790_CLK_IIC0               18
+#define R8A7790_CLK_IIC1               23
 #define R8A7790_CLK_SSUSB              28
 #define R8A7790_CLK_CMT1               29
 #define R8A7790_CLK_USBDMAC0           30
index 30f82f286e295df3423dd6729ef48918c80683c2..29b0f3355ffb345d3004b1f0110beb313ef55280 100644 (file)
@@ -32,7 +32,7 @@
 #define R8A7791_CLK_TMU0               25
 #define R8A7791_CLK_VSP1_DU1           27
 #define R8A7791_CLK_VSP1_DU0           28
-#define R8A7791_CLK_VSP1_SY            31
+#define R8A7791_CLK_VSP1_S             31
 
 /* MSTP2 */
 #define R8A7791_CLK_SCIFA2             2
@@ -51,6 +51,8 @@
 #define R8A7791_CLK_SDHI1              12
 #define R8A7791_CLK_SDHI0              14
 #define R8A7791_CLK_MMCIF0             15
+#define R8A7791_CLK_IIC0               18
+#define R8A7791_CLK_IIC1               23
 #define R8A7791_CLK_SSUSB              28
 #define R8A7791_CLK_CMT1               29
 #define R8A7791_CLK_USBDMAC0           30
@@ -61,6 +63,7 @@
 #define R8A7791_CLK_PWM                        23
 
 /* MSTP7 */
+#define R8A7791_CLK_EHCI               3
 #define R8A7791_CLK_HSUSB              4
 #define R8A7791_CLK_HSCIF2             13
 #define R8A7791_CLK_SCIF5              14
diff --git a/include/dt-bindings/clock/s3c2412.h b/include/dt-bindings/clock/s3c2412.h
new file mode 100644 (file)
index 0000000..aac1dcf
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Device Tree binding constants clock controllers of Samsung S3C2412.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H
+#define _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_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. */
+
+/* id 1 is reserved */
+#define MPLL                   2
+#define UPLL                   3
+#define MDIVCLK                        4
+#define MSYSCLK                        5
+#define USYSCLK                        6
+#define HCLK                   7
+#define PCLK                   8
+#define ARMDIV                 9
+#define ARMCLK                 10
+
+
+/* Special clocks */
+#define SCLK_CAM               16
+#define SCLK_UART              17
+#define SCLK_I2S               18
+#define SCLK_USBD              19
+#define SCLK_USBH              20
+
+/* pclk-gates */
+#define PCLK_WDT               32
+#define PCLK_SPI               33
+#define PCLK_I2S               34
+#define PCLK_I2C               35
+#define PCLK_ADC               36
+#define PCLK_RTC               37
+#define PCLK_GPIO              38
+#define PCLK_UART2             39
+#define PCLK_UART1             40
+#define PCLK_UART0             41
+#define PCLK_SDI               42
+#define PCLK_PWM               43
+#define PCLK_USBD              44
+
+/* hclk-gates */
+#define HCLK_HALF              48
+#define HCLK_X2                        49
+#define HCLK_SDRAM             50
+#define HCLK_USBH              51
+#define HCLK_LCD               52
+#define HCLK_NAND              53
+#define HCLK_DMA3              54
+#define HCLK_DMA2              55
+#define HCLK_DMA1              56
+#define HCLK_DMA0              57
+
+/* Total number of clocks. */
+#define NR_CLKS                        (HCLK_DMA0 + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H */
diff --git a/include/dt-bindings/clock/s3c2443.h b/include/dt-bindings/clock/s3c2443.h
new file mode 100644 (file)
index 0000000..37e66b0
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Device Tree binding constants clock controllers of Samsung S3C2443 and later.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_CLOCK_H
+#define _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_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 MSYSCLK                        1
+#define ESYSCLK                        2
+#define ARMDIV                 3
+#define ARMCLK                 4
+#define HCLK                   5
+#define PCLK                   6
+
+/* Special clocks */
+#define SCLK_HSSPI0            16
+#define SCLK_FIMD              17
+#define SCLK_I2S0              18
+#define SCLK_I2S1              19
+#define SCLK_HSMMC1            20
+#define SCLK_HSMMC_EXT         21
+#define SCLK_CAM               22
+#define SCLK_UART              23
+#define SCLK_USBH              24
+
+/* Muxes */
+#define MUX_HSSPI0             32
+#define MUX_HSSPI1             33
+#define MUX_HSMMC0             34
+#define MUX_HSMMC1             35
+
+/* hclk-gates */
+#define HCLK_DMA0              48
+#define HCLK_DMA1              49
+#define HCLK_DMA2              50
+#define HCLK_DMA3              51
+#define HCLK_DMA4              52
+#define HCLK_DMA5              53
+#define HCLK_DMA6              54
+#define HCLK_DMA7              55
+#define HCLK_CAM               56
+#define HCLK_LCD               57
+#define HCLK_USBH              58
+#define HCLK_USBD              59
+#define HCLK_IROM              60
+#define HCLK_HSMMC0            61
+#define HCLK_HSMMC1            62
+#define HCLK_CFC               63
+#define HCLK_SSMC              64
+#define HCLK_DRAM              65
+#define HCLK_2D                        66
+
+/* pclk-gates */
+#define PCLK_UART0             72
+#define PCLK_UART1             73
+#define PCLK_UART2             74
+#define PCLK_UART3             75
+#define PCLK_I2C0              76
+#define PCLK_SDI               77
+#define PCLK_SPI0              78
+#define PCLK_ADC               79
+#define PCLK_AC97              80
+#define PCLK_I2S0              81
+#define PCLK_PWM               82
+#define PCLK_WDT               83
+#define PCLK_RTC               84
+#define PCLK_GPIO              85
+#define PCLK_SPI1              86
+#define PCLK_CHIPID            87
+#define PCLK_I2C1              88
+#define PCLK_I2S1              89
+#define PCLK_PCM               90
+
+/* Total number of clocks. */
+#define NR_CLKS                        (PCLK_PCM + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_CLOCK_H */
diff --git a/include/linux/amba/xilinx_dma.h b/include/linux/amba/xilinx_dma.h
new file mode 100644 (file)
index 0000000..34b98f2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Xilinx DMA Engine drivers support header file
+ *
+ * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DMA_XILINX_DMA_H
+#define __DMA_XILINX_DMA_H
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+
+/**
+ * struct xilinx_vdma_config - VDMA Configuration structure
+ * @frm_dly: Frame delay
+ * @gen_lock: Whether in gen-lock mode
+ * @master: Master that it syncs to
+ * @frm_cnt_en: Enable frame count enable
+ * @park: Whether wants to park
+ * @park_frm: Frame to park on
+ * @coalesc: Interrupt coalescing threshold
+ * @delay: Delay counter
+ * @reset: Reset Channel
+ * @ext_fsync: External Frame Sync source
+ */
+struct xilinx_vdma_config {
+       int frm_dly;
+       int gen_lock;
+       int master;
+       int frm_cnt_en;
+       int park;
+       int park_frm;
+       int coalesc;
+       int delay;
+       int reset;
+       int ext_fsync;
+};
+
+int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
+                                       struct xilinx_vdma_config *cfg);
+
+#endif
index bba5508269219a0726ede9f97cc3d22afa97f213..5a645769f020f956415c1fac11ac868a1922f161 100644 (file)
@@ -333,7 +333,7 @@ static inline struct bio *bio_next_split(struct bio *bio, int sectors,
 
 extern struct bio_set *bioset_create(unsigned int, unsigned int);
 extern void bioset_free(struct bio_set *);
-extern mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries);
+extern mempool_t *biovec_create_pool(int pool_entries);
 
 extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *);
 extern void bio_put(struct bio *);
index 0120451545d8d2b85cc5eb10475359442f9d7460..3b561d651a0229326b41b275ab79e46f377e312a 100644 (file)
@@ -18,7 +18,9 @@ struct blk_mq_hw_ctx {
        } ____cacheline_aligned_in_smp;
 
        unsigned long           state;          /* BLK_MQ_S_* flags */
-       struct delayed_work     delayed_work;
+       struct delayed_work     run_work;
+       struct delayed_work     delay_work;
+       cpumask_var_t           cpumask;
 
        unsigned long           flags;          /* BLK_MQ_F_* flags */
 
@@ -32,8 +34,6 @@ struct blk_mq_hw_ctx {
        unsigned int            nr_ctx_map;
        unsigned long           *ctx_map;
 
-       struct request          **rqs;
-       struct list_head        page_list;
        struct blk_mq_tags      *tags;
 
        unsigned long           queued;
@@ -41,7 +41,6 @@ struct blk_mq_hw_ctx {
 #define BLK_MQ_MAX_DISPATCH_ORDER      10
        unsigned long           dispatched[BLK_MQ_MAX_DISPATCH_ORDER];
 
-       unsigned int            queue_depth;
        unsigned int            numa_node;
        unsigned int            cmd_size;       /* per-request extra data */
 
@@ -49,7 +48,7 @@ struct blk_mq_hw_ctx {
        struct kobject          kobj;
 };
 
-struct blk_mq_reg {
+struct blk_mq_tag_set {
        struct blk_mq_ops       *ops;
        unsigned int            nr_hw_queues;
        unsigned int            queue_depth;
@@ -58,14 +57,22 @@ struct blk_mq_reg {
        int                     numa_node;
        unsigned int            timeout;
        unsigned int            flags;          /* BLK_MQ_F_* */
+       void                    *driver_data;
+
+       struct blk_mq_tags      **tags;
 };
 
 typedef int (queue_rq_fn)(struct blk_mq_hw_ctx *, struct request *);
 typedef struct blk_mq_hw_ctx *(map_queue_fn)(struct request_queue *, const int);
-typedef struct blk_mq_hw_ctx *(alloc_hctx_fn)(struct blk_mq_reg *,unsigned int);
+typedef struct blk_mq_hw_ctx *(alloc_hctx_fn)(struct blk_mq_tag_set *,
+               unsigned int);
 typedef void (free_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int);
 typedef int (init_hctx_fn)(struct blk_mq_hw_ctx *, void *, unsigned int);
 typedef void (exit_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int);
+typedef int (init_request_fn)(void *, struct request *, unsigned int,
+               unsigned int, unsigned int);
+typedef void (exit_request_fn)(void *, struct request *, unsigned int,
+               unsigned int);
 
 struct blk_mq_ops {
        /*
@@ -98,6 +105,14 @@ struct blk_mq_ops {
         */
        init_hctx_fn            *init_hctx;
        exit_hctx_fn            *exit_hctx;
+
+       /*
+        * Called for every command allocated by the block layer to allow
+        * the driver to set up driver specific data.
+        * Ditto for exit/teardown.
+        */
+       init_request_fn         *init_request;
+       exit_request_fn         *exit_request;
 };
 
 enum {
@@ -107,18 +122,18 @@ enum {
 
        BLK_MQ_F_SHOULD_MERGE   = 1 << 0,
        BLK_MQ_F_SHOULD_SORT    = 1 << 1,
-       BLK_MQ_F_SHOULD_IPI     = 1 << 2,
 
        BLK_MQ_S_STOPPED        = 0,
 
        BLK_MQ_MAX_DEPTH        = 2048,
 };
 
-struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *);
+struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *);
 int blk_mq_register_disk(struct gendisk *);
 void blk_mq_unregister_disk(struct gendisk *);
-int blk_mq_init_commands(struct request_queue *, int (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
-void blk_mq_free_commands(struct request_queue *, void (*free)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
+
+int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set);
+void blk_mq_free_tag_set(struct blk_mq_tag_set *set);
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
 
@@ -128,26 +143,25 @@ void blk_mq_free_request(struct request *rq);
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
 struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp);
 struct request *blk_mq_alloc_reserved_request(struct request_queue *q, int rw, gfp_t gfp);
-struct request *blk_mq_rq_from_tag(struct request_queue *q, unsigned int tag);
+struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag);
 
 struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_index);
-struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *, unsigned int);
+struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *, unsigned int);
 void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int);
 
-bool blk_mq_end_io_partial(struct request *rq, int error,
-               unsigned int nr_bytes);
-static inline void blk_mq_end_io(struct request *rq, int error)
-{
-       bool done = !blk_mq_end_io_partial(rq, error, blk_rq_bytes(rq));
-       BUG_ON(!done);
-}
+void blk_mq_end_io(struct request *rq, int error);
+void __blk_mq_end_io(struct request *rq, int error);
+
+void blk_mq_requeue_request(struct request *rq);
 
 void blk_mq_complete_request(struct request *rq);
 
 void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx);
 void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx);
 void blk_mq_stop_hw_queues(struct request_queue *q);
-void blk_mq_start_stopped_hw_queues(struct request_queue *q);
+void blk_mq_start_hw_queues(struct request_queue *q);
+void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async);
+void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs);
 
 /*
  * Driver command data is immediately after the request. So subtract request
@@ -162,12 +176,6 @@ static inline void *blk_mq_rq_to_pdu(struct request *rq)
        return (void *) rq + sizeof(*rq);
 }
 
-static inline struct request *blk_mq_tag_to_rq(struct blk_mq_hw_ctx *hctx,
-                                              unsigned int tag)
-{
-       return hctx->rqs[tag];
-}
-
 #define queue_for_each_hw_ctx(q, hctx, i)                              \
        for ((i) = 0; (i) < (q)->nr_hw_queues &&                        \
             ({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++)
index aa0eaa2d0bd85854e231f9fecd56e4f037446d55..86df13b97160eb9b4bd8ede7e92158fd7f0825e4 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __LINUX_BLK_TYPES_H
 #define __LINUX_BLK_TYPES_H
 
-#ifdef CONFIG_BLOCK
-
 #include <linux/types.h>
 
 struct bio_set;
@@ -28,6 +26,8 @@ struct bio_vec {
        unsigned int    bv_offset;
 };
 
+#ifdef CONFIG_BLOCK
+
 struct bvec_iter {
        sector_t                bi_sector;      /* device address in 512 byte
                                                   sectors */
index 0d84981ee03fc1c9d7bd5b656611b8b87af696e0..74ee55fefcf0a4810f5fb984b2247aba9e019ae2 100644 (file)
@@ -98,7 +98,7 @@ struct request {
        struct list_head queuelist;
        union {
                struct call_single_data csd;
-               struct work_struct mq_flush_work;
+               struct work_struct requeue_work;
                unsigned long fifo_time;
        };
 
@@ -178,7 +178,6 @@ struct request {
        unsigned short ioprio;
 
        void *special;          /* opaque pointer available for LLD use */
-       char *buffer;           /* kaddr of the current segment if available */
 
        int tag;
        int errors;
@@ -613,6 +612,15 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
 
 #define rq_data_dir(rq)                (((rq)->cmd_flags & 1) != 0)
 
+/*
+ * Driver can handle struct request, if it either has an old style
+ * request_fn defined, or is blk-mq based.
+ */
+static inline bool queue_is_rq_based(struct request_queue *q)
+{
+       return q->request_fn || q->mq_ops;
+}
+
 static inline unsigned int blk_queue_cluster(struct request_queue *q)
 {
        return q->limits.cluster;
@@ -937,6 +945,7 @@ extern struct request *blk_fetch_request(struct request_queue *q);
  */
 extern bool blk_update_request(struct request *rq, int error,
                               unsigned int nr_bytes);
+extern void blk_finish_request(struct request *rq, int error);
 extern bool blk_end_request(struct request *rq, int error,
                            unsigned int nr_bytes);
 extern void blk_end_request_all(struct request *rq, int error);
@@ -1102,7 +1111,8 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk)
 /*
  * tag stuff
  */
-#define blk_rq_tagged(rq)              ((rq)->cmd_flags & REQ_QUEUED)
+#define blk_rq_tagged(rq) \
+       ((rq)->mq_ctx || ((rq)->cmd_flags & REQ_QUEUED))
 extern int blk_queue_start_tag(struct request_queue *, struct request *);
 extern struct request *blk_queue_find_tag(struct request_queue *, int);
 extern void blk_queue_end_tag(struct request_queue *, struct request *);
@@ -1370,8 +1380,9 @@ static inline void put_dev_sector(Sector p)
 }
 
 struct work_struct;
-int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
-int kblockd_schedule_delayed_work(struct request_queue *q, struct delayed_work *dwork, unsigned long delay);
+int kblockd_schedule_work(struct work_struct *work);
+int kblockd_schedule_delayed_work(struct delayed_work *dwork, unsigned long delay);
+int kblockd_schedule_delayed_work_on(int cpu, struct delayed_work *dwork, unsigned long delay);
 
 #ifdef CONFIG_BLK_CGROUP
 /*
index 2f49aa4c4f7f1d2feb361422e2b5f024c55a9519..279b0afac1c112e7eee89dddce0847ddcff2d5a2 100644 (file)
@@ -222,8 +222,6 @@ extern void ceph_copy_to_page_vector(struct page **pages,
 extern void ceph_copy_from_page_vector(struct page **pages,
                                    void *data,
                                    loff_t off, size_t len);
-extern int ceph_copy_page_vector_to_user(struct page **pages, void __user *data,
-                                   loff_t off, size_t len);
 extern void ceph_zero_page_vector_range(int off, int len, struct page **pages);
 
 
index 5ae5100c1f2457ec9573870f2b90875031255a02..77a5fa191502fdf96528a3eccbf57f79cf3d9f6d 100644 (file)
@@ -468,6 +468,27 @@ struct cpufreq_frequency_table {
                                    * order */
 };
 
+bool cpufreq_next_valid(struct cpufreq_frequency_table **pos);
+
+/*
+ * cpufreq_for_each_entry -    iterate over a cpufreq_frequency_table
+ * @pos:       the cpufreq_frequency_table * to use as a loop cursor.
+ * @table:     the cpufreq_frequency_table * to iterate over.
+ */
+
+#define cpufreq_for_each_entry(pos, table)     \
+       for (pos = table; pos->frequency != CPUFREQ_TABLE_END; pos++)
+
+/*
+ * cpufreq_for_each_valid_entry -     iterate over a cpufreq_frequency_table
+ *     excluding CPUFREQ_ENTRY_INVALID frequencies.
+ * @pos:        the cpufreq_frequency_table * to use as a loop cursor.
+ * @table:      the cpufreq_frequency_table * to iterate over.
+ */
+
+#define cpufreq_for_each_valid_entry(pos, table)       \
+       for (pos = table; cpufreq_next_valid(&pos); pos++)
+
 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
                                    struct cpufreq_frequency_table *table);
 
index 8300fb87b84ac1329d8facb1d560767c29c549d8..72cb0ddb9678d21eb2f2edd20a36b594b72160d9 100644 (file)
@@ -429,6 +429,7 @@ typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
 typedef void (*dma_async_tx_callback)(void *dma_async_param);
 
 struct dmaengine_unmap_data {
+       u8 map_cnt;
        u8 to_cnt;
        u8 from_cnt;
        u8 bidi_cnt;
index 0a114d05f68d35bd275924a7290a6c3b75ef17fd..212f537fc686a8384c7618e97f5e02cdea5f524c 100644 (file)
@@ -154,13 +154,23 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
  * @reset: Reset (part of) the device, as specified by a bitmask of
  *     flags from &enum ethtool_reset_flags.  Returns a negative
  *     error code or zero.
+ * @get_rxfh_key_size: Get the size of the RX flow hash key.
+ *     Returns zero if not supported for this specific device.
  * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table.
  *     Returns zero if not supported for this specific device.
  * @get_rxfh_indir: Get the contents of the RX flow hash indirection table.
  *     Will not be called if @get_rxfh_indir_size returns zero.
+ * @get_rxfh: Get the contents of the RX flow hash indirection table and hash
+ *     key.
+ *     Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size
+ *     returns zero.
  *     Returns a negative error code or zero.
  * @set_rxfh_indir: Set the contents of the RX flow hash indirection table.
  *     Will not be called if @get_rxfh_indir_size returns zero.
+ * @set_rxfh: Set the contents of the RX flow hash indirection table and
+ *     hash key.
+ *     Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size
+ *     returns zero.
  *     Returns a negative error code or zero.
  * @get_channels: Get number of channels.
  * @set_channels: Set number of channels.  Returns a negative error code or
@@ -232,7 +242,10 @@ struct ethtool_ops {
        int     (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
        int     (*flash_device)(struct net_device *, struct ethtool_flash *);
        int     (*reset)(struct net_device *, u32 *);
+       u32     (*get_rxfh_key_size)(struct net_device *);
        u32     (*get_rxfh_indir_size)(struct net_device *);
+       int     (*get_rxfh)(struct net_device *, u32 *, u8 *);
+       int     (*set_rxfh)(struct net_device *, u32 *, u8 *);
        int     (*get_rxfh_indir)(struct net_device *, u32 *);
        int     (*set_rxfh_indir)(struct net_device *, const u32 *);
        void    (*get_channels)(struct net_device *, struct ethtool_channels *);
index df53e1753a76bffe0ff8fefa8c5a2a0ab8ad0790..8c03f71307c6d2485121b89a0d66b84efb7a4ab0 100644 (file)
@@ -146,6 +146,9 @@ struct f2fs_extent {
 #define ADDRS_PER_BLOCK                1018    /* Address Pointers in a Direct Block */
 #define NIDS_PER_BLOCK         1018    /* Node IDs in an Indirect Block */
 
+#define ADDRS_PER_PAGE(page, fi)       \
+       (IS_INODE(page) ? ADDRS_PER_INODE(fi) : ADDRS_PER_BLOCK)
+
 #define        NODE_DIR1_BLOCK         (DEF_ADDRS_PER_INODE + 1)
 #define        NODE_DIR2_BLOCK         (DEF_ADDRS_PER_INODE + 2)
 #define        NODE_IND1_BLOCK         (DEF_ADDRS_PER_INODE + 3)
index fe6ac956550e4e099a04889e9b33bf0f9a917c2e..b6bfda99add3c78d7b638a8a3b8f86730f77113f 100644 (file)
@@ -47,6 +47,7 @@ struct device_node;
 
 #define FB_MISC_PRIM_COLOR     1
 #define FB_MISC_1ST_DETAIL     2       /* First Detailed Timing is preferred */
+#define FB_MISC_HDMI           4
 struct fb_chroma {
        __u32 redx;     /* in fraction of 1024 */
        __u32 greenx;
@@ -641,7 +642,7 @@ static inline void unlock_fb_info(struct fb_info *info)
 static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch,
                                           u8 *src, u32 s_pitch, u32 height)
 {
-       int i, j;
+       u32 i, j;
 
        d_pitch -= s_pitch;
 
index 024fd03e5d182d5670ee2c60005cbea43f8a83e8..ed1efab10b8fb79b8356d786ca55354f9d289b28 100644 (file)
 #define BPF_CALL       0x80    /* function call */
 #define BPF_EXIT       0x90    /* function return */
 
+/* Placeholder/dummy for 0 */
+#define BPF_0          0
+
+/* Register numbers */
+enum {
+       BPF_REG_0 = 0,
+       BPF_REG_1,
+       BPF_REG_2,
+       BPF_REG_3,
+       BPF_REG_4,
+       BPF_REG_5,
+       BPF_REG_6,
+       BPF_REG_7,
+       BPF_REG_8,
+       BPF_REG_9,
+       BPF_REG_10,
+       __MAX_BPF_REG,
+};
+
 /* BPF has 10 general purpose 64-bit registers and stack frame. */
-#define MAX_BPF_REG    11
+#define MAX_BPF_REG    __MAX_BPF_REG
+
+/* ArgX, context and stack frame pointer register positions. Note,
+ * Arg1, Arg2, Arg3, etc are used as argument mappings of function
+ * calls in BPF_CALL instruction.
+ */
+#define BPF_REG_ARG1   BPF_REG_1
+#define BPF_REG_ARG2   BPF_REG_2
+#define BPF_REG_ARG3   BPF_REG_3
+#define BPF_REG_ARG4   BPF_REG_4
+#define BPF_REG_ARG5   BPF_REG_5
+#define BPF_REG_CTX    BPF_REG_6
+#define BPF_REG_FP     BPF_REG_10
+
+/* Additional register mappings for converted user programs. */
+#define BPF_REG_A      BPF_REG_0
+#define BPF_REG_X      BPF_REG_7
+#define BPF_REG_TMP    BPF_REG_8
 
 /* BPF program can access up to 512 bytes of stack space. */
 #define MAX_BPF_STACK  512
 
-/* Arg1, context and stack frame pointer register positions. */
-#define ARG1_REG       1
-#define CTX_REG                6
-#define FP_REG         10
+/* Macro to invoke filter function. */
+#define SK_RUN_FILTER(filter, ctx)  (*filter->bpf_func)(ctx, filter->insnsi)
 
 struct sock_filter_int {
        __u8    code;           /* opcode */
@@ -97,9 +131,6 @@ static inline unsigned int sk_filter_size(unsigned int proglen)
 #define sk_filter_proglen(fprog)                       \
                (fprog->len * sizeof(fprog->filter[0]))
 
-#define SK_RUN_FILTER(filter, ctx)                     \
-               (*filter->bpf_func)(ctx, filter->insnsi)
-
 int sk_filter(struct sock *sk, struct sk_buff *skb);
 
 u32 sk_run_filter_int_seccomp(const struct seccomp_data *ctx,
@@ -223,6 +254,7 @@ enum {
        BPF_S_ANC_VLAN_TAG,
        BPF_S_ANC_VLAN_TAG_PRESENT,
        BPF_S_ANC_PAY_OFFSET,
+       BPF_S_ANC_RANDOM,
 };
 
 #endif /* __LINUX_FILTER_H__ */
index 878031227c57a0b41be7cde3070ee90f1921b570..4e92d551518d89d61f763775f5416bfc520e7630 100644 (file)
@@ -128,6 +128,10 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 #define FMODE_ATOMIC_POS       ((__force fmode_t)0x8000)
 /* Write access to underlying fs */
 #define FMODE_WRITER           ((__force fmode_t)0x10000)
+/* Has read method(s) */
+#define FMODE_CAN_READ          ((__force fmode_t)0x20000)
+/* Has write method(s) */
+#define FMODE_CAN_WRITE         ((__force fmode_t)0x40000)
 
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
@@ -343,8 +347,7 @@ struct address_space_operations {
        void (*invalidatepage) (struct page *, unsigned int, unsigned int);
        int (*releasepage) (struct page *, gfp_t);
        void (*freepage)(struct page *);
-       ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
-                       loff_t offset, unsigned long nr_segs);
+       ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset);
        int (*get_xip_mem)(struct address_space *, pgoff_t, int,
                                                void **, unsigned long *);
        /*
@@ -1448,6 +1451,8 @@ struct block_device_operations;
 #define HAVE_COMPAT_IOCTL 1
 #define HAVE_UNLOCKED_IOCTL 1
 
+struct iov_iter;
+
 struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
@@ -1455,6 +1460,8 @@ struct file_operations {
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+       ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
+       ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
        int (*iterate) (struct file *, struct dir_context *);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
@@ -2404,20 +2411,18 @@ extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
 extern int generic_file_remap_pages(struct vm_area_struct *, unsigned long addr,
                unsigned long size, pgoff_t pgoff);
 int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
-extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
-extern ssize_t __generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long);
-extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
-extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *,
-               unsigned long *, loff_t, size_t, size_t);
+extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);
+extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *);
+extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *);
+extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *, loff_t);
 extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t);
 extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
 extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
-extern int generic_segment_checks(const struct iovec *iov,
-               unsigned long *nr_segs, size_t *count, int access_flags);
+extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
+extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
 
 /* fs/block_dev.c */
-extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos);
+extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from);
 extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
                        int datasync);
 extern void block_sync_page(struct page *page);
@@ -2427,7 +2432,7 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *,
                struct pipe_inode_info *, size_t, unsigned int);
 extern ssize_t default_file_splice_read(struct file *, loff_t *,
                struct pipe_inode_info *, size_t, unsigned int);
-extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
+extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
                struct file *, loff_t *, size_t, unsigned int);
 extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
                struct file *out, loff_t *, size_t len, unsigned int flags);
@@ -2477,16 +2482,16 @@ enum {
 void dio_end_io(struct bio *bio, int error);
 
 ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
-       struct block_device *bdev, const struct iovec *iov, loff_t offset,
-       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       struct block_device *bdev, struct iov_iter *iter, loff_t offset,
+       get_block_t get_block, dio_iodone_t end_io,
        dio_submit_t submit_io, int flags);
 
 static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
-               struct inode *inode, const struct iovec *iov, loff_t offset,
-               unsigned long nr_segs, get_block_t get_block)
+               struct inode *inode, struct iov_iter *iter, loff_t offset,
+               get_block_t get_block)
 {
-       return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                                   offset, nr_segs, get_block, NULL, NULL,
+       return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iter,
+                                   offset, get_block, NULL, NULL,
                                    DIO_LOCKING | DIO_SKIP_HOLES);
 }
 #endif
index 9212b017bc7236cfc63afe5c268cc741995a1af4..ae9504b4b67d3026cd9c1c1fcd30a8cfc928c984 100644 (file)
@@ -535,6 +535,7 @@ static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_a
 extern int ftrace_arch_read_dyn_info(char *buf, int size);
 
 extern int skip_trace(unsigned long ip);
+extern void ftrace_module_init(struct module *mod);
 
 extern void ftrace_disable_daemon(void);
 extern void ftrace_enable_daemon(void);
@@ -544,6 +545,7 @@ static inline int ftrace_force_update(void) { return 0; }
 static inline void ftrace_disable_daemon(void) { }
 static inline void ftrace_enable_daemon(void) { }
 static inline void ftrace_release_mod(struct module *mod) {}
+static inline void ftrace_module_init(struct module *mod) {}
 static inline __init int register_ftrace_command(struct ftrace_func_command *cmd)
 {
        return -EINVAL;
index a7e977ff4abf060190118884b8a107c826c78feb..8b622468952c427470fa44905ba991d7220a0d68 100644 (file)
@@ -3,29 +3,53 @@
 
 struct device;
 
+/**
+ * struct gpio_keys_button - configuration parameters
+ * @code:              input event code (KEY_*, SW_*)
+ * @gpio:              %-1 if this key does not support gpio
+ * @active_low:                %true indicates that button is considered
+ *                     depressed when gpio is low
+ * @desc:              label that will be attached to button's gpio
+ * @type:              input event type (%EV_KEY, %EV_SW, %EV_ABS)
+ * @wakeup:            configure the button as a wake-up source
+ * @debounce_interval: debounce ticks interval in msecs
+ * @can_disable:       %true indicates that userspace is allowed to
+ *                     disable button via sysfs
+ * @value:             axis value for %EV_ABS
+ * @irq:               Irq number in case of interrupt keys
+ */
 struct gpio_keys_button {
-       /* Configuration parameters */
-       unsigned int code;      /* input event code (KEY_*, SW_*) */
-       int gpio;               /* -1 if this key does not support gpio */
+       unsigned int code;
+       int gpio;
        int active_low;
        const char *desc;
-       unsigned int type;      /* input event type (EV_KEY, EV_SW, EV_ABS) */
-       int wakeup;             /* configure the button as a wake-up source */
-       int debounce_interval;  /* debounce ticks interval in msecs */
+       unsigned int type;
+       int wakeup;
+       int debounce_interval;
        bool can_disable;
-       int value;              /* axis value for EV_ABS */
-       unsigned int irq;       /* Irq number in case of interrupt keys */
+       int value;
+       unsigned int irq;
 };
 
+/**
+ * struct gpio_keys_platform_data - platform data for gpio_keys driver
+ * @buttons:           pointer to array of &gpio_keys_button structures
+ *                     describing buttons attached to the device
+ * @nbuttons:          number of elements in @buttons array
+ * @poll_interval:     polling interval in msecs - for polling driver only
+ * @rep:               enable input subsystem auto repeat
+ * @enable:            platform hook for enabling the device
+ * @disable:           platform hook for disabling the device
+ * @name:              input device name
+ */
 struct gpio_keys_platform_data {
        struct gpio_keys_button *buttons;
        int nbuttons;
-       unsigned int poll_interval;     /* polling interval in msecs -
-                                          for polling driver only */
-       unsigned int rep:1;             /* enable input subsystem auto repeat */
+       unsigned int poll_interval;
+       unsigned int rep:1;
        int (*enable)(struct device *dev);
        void (*disable)(struct device *dev);
-       const char *name;               /* input device name */
+       const char *name;
 };
 
 #endif
index 720e3a10608cec94c02c94a6a1053789a567bae5..54f855b2c902ebb595b642834a030cd02704d358 100644 (file)
@@ -570,6 +570,8 @@ struct hid_descriptor {
        .bus = BUS_USB, .vendor = (ven), .product = (prod)
 #define HID_BLUETOOTH_DEVICE(ven, prod)                                        \
        .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod)
+#define HID_I2C_DEVICE(ven, prod)                              \
+       .bus = BUS_I2C, .vendor = (ven), .product = (prod)
 
 #define HID_REPORT_ID(rep) \
        .report_type = (rep)
index 8834a7e5b944a04850ebd824b0dc6b94e944fb35..97ac926c78a707fb6bf45293d00e8f4d86515f43 100644 (file)
@@ -210,7 +210,7 @@ extern int __irq_set_affinity(unsigned int irq, const struct cpumask *cpumask,
 /**
  * irq_set_affinity - Set the irq affinity of a given irq
  * @irq:       Interrupt to set affinity
- * @mask:      cpumask
+ * @cpumask:   cpumask
  *
  * Fails if cpumask does not contain an online CPU
  */
@@ -223,7 +223,7 @@ irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 /**
  * irq_force_affinity - Force the irq affinity of a given irq
  * @irq:       Interrupt to set affinity
- * @mask:      cpumask
+ * @cpumask:   cpumask
  *
  * Same as irq_set_affinity, but without checking the mask against
  * online cpus.
index 10a0b1ac4ea078e3e8e1b5f3117ab47b0dfba936..5c57efb863d08e5937a36e06778efa8047060156 100644 (file)
@@ -603,6 +603,8 @@ static inline u32 irq_get_trigger_type(unsigned int irq)
        return d ? irqd_get_trigger_type(d) : 0;
 }
 
+unsigned int arch_dynirq_lower_bound(unsigned int from);
+
 int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
                struct module *owner);
 
index 80d677483e31f95ce4b08ef00ffb79c239932c18..cd0abb8c9c33de3ce139632340de1c19381f9780 100644 (file)
@@ -309,6 +309,17 @@ static inline key_serial_t key_serial(const struct key *key)
 
 extern void key_set_timeout(struct key *, unsigned);
 
+/*
+ * The permissions required on a key that we're looking up.
+ */
+#define        KEY_NEED_VIEW   0x01    /* Require permission to view attributes */
+#define        KEY_NEED_READ   0x02    /* Require permission to read content */
+#define        KEY_NEED_WRITE  0x04    /* Require permission to update / modify */
+#define        KEY_NEED_SEARCH 0x08    /* Require permission to search (keyring) or find (key) */
+#define        KEY_NEED_LINK   0x10    /* Require permission to link */
+#define        KEY_NEED_SETATTR 0x20   /* Require permission to change attributes */
+#define        KEY_NEED_ALL    0x3f    /* All the above permissions */
+
 /**
  * key_is_instantiated - Determine if a key has been positively instantiated
  * @key: The key to check.
index 345b8c53b8974d7a6cc271fda41c851ee5835f7c..550c88fb0267f158c26d05714e411805ba15ee90 100644 (file)
@@ -73,6 +73,6 @@ int mvebu_mbus_del_window(phys_addr_t base, size_t size);
 int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base,
                    size_t mbus_size, phys_addr_t sdram_phys_base,
                    size_t sdram_size);
-int mvebu_mbus_dt_init(void);
+int mvebu_mbus_dt_init(bool is_coherent);
 
 #endif /* __LINUX_MBUS_H */
index 8a20a51ed42d9c53c1b57153106fe33a0a61d78c..73dc382e72d8ebeccf6ac118f0f0cd643d1bb1fc 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 
 #define INIT_MEMBLOCK_REGIONS  128
+#define INIT_PHYSMEM_REGIONS   4
 
 /* Definition of memblock flags. */
 #define MEMBLOCK_HOTPLUG       0x1     /* hotpluggable region */
@@ -43,6 +44,9 @@ struct memblock {
        phys_addr_t current_limit;
        struct memblock_type memory;
        struct memblock_type reserved;
+#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
+       struct memblock_type physmem;
+#endif
 };
 
 extern struct memblock memblock;
@@ -71,6 +75,63 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size);
 void memblock_trim_memory(phys_addr_t align);
 int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
 int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
+
+/* Low level functions */
+int memblock_add_range(struct memblock_type *type,
+                      phys_addr_t base, phys_addr_t size,
+                      int nid, unsigned long flags);
+
+int memblock_remove_range(struct memblock_type *type,
+                         phys_addr_t base,
+                         phys_addr_t size);
+
+void __next_mem_range(u64 *idx, int nid, struct memblock_type *type_a,
+                     struct memblock_type *type_b, phys_addr_t *out_start,
+                     phys_addr_t *out_end, int *out_nid);
+
+void __next_mem_range_rev(u64 *idx, int nid, struct memblock_type *type_a,
+                         struct memblock_type *type_b, phys_addr_t *out_start,
+                         phys_addr_t *out_end, int *out_nid);
+
+/**
+ * for_each_mem_range - iterate through memblock areas from type_a and not
+ * included in type_b. Or just type_a if type_b is NULL.
+ * @i: u64 used as loop variable
+ * @type_a: ptr to memblock_type to iterate
+ * @type_b: ptr to memblock_type which excludes from the iteration
+ * @nid: node selector, %NUMA_NO_NODE for all nodes
+ * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
+ * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
+ * @p_nid: ptr to int for nid of the range, can be %NULL
+ */
+#define for_each_mem_range(i, type_a, type_b, nid,                     \
+                          p_start, p_end, p_nid)                       \
+       for (i = 0, __next_mem_range(&i, nid, type_a, type_b,           \
+                                    p_start, p_end, p_nid);            \
+            i != (u64)ULLONG_MAX;                                      \
+            __next_mem_range(&i, nid, type_a, type_b,                  \
+                             p_start, p_end, p_nid))
+
+/**
+ * for_each_mem_range_rev - reverse iterate through memblock areas from
+ * type_a and not included in type_b. Or just type_a if type_b is NULL.
+ * @i: u64 used as loop variable
+ * @type_a: ptr to memblock_type to iterate
+ * @type_b: ptr to memblock_type which excludes from the iteration
+ * @nid: node selector, %NUMA_NO_NODE for all nodes
+ * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
+ * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
+ * @p_nid: ptr to int for nid of the range, can be %NULL
+ */
+#define for_each_mem_range_rev(i, type_a, type_b, nid,                 \
+                              p_start, p_end, p_nid)                   \
+       for (i = (u64)ULLONG_MAX,                                       \
+                    __next_mem_range_rev(&i, nid, type_a, type_b,      \
+                                        p_start, p_end, p_nid);        \
+            i != (u64)ULLONG_MAX;                                      \
+            __next_mem_range_rev(&i, nid, type_a, type_b,              \
+                                 p_start, p_end, p_nid))
+
 #ifdef CONFIG_MOVABLE_NODE
 static inline bool memblock_is_hotpluggable(struct memblock_region *m)
 {
@@ -113,9 +174,6 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
             i >= 0; __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid))
 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
 
-void __next_free_mem_range(u64 *idx, int nid, phys_addr_t *out_start,
-                          phys_addr_t *out_end, int *out_nid);
-
 /**
  * for_each_free_mem_range - iterate through free memblock areas
  * @i: u64 used as loop variable
@@ -128,13 +186,8 @@ void __next_free_mem_range(u64 *idx, int nid, phys_addr_t *out_start,
  * soon as memblock is initialized.
  */
 #define for_each_free_mem_range(i, nid, p_start, p_end, p_nid)         \
-       for (i = 0,                                                     \
-            __next_free_mem_range(&i, nid, p_start, p_end, p_nid);     \
-            i != (u64)ULLONG_MAX;                                      \
-            __next_free_mem_range(&i, nid, p_start, p_end, p_nid))
-
-void __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start,
-                              phys_addr_t *out_end, int *out_nid);
+       for_each_mem_range(i, &memblock.memory, &memblock.reserved,     \
+                          nid, p_start, p_end, p_nid)
 
 /**
  * for_each_free_mem_range_reverse - rev-iterate through free memblock areas
@@ -148,10 +201,8 @@ void __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start,
  * order.  Available as soon as memblock is initialized.
  */
 #define for_each_free_mem_range_reverse(i, nid, p_start, p_end, p_nid) \
-       for (i = (u64)ULLONG_MAX,                                       \
-            __next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid); \
-            i != (u64)ULLONG_MAX;                                      \
-            __next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid))
+       for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved, \
+                              nid, p_start, p_end, p_nid)
 
 static inline void memblock_set_region_flags(struct memblock_region *r,
                                             unsigned long flags)
index 5cf8b91ce996c29652b4f5bdd5afad8cd9a62e6f..6d9371f88875d49c223f07f42401b1d1ed6f4bde 100644 (file)
@@ -124,4 +124,7 @@ int wm5102_patch(struct arizona *arizona);
 int wm5110_patch(struct arizona *arizona);
 int wm8997_patch(struct arizona *arizona);
 
+extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
+                                    bool mandatory);
+
 #endif
diff --git a/include/linux/mfd/ipaq-micro.h b/include/linux/mfd/ipaq-micro.h
new file mode 100644 (file)
index 0000000..5c4d29f
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Header file for the compaq Micro MFD
+ */
+
+#ifndef _MFD_IPAQ_MICRO_H_
+#define _MFD_IPAQ_MICRO_H_
+
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+
+#define TX_BUF_SIZE    32
+#define RX_BUF_SIZE    16
+#define CHAR_SOF       0x02
+
+/*
+ * These are the different messages that can be sent to the microcontroller
+ * to control various aspects.
+ */
+#define MSG_VERSION            0x0
+#define MSG_KEYBOARD           0x2
+#define MSG_TOUCHSCREEN                0x3
+#define MSG_EEPROM_READ                0x4
+#define MSG_EEPROM_WRITE       0x5
+#define MSG_THERMAL_SENSOR     0x6
+#define MSG_NOTIFY_LED         0x8
+#define MSG_BATTERY            0x9
+#define MSG_SPI_READ           0xb
+#define MSG_SPI_WRITE          0xc
+#define MSG_BACKLIGHT          0xd /* H3600 only */
+#define MSG_CODEC_CTRL         0xe /* H3100 only */
+#define MSG_DISPLAY_CTRL       0xf /* H3100 only */
+
+/* state of receiver parser */
+enum rx_state {
+       STATE_SOF = 0,     /* Next byte should be start of frame */
+       STATE_ID,          /* Next byte is ID & message length   */
+       STATE_DATA,        /* Next byte is a data byte           */
+       STATE_CHKSUM       /* Next byte should be checksum       */
+};
+
+/**
+ * struct ipaq_micro_txdev - TX state
+ * @len: length of message in TX buffer
+ * @index: current index into TX buffer
+ * @buf: TX buffer
+ */
+struct ipaq_micro_txdev {
+       u8 len;
+       u8 index;
+       u8 buf[TX_BUF_SIZE];
+};
+
+/**
+ * struct ipaq_micro_rxdev - RX state
+ * @state: context of RX state machine
+ * @chksum: calculated checksum
+ * @id: message ID from packet
+ * @len: RX buffer length
+ * @index: RX buffer index
+ * @buf: RX buffer
+ */
+struct ipaq_micro_rxdev {
+       enum rx_state state;
+       unsigned char chksum;
+       u8            id;
+       unsigned int  len;
+       unsigned int  index;
+       u8            buf[RX_BUF_SIZE];
+};
+
+/**
+ * struct ipaq_micro_msg - message to the iPAQ microcontroller
+ * @id: 4-bit ID of the message
+ * @tx_len: length of TX data
+ * @tx_data: TX data to send
+ * @rx_len: length of receieved RX data
+ * @rx_data: RX data to recieve
+ * @ack: a completion that will be completed when RX is complete
+ * @node: list node if message gets queued
+ */
+struct ipaq_micro_msg {
+       u8 id;
+       u8 tx_len;
+       u8 tx_data[TX_BUF_SIZE];
+       u8 rx_len;
+       u8 rx_data[RX_BUF_SIZE];
+       struct completion ack;
+       struct list_head node;
+};
+
+/**
+ * struct ipaq_micro - iPAQ microcontroller state
+ * @dev: corresponding platform device
+ * @base: virtual memory base for underlying serial device
+ * @sdlc: virtual memory base for Synchronous Data Link Controller
+ * @version: version string
+ * @tx: TX state
+ * @rx: RX state
+ * @lock: lock for this state container
+ * @msg: current message
+ * @queue: message queue
+ * @key: callback for asynchronous key events
+ * @key_data: data to pass along with key events
+ * @ts: callback for asynchronous touchscreen events
+ * @ts_data: data to pass along with key events
+ */
+struct ipaq_micro {
+       struct device *dev;
+       void __iomem *base;
+       void __iomem *sdlc;
+       char version[5];
+       struct ipaq_micro_txdev tx;     /* transmit ISR state */
+       struct ipaq_micro_rxdev rx;     /* receive ISR state */
+       spinlock_t lock;
+       struct ipaq_micro_msg *msg;
+       struct list_head queue;
+       void (*key) (void *data, int len, unsigned char *rxdata);
+       void *key_data;
+       void (*ts) (void *data, int len, unsigned char *rxdata);
+       void *ts_data;
+};
+
+extern int
+ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg);
+
+static inline int
+ipaq_micro_tx_msg_sync(struct ipaq_micro *micro,
+                      struct ipaq_micro_msg *msg)
+{
+       int ret;
+
+       init_completion(&msg->ack);
+       ret = ipaq_micro_tx_msg(micro, msg);
+       wait_for_completion(&msg->ack);
+
+       return ret;
+}
+
+static inline int
+ipaq_micro_tx_msg_async(struct ipaq_micro *micro,
+                       struct ipaq_micro_msg *msg)
+{
+       init_completion(&msg->ack);
+       return ipaq_micro_tx_msg(micro, msg);
+}
+
+#endif /* _MFD_IPAQ_MICRO_H_ */
index b911ef3add03de8973a424d441827fcc9767a4ef..26e0b469e5678dac4edb6901c4daff467a29059d 100644 (file)
@@ -51,6 +51,8 @@
 #define        KEMPLD_TYPE_DEBUG               0x1
 #define        KEMPLD_TYPE_CUSTOM              0x2
 
+#define KEMPLD_VERSION_LEN             10
+
 /**
  * struct kempld_info - PLD device information structure
  * @major:     PLD major revision
@@ -60,6 +62,7 @@
  * @type:      PLD type
  * @spec_major:        PLD FW specification major revision
  * @spec_minor:        PLD FW specification minor revision
+ * @version:   PLD version string
  */
 struct kempld_info {
        unsigned int major;
@@ -69,6 +72,7 @@ struct kempld_info {
        unsigned int type;
        unsigned int spec_major;
        unsigned int spec_minor;
+       char version[KEMPLD_VERSION_LEN];
 };
 
 /**
index c9b332fb0d5da1e11c0ac42c06bf62521541d55e..499253604026cf94044fe18709501b3b47e8fc3c 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * max14577-private.h - Common API for the Maxim 14577 internal sub chip
+ * max14577-private.h - Common API for the Maxim 14577/77836 internal sub chip
  *
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2014 Samsung Electrnoics
  * Chanwoo Choi <cw00.choi@samsung.com>
  * Krzysztof Kozlowski <k.kozlowski@samsung.com>
  *
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 
-#define MAX14577_REG_INVALID           (0xff)
+#define I2C_ADDR_PMIC  (0x46 >> 1)
+#define I2C_ADDR_MUIC  (0x4A >> 1)
+#define I2C_ADDR_FG    (0x6C >> 1)
 
-/* Slave addr = 0x4A: Interrupt */
+enum maxim_device_type {
+       MAXIM_DEVICE_TYPE_UNKNOWN       = 0,
+       MAXIM_DEVICE_TYPE_MAX14577,
+       MAXIM_DEVICE_TYPE_MAX77836,
+
+       MAXIM_DEVICE_TYPE_NUM,
+};
+
+/* Slave addr = 0x4A: MUIC and Charger */
 enum max14577_reg {
        MAX14577_REG_DEVICEID           = 0x00,
        MAX14577_REG_INT1               = 0x01,
@@ -74,20 +84,22 @@ enum max14577_muic_charger_type {
 };
 
 /* MAX14577 interrupts */
-#define INT1_ADC_MASK                  (0x1 << 0)
-#define INT1_ADCLOW_MASK               (0x1 << 1)
-#define INT1_ADCERR_MASK               (0x1 << 2)
-
-#define INT2_CHGTYP_MASK               (0x1 << 0)
-#define INT2_CHGDETRUN_MASK            (0x1 << 1)
-#define INT2_DCDTMR_MASK               (0x1 << 2)
-#define INT2_DBCHG_MASK                        (0x1 << 3)
-#define INT2_VBVOLT_MASK               (0x1 << 4)
-
-#define INT3_EOC_MASK                  (0x1 << 0)
-#define INT3_CGMBC_MASK                        (0x1 << 1)
-#define INT3_OVP_MASK                  (0x1 << 2)
-#define INT3_MBCCHGERR_MASK            (0x1 << 3)
+#define MAX14577_INT1_ADC_MASK         BIT(0)
+#define MAX14577_INT1_ADCLOW_MASK      BIT(1)
+#define MAX14577_INT1_ADCERR_MASK      BIT(2)
+#define MAX77836_INT1_ADC1K_MASK       BIT(3)
+
+#define MAX14577_INT2_CHGTYP_MASK      BIT(0)
+#define MAX14577_INT2_CHGDETRUN_MASK   BIT(1)
+#define MAX14577_INT2_DCDTMR_MASK      BIT(2)
+#define MAX14577_INT2_DBCHG_MASK       BIT(3)
+#define MAX14577_INT2_VBVOLT_MASK      BIT(4)
+#define MAX77836_INT2_VIDRM_MASK       BIT(5)
+
+#define MAX14577_INT3_EOC_MASK         BIT(0)
+#define MAX14577_INT3_CGMBC_MASK       BIT(1)
+#define MAX14577_INT3_OVP_MASK         BIT(2)
+#define MAX14577_INT3_MBCCHGERR_MASK   BIT(3)
 
 /* MAX14577 DEVICE ID register */
 #define DEVID_VENDORID_SHIFT           0
@@ -99,9 +111,11 @@ enum max14577_muic_charger_type {
 #define STATUS1_ADC_SHIFT              0
 #define STATUS1_ADCLOW_SHIFT           5
 #define STATUS1_ADCERR_SHIFT           6
+#define MAX77836_STATUS1_ADC1K_SHIFT   7
 #define STATUS1_ADC_MASK               (0x1f << STATUS1_ADC_SHIFT)
-#define STATUS1_ADCLOW_MASK            (0x1 << STATUS1_ADCLOW_SHIFT)
-#define STATUS1_ADCERR_MASK            (0x1 << STATUS1_ADCERR_SHIFT)
+#define STATUS1_ADCLOW_MASK            BIT(STATUS1_ADCLOW_SHIFT)
+#define STATUS1_ADCERR_MASK            BIT(STATUS1_ADCERR_SHIFT)
+#define MAX77836_STATUS1_ADC1K_MASK    BIT(MAX77836_STATUS1_ADC1K_SHIFT)
 
 /* MAX14577 STATUS2 register */
 #define STATUS2_CHGTYP_SHIFT           0
@@ -109,11 +123,13 @@ enum max14577_muic_charger_type {
 #define STATUS2_DCDTMR_SHIFT           4
 #define STATUS2_DBCHG_SHIFT            5
 #define STATUS2_VBVOLT_SHIFT           6
+#define MAX77836_STATUS2_VIDRM_SHIFT   7
 #define STATUS2_CHGTYP_MASK            (0x7 << STATUS2_CHGTYP_SHIFT)
-#define STATUS2_CHGDETRUN_MASK         (0x1 << STATUS2_CHGDETRUN_SHIFT)
-#define STATUS2_DCDTMR_MASK            (0x1 << STATUS2_DCDTMR_SHIFT)
-#define STATUS2_DBCHG_MASK             (0x1 << STATUS2_DBCHG_SHIFT)
-#define STATUS2_VBVOLT_MASK            (0x1 << STATUS2_VBVOLT_SHIFT)
+#define STATUS2_CHGDETRUN_MASK         BIT(STATUS2_CHGDETRUN_SHIFT)
+#define STATUS2_DCDTMR_MASK            BIT(STATUS2_DCDTMR_SHIFT)
+#define STATUS2_DBCHG_MASK             BIT(STATUS2_DBCHG_SHIFT)
+#define STATUS2_VBVOLT_MASK            BIT(STATUS2_VBVOLT_SHIFT)
+#define MAX77836_STATUS2_VIDRM_MASK    BIT(MAX77836_STATUS2_VIDRM_SHIFT)
 
 /* MAX14577 CONTROL1 register */
 #define COMN1SW_SHIFT                  0
@@ -122,8 +138,8 @@ enum max14577_muic_charger_type {
 #define IDBEN_SHIFT                    7
 #define COMN1SW_MASK                   (0x7 << COMN1SW_SHIFT)
 #define COMP2SW_MASK                   (0x7 << COMP2SW_SHIFT)
-#define MICEN_MASK                     (0x1 << MICEN_SHIFT)
-#define IDBEN_MASK                     (0x1 << IDBEN_SHIFT)
+#define MICEN_MASK                     BIT(MICEN_SHIFT)
+#define IDBEN_MASK                     BIT(IDBEN_SHIFT)
 #define CLEAR_IDBEN_MICEN_MASK         (COMN1SW_MASK | COMP2SW_MASK)
 #define CTRL1_SW_USB                   ((1 << COMP2SW_SHIFT) \
                                                | (1 << COMN1SW_SHIFT))
@@ -143,14 +159,14 @@ enum max14577_muic_charger_type {
 #define CTRL2_ACCDET_SHIFT             (5)
 #define CTRL2_USBCPINT_SHIFT           (6)
 #define CTRL2_RCPS_SHIFT               (7)
-#define CTRL2_LOWPWR_MASK              (0x1 << CTRL2_LOWPWR_SHIFT)
-#define CTRL2_ADCEN_MASK               (0x1 << CTRL2_ADCEN_SHIFT)
-#define CTRL2_CPEN_MASK                        (0x1 << CTRL2_CPEN_SHIFT)
-#define CTRL2_SFOUTASRT_MASK           (0x1 << CTRL2_SFOUTASRT_SHIFT)
-#define CTRL2_SFOUTORD_MASK            (0x1 << CTRL2_SFOUTORD_SHIFT)
-#define CTRL2_ACCDET_MASK              (0x1 << CTRL2_ACCDET_SHIFT)
-#define CTRL2_USBCPINT_MASK            (0x1 << CTRL2_USBCPINT_SHIFT)
-#define CTRL2_RCPS_MASK                        (0x1 << CTR2_RCPS_SHIFT)
+#define CTRL2_LOWPWR_MASK              BIT(CTRL2_LOWPWR_SHIFT)
+#define CTRL2_ADCEN_MASK               BIT(CTRL2_ADCEN_SHIFT)
+#define CTRL2_CPEN_MASK                        BIT(CTRL2_CPEN_SHIFT)
+#define CTRL2_SFOUTASRT_MASK           BIT(CTRL2_SFOUTASRT_SHIFT)
+#define CTRL2_SFOUTORD_MASK            BIT(CTRL2_SFOUTORD_SHIFT)
+#define CTRL2_ACCDET_MASK              BIT(CTRL2_ACCDET_SHIFT)
+#define CTRL2_USBCPINT_MASK            BIT(CTRL2_USBCPINT_SHIFT)
+#define CTRL2_RCPS_MASK                        BIT(CTRL2_RCPS_SHIFT)
 
 #define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \
                                (0 << CTRL2_LOWPWR_SHIFT))
@@ -198,14 +214,14 @@ enum max14577_charger_reg {
 #define CDETCTRL1_DBEXIT_SHIFT         5
 #define CDETCTRL1_DBIDLE_SHIFT         6
 #define CDETCTRL1_CDPDET_SHIFT         7
-#define CDETCTRL1_CHGDETEN_MASK                (0x1 << CDETCTRL1_CHGDETEN_SHIFT)
-#define CDETCTRL1_CHGTYPMAN_MASK       (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT)
-#define CDETCTRL1_DCDEN_MASK           (0x1 << CDETCTRL1_DCDEN_SHIFT)
-#define CDETCTRL1_DCD2SCT_MASK         (0x1 << CDETCTRL1_DCD2SCT_SHIFT)
-#define CDETCTRL1_DCHKTM_MASK          (0x1 << CDETCTRL1_DCHKTM_SHIFT)
-#define CDETCTRL1_DBEXIT_MASK          (0x1 << CDETCTRL1_DBEXIT_SHIFT)
-#define CDETCTRL1_DBIDLE_MASK          (0x1 << CDETCTRL1_DBIDLE_SHIFT)
-#define CDETCTRL1_CDPDET_MASK          (0x1 << CDETCTRL1_CDPDET_SHIFT)
+#define CDETCTRL1_CHGDETEN_MASK                BIT(CDETCTRL1_CHGDETEN_SHIFT)
+#define CDETCTRL1_CHGTYPMAN_MASK       BIT(CDETCTRL1_CHGTYPMAN_SHIFT)
+#define CDETCTRL1_DCDEN_MASK           BIT(CDETCTRL1_DCDEN_SHIFT)
+#define CDETCTRL1_DCD2SCT_MASK         BIT(CDETCTRL1_DCD2SCT_SHIFT)
+#define CDETCTRL1_DCHKTM_MASK          BIT(CDETCTRL1_DCHKTM_SHIFT)
+#define CDETCTRL1_DBEXIT_MASK          BIT(CDETCTRL1_DBEXIT_SHIFT)
+#define CDETCTRL1_DBIDLE_MASK          BIT(CDETCTRL1_DBIDLE_SHIFT)
+#define CDETCTRL1_CDPDET_MASK          BIT(CDETCTRL1_CDPDET_SHIFT)
 
 /* MAX14577 CHGCTRL1 register */
 #define CHGCTRL1_TCHW_SHIFT            4
@@ -213,9 +229,9 @@ enum max14577_charger_reg {
 
 /* MAX14577 CHGCTRL2 register */
 #define CHGCTRL2_MBCHOSTEN_SHIFT       6
-#define CHGCTRL2_MBCHOSTEN_MASK                (0x1 << CHGCTRL2_MBCHOSTEN_SHIFT)
+#define CHGCTRL2_MBCHOSTEN_MASK                BIT(CHGCTRL2_MBCHOSTEN_SHIFT)
 #define CHGCTRL2_VCHGR_RC_SHIFT                7
-#define CHGCTRL2_VCHGR_RC_MASK         (0x1 << CHGCTRL2_VCHGR_RC_SHIFT)
+#define CHGCTRL2_VCHGR_RC_MASK         BIT(CHGCTRL2_VCHGR_RC_SHIFT)
 
 /* MAX14577 CHGCTRL3 register */
 #define CHGCTRL3_MBCCVWRC_SHIFT                0
@@ -225,7 +241,7 @@ enum max14577_charger_reg {
 #define CHGCTRL4_MBCICHWRCH_SHIFT      0
 #define CHGCTRL4_MBCICHWRCH_MASK       (0xf << CHGCTRL4_MBCICHWRCH_SHIFT)
 #define CHGCTRL4_MBCICHWRCL_SHIFT      4
-#define CHGCTRL4_MBCICHWRCL_MASK       (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT)
+#define CHGCTRL4_MBCICHWRCL_MASK       BIT(CHGCTRL4_MBCICHWRCL_SHIFT)
 
 /* MAX14577 CHGCTRL5 register */
 #define CHGCTRL5_EOCS_SHIFT            0
@@ -233,7 +249,7 @@ enum max14577_charger_reg {
 
 /* MAX14577 CHGCTRL6 register */
 #define CHGCTRL6_AUTOSTOP_SHIFT                5
-#define CHGCTRL6_AUTOSTOP_MASK         (0x1 << CHGCTRL6_AUTOSTOP_SHIFT)
+#define CHGCTRL6_AUTOSTOP_MASK         BIT(CHGCTRL6_AUTOSTOP_SHIFT)
 
 /* MAX14577 CHGCTRL7 register */
 #define CHGCTRL7_OTPCGHCVS_SHIFT       0
@@ -245,14 +261,111 @@ enum max14577_charger_reg {
 #define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP      50000
 #define MAX14577_REGULATOR_CURRENT_LIMIT_MAX           950000
 
+/* MAX77836 regulator current limits (as in CHGCTRL4 register), uA */
+#define MAX77836_REGULATOR_CURRENT_LIMIT_MIN            45000
+#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START    100000
+#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP      25000
+#define MAX77836_REGULATOR_CURRENT_LIMIT_MAX           475000
+
 /* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
 #define MAX14577_REGULATOR_SAFEOUT_VOLTAGE             4900000
 
+/* MAX77836 regulator LDOx voltage, uV */
+#define MAX77836_REGULATOR_LDO_VOLTAGE_MIN             800000
+#define MAX77836_REGULATOR_LDO_VOLTAGE_MAX             3950000
+#define MAX77836_REGULATOR_LDO_VOLTAGE_STEP            50000
+#define MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM       64
+
+/* Slave addr = 0x46: PMIC */
+enum max77836_pmic_reg {
+       MAX77836_PMIC_REG_PMIC_ID               = 0x20,
+       MAX77836_PMIC_REG_PMIC_REV              = 0x21,
+       MAX77836_PMIC_REG_INTSRC                = 0x22,
+       MAX77836_PMIC_REG_INTSRC_MASK           = 0x23,
+       MAX77836_PMIC_REG_TOPSYS_INT            = 0x24,
+       MAX77836_PMIC_REG_TOPSYS_INT_MASK       = 0x26,
+       MAX77836_PMIC_REG_TOPSYS_STAT           = 0x28,
+       MAX77836_PMIC_REG_MRSTB_CNTL            = 0x2A,
+       MAX77836_PMIC_REG_LSCNFG                = 0x2B,
+
+       MAX77836_LDO_REG_CNFG1_LDO1             = 0x51,
+       MAX77836_LDO_REG_CNFG2_LDO1             = 0x52,
+       MAX77836_LDO_REG_CNFG1_LDO2             = 0x53,
+       MAX77836_LDO_REG_CNFG2_LDO2             = 0x54,
+       MAX77836_LDO_REG_CNFG_LDO_BIAS          = 0x55,
+
+       MAX77836_COMP_REG_COMP1                 = 0x60,
+
+       MAX77836_PMIC_REG_END,
+};
+
+#define MAX77836_INTSRC_MASK_TOP_INT_SHIFT     1
+#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT        3
+#define MAX77836_INTSRC_MASK_TOP_INT_MASK      BIT(MAX77836_INTSRC_MASK_TOP_INT_SHIFT)
+#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK BIT(MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT)
+
+/* MAX77836 PMIC interrupts */
+#define MAX77836_TOPSYS_INT_T120C_SHIFT                0
+#define MAX77836_TOPSYS_INT_T140C_SHIFT                1
+#define MAX77836_TOPSYS_INT_T120C_MASK         BIT(MAX77836_TOPSYS_INT_T120C_SHIFT)
+#define MAX77836_TOPSYS_INT_T140C_MASK         BIT(MAX77836_TOPSYS_INT_T140C_SHIFT)
+
+/* LDO1/LDO2 CONFIG1 register */
+#define MAX77836_CNFG1_LDO_PWRMD_SHIFT         6
+#define MAX77836_CNFG1_LDO_TV_SHIFT            0
+#define MAX77836_CNFG1_LDO_PWRMD_MASK          (0x3 << MAX77836_CNFG1_LDO_PWRMD_SHIFT)
+#define MAX77836_CNFG1_LDO_TV_MASK             (0x3f << MAX77836_CNFG1_LDO_TV_SHIFT)
+
+/* LDO1/LDO2 CONFIG2 register */
+#define MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT      7
+#define MAX77836_CNFG2_LDO_ALPMEN_SHIFT                6
+#define MAX77836_CNFG2_LDO_COMP_SHIFT          4
+#define MAX77836_CNFG2_LDO_POK_SHIFT           3
+#define MAX77836_CNFG2_LDO_ADE_SHIFT           1
+#define MAX77836_CNFG2_LDO_SS_SHIFT            0
+#define MAX77836_CNFG2_LDO_OVCLMPEN_MASK       BIT(MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT)
+#define MAX77836_CNFG2_LDO_ALPMEN_MASK         BIT(MAX77836_CNFG2_LDO_ALPMEN_SHIFT)
+#define MAX77836_CNFG2_LDO_COMP_MASK           (0x3 << MAX77836_CNFG2_LDO_COMP_SHIFT)
+#define MAX77836_CNFG2_LDO_POK_MASK            BIT(MAX77836_CNFG2_LDO_POK_SHIFT)
+#define MAX77836_CNFG2_LDO_ADE_MASK            BIT(MAX77836_CNFG2_LDO_ADE_SHIFT)
+#define MAX77836_CNFG2_LDO_SS_MASK             BIT(MAX77836_CNFG2_LDO_SS_SHIFT)
+
+/* Slave addr = 0x6C: Fuel-Gauge/Battery */
+enum max77836_fg_reg {
+       MAX77836_FG_REG_VCELL_MSB       = 0x02,
+       MAX77836_FG_REG_VCELL_LSB       = 0x03,
+       MAX77836_FG_REG_SOC_MSB         = 0x04,
+       MAX77836_FG_REG_SOC_LSB         = 0x05,
+       MAX77836_FG_REG_MODE_H          = 0x06,
+       MAX77836_FG_REG_MODE_L          = 0x07,
+       MAX77836_FG_REG_VERSION_MSB     = 0x08,
+       MAX77836_FG_REG_VERSION_LSB     = 0x09,
+       MAX77836_FG_REG_HIBRT_H         = 0x0A,
+       MAX77836_FG_REG_HIBRT_L         = 0x0B,
+       MAX77836_FG_REG_CONFIG_H        = 0x0C,
+       MAX77836_FG_REG_CONFIG_L        = 0x0D,
+       MAX77836_FG_REG_VALRT_MIN       = 0x14,
+       MAX77836_FG_REG_VALRT_MAX       = 0x15,
+       MAX77836_FG_REG_CRATE_MSB       = 0x16,
+       MAX77836_FG_REG_CRATE_LSB       = 0x17,
+       MAX77836_FG_REG_VRESET          = 0x18,
+       MAX77836_FG_REG_FGID            = 0x19,
+       MAX77836_FG_REG_STATUS_H        = 0x1A,
+       MAX77836_FG_REG_STATUS_L        = 0x1B,
+       /*
+        * TODO: TABLE registers
+        * TODO: CMD register
+        */
+
+       MAX77836_FG_REG_END,
+};
+
 enum max14577_irq {
        /* INT1 */
        MAX14577_IRQ_INT1_ADC,
        MAX14577_IRQ_INT1_ADCLOW,
        MAX14577_IRQ_INT1_ADCERR,
+       MAX77836_IRQ_INT1_ADC1K,
 
        /* INT2 */
        MAX14577_IRQ_INT2_CHGTYP,
@@ -260,6 +373,7 @@ enum max14577_irq {
        MAX14577_IRQ_INT2_DCDTMR,
        MAX14577_IRQ_INT2_DBCHG,
        MAX14577_IRQ_INT2_VBVOLT,
+       MAX77836_IRQ_INT2_VIDRM,
 
        /* INT3 */
        MAX14577_IRQ_INT3_EOC,
@@ -267,21 +381,25 @@ enum max14577_irq {
        MAX14577_IRQ_INT3_OVP,
        MAX14577_IRQ_INT3_MBCCHGERR,
 
+       /* TOPSYS_INT, only MAX77836 */
+       MAX77836_IRQ_TOPSYS_T140C,
+       MAX77836_IRQ_TOPSYS_T120C,
+
        MAX14577_IRQ_NUM,
 };
 
 struct max14577 {
        struct device *dev;
        struct i2c_client *i2c; /* Slave addr = 0x4A */
+       struct i2c_client *i2c_pmic; /* Slave addr = 0x46 */
+       enum maxim_device_type dev_type;
 
-       struct regmap *regmap;
+       struct regmap *regmap; /* For MUIC and Charger */
+       struct regmap *regmap_pmic;
 
-       struct regmap_irq_chip_data *irq_data;
+       struct regmap_irq_chip_data *irq_data; /* For MUIC and Charger */
+       struct regmap_irq_chip_data *irq_data_pmic;
        int irq;
-
-       /* Device ID */
-       u8 vendor_id;   /* Vendor Identification */
-       u8 device_id;   /* Chip Version */
 };
 
 /* MAX14577 shared regmap API function */
index 736d39c3ec0d7a4b115df93d97d60d84c4979a85..c83fbed1c7b64a7e59ab0ab36e8cfa8fb4d1b6af 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * max14577.h - Driver for the Maxim 14577
+ * max14577.h - Driver for the Maxim 14577/77836
  *
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2014 Samsung Electrnoics
  * Chanwoo Choi <cw00.choi@samsung.com>
  * Krzysztof Kozlowski <k.kozlowski@samsung.com>
  *
@@ -20,6 +20,9 @@
  * MAX14577 has MUIC, Charger devices.
  * The devices share the same I2C bus and interrupt line
  * included in this mfd driver.
+ *
+ * MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave
+ * addresses.
  */
 
 #ifndef __MAX14577_H__
@@ -32,7 +35,17 @@ enum max14577_regulators {
        MAX14577_SAFEOUT = 0,
        MAX14577_CHARGER,
 
-       MAX14577_REG_MAX,
+       MAX14577_REGULATOR_NUM,
+};
+
+/* MAX77836 regulator IDs */
+enum max77836_regulators {
+       MAX77836_SAFEOUT = 0,
+       MAX77836_CHARGER,
+       MAX77836_LDO1,
+       MAX77836_LDO2,
+
+       MAX77836_REGULATOR_NUM,
 };
 
 struct max14577_regulator_platform_data {
index a326c850f0468ad415ad6ab014a470db452b5b03..d63b1d3091061a6c8f48e8ae9eca76eedc21175a 100644 (file)
@@ -117,10 +117,6 @@ struct mc13xxx_led_platform_data {
 
 #define MAX_LED_CONTROL_REGS   6
 
-struct mc13xxx_leds_platform_data {
-       struct mc13xxx_led_platform_data *led;
-       int num_leds;
-
 /* MC13783 LED Control 0 */
 #define MC13783_LED_C0_ENABLE          (1 << 0)
 #define MC13783_LED_C0_TRIODE_MD       (1 << 7)
@@ -169,10 +165,13 @@ struct mc13xxx_leds_platform_data {
 /* MC34708 LED Control 0 */
 #define MC34708_LED_C0_CURRENT_R(x)    (((x) & 0x3) << 9)
 #define MC34708_LED_C0_CURRENT_G(x)    (((x) & 0x3) << 21)
+
+struct mc13xxx_leds_platform_data {
+       struct mc13xxx_led_platform_data *led;
+       int num_leds;
        u32 led_control[MAX_LED_CONTROL_REGS];
 };
 
-struct mc13xxx_buttons_platform_data {
 #define MC13783_BUTTON_DBNC_0MS                0
 #define MC13783_BUTTON_DBNC_30MS       1
 #define MC13783_BUTTON_DBNC_150MS      2
@@ -180,6 +179,8 @@ struct mc13xxx_buttons_platform_data {
 #define MC13783_BUTTON_ENABLE          (1 << 2)
 #define MC13783_BUTTON_POL_INVERT      (1 << 3)
 #define MC13783_BUTTON_RESET_EN                (1 << 4)
+
+struct mc13xxx_buttons_platform_data {
        int b1on_flags;
        unsigned short b1on_key;
        int b2on_flags;
@@ -188,14 +189,14 @@ struct mc13xxx_buttons_platform_data {
        unsigned short b3on_key;
 };
 
+#define MC13783_TS_ATO_FIRST   false
+#define MC13783_TS_ATO_EACH    true
+
 struct mc13xxx_ts_platform_data {
        /* Delay between Touchscreen polarization and ADC Conversion.
         * Given in clock ticks of a 32 kHz clock which gives a granularity of
         * about 30.5ms */
        u8 ato;
-
-#define MC13783_TS_ATO_FIRST false
-#define MC13783_TS_ATO_EACH  true
        /* Use the ATO delay only for the first conversion or for each one */
        bool atox;
 };
@@ -210,11 +211,12 @@ struct mc13xxx_codec_platform_data {
        enum mc13783_ssi_port dac_ssi_port;
 };
 
-struct mc13xxx_platform_data {
-#define MC13XXX_USE_TOUCHSCREEN (1 << 0)
+#define MC13XXX_USE_TOUCHSCREEN        (1 << 0)
 #define MC13XXX_USE_CODEC      (1 << 1)
 #define MC13XXX_USE_ADC                (1 << 2)
 #define MC13XXX_USE_RTC                (1 << 3)
+
+struct mc13xxx_platform_data {
        unsigned int flags;
 
        struct mc13xxx_regulator_platform_data regulators;
index 157e32b6ca28790fccbc2a3d47d30c9b210d6ec4..e7e12ebacb9b33e11ca8136c55bf65885587deaf 100644 (file)
@@ -28,7 +28,6 @@ enum sec_device_type {
  * @dev: master device of the chip (can be used to access platform data)
  * @pdata: pointer to private data used to pass platform data to child
  * @i2c: i2c client private data for regulator
- * @rtc: i2c client private data for rtc
  * @iolock: mutex for serializing io access
  * @irqlock: mutex for buslock
  * @irq_base: base IRQ number for sec-pmic, required for IRQs
@@ -42,17 +41,14 @@ struct sec_pmic_dev {
        struct device *dev;
        struct sec_platform_data *pdata;
        struct regmap *regmap_pmic;
-       struct regmap *regmap_rtc;
        struct i2c_client *i2c;
-       struct i2c_client *rtc;
 
-       int device_type;
+       unsigned long device_type;
        int irq_base;
        int irq;
        struct regmap_irq_chip_data *irq_data;
 
        int ono;
-       unsigned long type;
        bool wakeup;
        bool wtsr_smpl;
 };
index 4b449b8ac548bbff383f12b7ff6da29e41d27b50..900cd7a04314d3c90e58edcbf4960890ce5be69e 100644 (file)
@@ -148,6 +148,8 @@ enum s2mps14_regulators {
 #define S2MPS14_ENABLE_SHIFT           6
 /* On/Off controlled by PWREN */
 #define S2MPS14_ENABLE_SUSPEND         (0x01 << S2MPS14_ENABLE_SHIFT)
+/* On/Off controlled by LDO10EN or EMMCEN */
+#define S2MPS14_ENABLE_EXT_CONTROL     (0x00 << S2MPS14_ENABLE_SHIFT)
 #define S2MPS14_LDO_N_VOLTAGES         (S2MPS14_LDO_VSEL_MASK + 1)
 #define S2MPS14_BUCK_N_VOLTAGES                (S2MPS14_BUCK_VSEL_MASK + 1)
 
index 3f43069413e72dcc2975a14c1e9edf5677365627..0bf2708df150d07862484b48c13204d799f81530 100644 (file)
@@ -64,6 +64,20 @@ enum {
        TPS65090_REGULATOR_MAX,
 };
 
+/* Register addresses */
+#define TPS65090_REG_INTR_STS  0x00
+#define TPS65090_REG_INTR_STS2 0x01
+#define TPS65090_REG_INTR_MASK 0x02
+#define TPS65090_REG_INTR_MASK2        0x03
+#define TPS65090_REG_CG_CTRL0  0x04
+#define TPS65090_REG_CG_CTRL1  0x05
+#define TPS65090_REG_CG_CTRL2  0x06
+#define TPS65090_REG_CG_CTRL3  0x07
+#define TPS65090_REG_CG_CTRL4  0x08
+#define TPS65090_REG_CG_CTRL5  0x09
+#define TPS65090_REG_CG_STATUS1        0x0a
+#define TPS65090_REG_CG_STATUS2        0x0b
+
 struct tps65090 {
        struct device           *dev;
        struct regmap           *rmap;
@@ -78,11 +92,16 @@ struct tps65090 {
  *     DCDC1, DCDC2 and DCDC3.
  * @gpio: Gpio number if external control is enabled and controlled through
  *     gpio.
+ * @overcurrent_wait_valid: True if the overcurrent_wait should be applied.
+ * @overcurrent_wait: Value to set as the overcurrent wait time.  This is the
+ *     actual bitfield value, not a time in ms (valid value are 0 - 3).
  */
 struct tps65090_regulator_plat_data {
        struct regulator_init_data *reg_init_data;
        bool enable_ext_control;
        int gpio;
+       bool overcurrent_wait_valid;
+       int overcurrent_wait;
 };
 
 struct tps65090_platform_data {
index 54b5458ec084a50ec06cc9f418d4e623e0aaf7bc..95d6938737fd291b3ab4c340053f21415521bdb9 100644 (file)
@@ -254,7 +254,6 @@ struct tps65217 {
        struct tps65217_board *pdata;
        unsigned long id;
        struct regulator_desc desc[TPS65217_NUM_REGULATOR];
-       struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
        struct regmap *regmap;
 };
 
index d2e357df5a0e49ac5d0458218d5fcaf8d81c7c19..2f9b593246ee694ddbf46cb5580bcf686a5ff47d 100644 (file)
@@ -267,7 +267,6 @@ struct tps65218 {
        u32 irq_mask;
        struct regmap_irq_chip_data *irq_data;
        struct regulator_desc desc[TPS65218_NUM_REGULATOR];
-       struct regulator_dev *rdev[TPS65218_NUM_REGULATOR];
        struct tps_info *info[TPS65218_NUM_REGULATOR];
        struct regmap *regmap;
 };
index bf9811e1321a5ae80eceeba7664f7d677da9648e..a784964fa4184b9ab19f3bab084c48ed7ea07e18 100644 (file)
@@ -370,6 +370,17 @@ static inline int is_vmalloc_or_module_addr(const void *x)
 }
 #endif
 
+static inline void kvfree(const void *x)
+{
+       /* include order mess... */
+       extern void kfree(const void *);
+       extern void vfree(const void *);
+       if (is_vmalloc_addr(x))
+               vfree(x);
+       else
+               kfree(x);
+}
+
 static inline void compound_lock(struct page *page)
 {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
index b73027298b3a68e71f92b2716ac6952cfc8a1091..aa7e57f60fb26094a003069a526da1c6fb4498e6 100644 (file)
@@ -353,7 +353,7 @@ struct mmc_fixup {
 #define CID_OEMID_ANY ((unsigned short) -1)
 #define CID_NAME_ANY (NULL)
 
-#define END_FIXUP { 0 }
+#define END_FIXUP { NULL }
 
 #define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,       \
                   _cis_vendor, _cis_device,                            \
index 6ce7d2cd3c7ad7dd5eea530192de207b3d1aef22..babaea93bca646d302ae19435e468e9ba68b0042 100644 (file)
@@ -248,20 +248,6 @@ struct dw_mci_board {
        /* delay in mS before detecting cards after interrupt */
        u32 detect_delay_ms;
 
-       int (*init)(u32 slot_id, irq_handler_t , void *);
-       int (*get_ro)(u32 slot_id);
-       int (*get_cd)(u32 slot_id);
-       int (*get_ocr)(u32 slot_id);
-       int (*get_bus_wd)(u32 slot_id);
-       /*
-        * Enable power to selected slot and set voltage to desired level.
-        * Voltage levels are specified using MMC_VDD_xxx defines defined
-        * in linux/mmc/host.h file.
-        */
-       void (*setpower)(u32 slot_id, u32 volt);
-       void (*exit)(u32 slot_id);
-       void (*select_slot)(u32 slot_id);
-
        struct dw_mci_dma_ops *dma_ops;
        struct dma_pdata *data;
        struct block_settings *blk_settings;
index cb61ea4d69455366768fa04bc2263c65795bc92f..0cf705c839985a9bb0595fa3a044e307912138a6 100644 (file)
@@ -58,7 +58,8 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50   5
 #define MMC_TIMING_UHS_SDR104  6
 #define MMC_TIMING_UHS_DDR50   7
-#define MMC_TIMING_MMC_HS200   8
+#define MMC_TIMING_MMC_DDR52   8
+#define MMC_TIMING_MMC_HS200   9
 
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
@@ -318,6 +319,8 @@ struct mmc_host {
        int                     rescan_disable; /* disable card detection */
        int                     rescan_entered; /* used with nonremovable devices */
 
+       bool                    trigger_card_event; /* card_event necessary */
+
        struct mmc_card         *card;          /* device attached to this host */
 
        wait_queue_head_t       wq;
index 204a677438049b13570e779f36078e0450298614..b1990c5524e1cea5a0d52f618f0846a1fd442dfe 100644 (file)
@@ -321,7 +321,7 @@ extern bool parameq(const char *name1, const char *name2);
 extern bool parameqn(const char *name1, const char *name2, size_t n);
 
 /* Called on module insert or kernel boot */
-extern int parse_args(const char *name,
+extern char *parse_args(const char *name,
                      char *args,
                      const struct kernel_param *params,
                      unsigned num,
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
new file mode 100644 (file)
index 0000000..5324184
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_MTD_SPI_NOR_H
+#define __LINUX_MTD_SPI_NOR_H
+
+/*
+ * Note on opcode nomenclature: some opcodes have a format like
+ * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
+ * of I/O lines used for the opcode, address, and data (respectively). The
+ * FUNCTION has an optional suffix of '4', to represent an opcode which
+ * requires a 4-byte (32-bit) address.
+ */
+
+/* Flash opcodes. */
+#define SPINOR_OP_WREN         0x06    /* Write enable */
+#define SPINOR_OP_RDSR         0x05    /* Read status register */
+#define SPINOR_OP_WRSR         0x01    /* Write status register 1 byte */
+#define SPINOR_OP_READ         0x03    /* Read data bytes (low frequency) */
+#define SPINOR_OP_READ_FAST    0x0b    /* Read data bytes (high frequency) */
+#define SPINOR_OP_READ_1_1_2   0x3b    /* Read data bytes (Dual SPI) */
+#define SPINOR_OP_READ_1_1_4   0x6b    /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_PP           0x02    /* Page program (up to 256 bytes) */
+#define SPINOR_OP_BE_4K                0x20    /* Erase 4KiB block */
+#define SPINOR_OP_BE_4K_PMC    0xd7    /* Erase 4KiB block on PMC chips */
+#define SPINOR_OP_BE_32K       0x52    /* Erase 32KiB block */
+#define SPINOR_OP_CHIP_ERASE   0xc7    /* Erase whole flash chip */
+#define SPINOR_OP_SE           0xd8    /* Sector erase (usually 64KiB) */
+#define SPINOR_OP_RDID         0x9f    /* Read JEDEC ID */
+#define SPINOR_OP_RDCR         0x35    /* Read configuration register */
+
+/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+#define SPINOR_OP_READ4                0x13    /* Read data bytes (low frequency) */
+#define SPINOR_OP_READ4_FAST   0x0c    /* Read data bytes (high frequency) */
+#define SPINOR_OP_READ4_1_1_2  0x3c    /* Read data bytes (Dual SPI) */
+#define SPINOR_OP_READ4_1_1_4  0x6c    /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_PP_4B                0x12    /* Page program (up to 256 bytes) */
+#define SPINOR_OP_SE_4B                0xdc    /* Sector erase (usually 64KiB) */
+
+/* Used for SST flashes only. */
+#define SPINOR_OP_BP           0x02    /* Byte program */
+#define SPINOR_OP_WRDI         0x04    /* Write disable */
+#define SPINOR_OP_AAI_WP       0xad    /* Auto address increment word program */
+
+/* Used for Macronix and Winbond flashes. */
+#define SPINOR_OP_EN4B         0xb7    /* Enter 4-byte mode */
+#define SPINOR_OP_EX4B         0xe9    /* Exit 4-byte mode */
+
+/* Used for Spansion flashes only. */
+#define SPINOR_OP_BRWR         0x17    /* Bank register write */
+
+/* Status Register bits. */
+#define SR_WIP                 1       /* Write in progress */
+#define SR_WEL                 2       /* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
+#define SR_BP0                 4       /* Block protect 0 */
+#define SR_BP1                 8       /* Block protect 1 */
+#define SR_BP2                 0x10    /* Block protect 2 */
+#define SR_SRWD                        0x80    /* SR write protect */
+
+#define SR_QUAD_EN_MX          0x40    /* Macronix Quad I/O */
+
+/* Configuration Register bits. */
+#define CR_QUAD_EN_SPAN                0x2     /* Spansion Quad I/O */
+
+enum read_mode {
+       SPI_NOR_NORMAL = 0,
+       SPI_NOR_FAST,
+       SPI_NOR_DUAL,
+       SPI_NOR_QUAD,
+};
+
+/**
+ * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer
+ * @wren:              command for "Write Enable", or 0x00 for not required
+ * @cmd:               command for operation
+ * @cmd_pins:          number of pins to send @cmd (1, 2, 4)
+ * @addr:              address for operation
+ * @addr_pins:         number of pins to send @addr (1, 2, 4)
+ * @addr_width:                number of address bytes
+ *                     (3,4, or 0 for address not required)
+ * @mode:              mode data
+ * @mode_pins:         number of pins to send @mode (1, 2, 4)
+ * @mode_cycles:       number of mode cycles (0 for mode not required)
+ * @dummy_cycles:      number of dummy cycles (0 for dummy not required)
+ */
+struct spi_nor_xfer_cfg {
+       u8              wren;
+       u8              cmd;
+       u8              cmd_pins;
+       u32             addr;
+       u8              addr_pins;
+       u8              addr_width;
+       u8              mode;
+       u8              mode_pins;
+       u8              mode_cycles;
+       u8              dummy_cycles;
+};
+
+#define SPI_NOR_MAX_CMD_SIZE   8
+enum spi_nor_ops {
+       SPI_NOR_OPS_READ = 0,
+       SPI_NOR_OPS_WRITE,
+       SPI_NOR_OPS_ERASE,
+       SPI_NOR_OPS_LOCK,
+       SPI_NOR_OPS_UNLOCK,
+};
+
+/**
+ * struct spi_nor - Structure for defining a the SPI NOR layer
+ * @mtd:               point to a mtd_info structure
+ * @lock:              the lock for the read/write/erase/lock/unlock operations
+ * @dev:               point to a spi device, or a spi nor controller device.
+ * @page_size:         the page size of the SPI NOR
+ * @addr_width:                number of address bytes
+ * @erase_opcode:      the opcode for erasing a sector
+ * @read_opcode:       the read opcode
+ * @read_dummy:                the dummy needed by the read operation
+ * @program_opcode:    the program opcode
+ * @flash_read:                the mode of the read
+ * @sst_write_second:  used by the SST write operation
+ * @cfg:               used by the read_xfer/write_xfer
+ * @cmd_buf:           used by the write_reg
+ * @prepare:           [OPTIONAL] do some preparations for the
+ *                     read/write/erase/lock/unlock operations
+ * @unprepare:         [OPTIONAL] do some post work after the
+ *                     read/write/erase/lock/unlock operations
+ * @read_xfer:         [OPTIONAL] the read fundamental primitive
+ * @write_xfer:                [OPTIONAL] the writefundamental primitive
+ * @read_reg:          [DRIVER-SPECIFIC] read out the register
+ * @write_reg:         [DRIVER-SPECIFIC] write data to the register
+ * @read_id:           [REPLACEABLE] read out the ID data, and find
+ *                     the proper spi_device_id
+ * @wait_till_ready:   [REPLACEABLE] wait till the NOR becomes ready
+ * @read:              [DRIVER-SPECIFIC] read data from the SPI NOR
+ * @write:             [DRIVER-SPECIFIC] write data to the SPI NOR
+ * @erase:             [DRIVER-SPECIFIC] erase a sector of the SPI NOR
+ *                     at the offset @offs
+ * @priv:              the private data
+ */
+struct spi_nor {
+       struct mtd_info         *mtd;
+       struct mutex            lock;
+       struct device           *dev;
+       u32                     page_size;
+       u8                      addr_width;
+       u8                      erase_opcode;
+       u8                      read_opcode;
+       u8                      read_dummy;
+       u8                      program_opcode;
+       enum read_mode          flash_read;
+       bool                    sst_write_second;
+       struct spi_nor_xfer_cfg cfg;
+       u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+
+       int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+       void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+       int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+                        u8 *buf, size_t len);
+       int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+                         u8 *buf, size_t len);
+       int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+                       int write_enable);
+       const struct spi_device_id *(*read_id)(struct spi_nor *nor);
+       int (*wait_till_ready)(struct spi_nor *nor);
+
+       int (*read)(struct spi_nor *nor, loff_t from,
+                       size_t len, size_t *retlen, u_char *read_buf);
+       void (*write)(struct spi_nor *nor, loff_t to,
+                       size_t len, size_t *retlen, const u_char *write_buf);
+       int (*erase)(struct spi_nor *nor, loff_t offs);
+
+       void *priv;
+};
+
+/**
+ * spi_nor_scan() - scan the SPI NOR
+ * @nor:       the spi_nor structure
+ * @id:                the spi_device_id provided by the driver
+ * @mode:      the read mode supported by the driver
+ *
+ * The drivers can use this fuction to scan the SPI NOR.
+ * In the scanning, it will try to get all the necessary information to
+ * fill the mtd_info{} and the spi_nor{}.
+ *
+ * The board may assigns a spi_device_id with @id which be used to compared with
+ * the spi_device_id detected by the scanning.
+ *
+ * Return: 0 for success, others for failure.
+ */
+int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
+                       enum read_mode mode);
+extern const struct spi_device_id spi_nor_ids[];
+
+/**
+ * spi_nor_match_id() - find the spi_device_id by the name
+ * @name:      the name of the spi_device_id
+ *
+ * The drivers use this function to find the spi_device_id
+ * specified by the @name.
+ *
+ * Return: returns the right spi_device_id pointer on success,
+ *         and returns NULL on failure.
+ */
+const struct spi_device_id *spi_nor_match_id(char *name);
+
+#endif
index 7ed3a3aa6604b7b8511ea709ea2c2312a1d38bb2..a803d792df1e6c9c6d3a83ed2ae81a0b9265cae0 100644 (file)
@@ -2633,6 +2633,7 @@ int dev_get_phys_port_id(struct net_device *dev,
                         struct netdev_phys_port_id *ppid);
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        struct netdev_queue *txq);
+int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb);
 
index aad8eeaf416d4bbf6d7ae6a4b40a27d4c346f1c4..7a28115dd3965a7f64487378f5661bda8592b33c 100644 (file)
@@ -45,7 +45,8 @@ struct netlink_kernel_cfg {
        unsigned int    flags;
        void            (*input)(struct sk_buff *skb);
        struct mutex    *cb_mutex;
-       void            (*bind)(int group);
+       int             (*bind)(int group);
+       void            (*unbind)(int group);
        bool            (*compare)(struct net *net, struct sock *sk);
 };
 
@@ -169,4 +170,11 @@ struct netlink_tap {
 extern int netlink_add_tap(struct netlink_tap *nt);
 extern int netlink_remove_tap(struct netlink_tap *nt);
 
+bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
+                         struct user_namespace *ns, int cap);
+bool netlink_ns_capable(const struct sk_buff *skb,
+                       struct user_namespace *ns, int cap);
+bool netlink_capable(const struct sk_buff *skb, int cap);
+bool netlink_net_capable(const struct sk_buff *skb, int cap);
+
 #endif /* __LINUX_NETLINK_H */
index fa6918b0f8295296a04e89c01c3b685dd360e1aa..0a82b6fbae8a4de63683877fce383ae1dee4fcfa 100644 (file)
@@ -459,13 +459,12 @@ extern int nfs3_removexattr (struct dentry *, const char *name);
 /*
  * linux/fs/nfs/direct.c
  */
-extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
-                       unsigned long);
+extern ssize_t nfs_direct_IO(int, struct kiocb *, struct iov_iter *, loff_t);
 extern ssize_t nfs_file_direct_read(struct kiocb *iocb,
-                       const struct iovec *iov, unsigned long nr_segs,
+                       struct iov_iter *iter,
                        loff_t pos, bool uio);
 extern ssize_t nfs_file_direct_write(struct kiocb *iocb,
-                       const struct iovec *iov, unsigned long nr_segs,
+                       struct iov_iter *iter,
                        loff_t pos, bool uio);
 
 /*
index 3f23b4472c3150990237a566ba2d46acb1d1aa82..6404253d810d7482a64fa9e959e99c8bad05c912 100644 (file)
@@ -44,11 +44,16 @@ extern void of_irq_init(const struct of_device_id *matches);
 
 #ifdef CONFIG_OF_IRQ
 extern int of_irq_count(struct device_node *dev);
+extern int of_irq_get(struct device_node *dev, int index);
 #else
 static inline int of_irq_count(struct device_node *dev)
 {
        return 0;
 }
+static inline int of_irq_get(struct device_node *dev, int index)
+{
+       return 0;
+}
 #endif
 
 #if defined(CONFIG_OF)
index aab57b4abe7fce4ef59adc14db6400d3a6af57cc..a95aac7ad37fd5100b3407dd79ee633a6f3a5b08 100644 (file)
@@ -680,8 +680,8 @@ struct pci_driver {
 
 /**
  * PCI_VDEVICE - macro used to describe a specific pci device in short form
- * @vendor: the vendor name
- * @device: the 16 bit PCI Device ID
+ * @vend: the vendor name
+ * @dev: the 16 bit PCI Device ID
  *
  * This macro is used to create a struct pci_device_id that matches a
  * specific PCI device.  The subvendor, and subdevice fields will be set
@@ -689,9 +689,9 @@ struct pci_driver {
  * private data.
  */
 
-#define PCI_VDEVICE(vendor, device)            \
-       PCI_VENDOR_ID_##vendor, (device),       \
-       PCI_ANY_ID, PCI_ANY_ID, 0, 0
+#define PCI_VDEVICE(vend, dev) \
+       .vendor = PCI_VENDOR_ID_##vend, .device = (dev), \
+       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0
 
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
index d4de24b4d4c64a184ff4270e2c0755f4ff59b4d6..7fa31731c8548e82f354df86571ee1189cec5f95 100644 (file)
 #define PCI_DEVICE_ID_ATT_VENUS_MODEM  0x480
 
 #define PCI_VENDOR_ID_SPECIALIX                0x11cb
-#define PCI_DEVICE_ID_SPECIALIX_IO8    0x2000
-#define PCI_DEVICE_ID_SPECIALIX_RIO    0x8000
 #define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
 
 #define PCI_VENDOR_ID_ANALOG_DEVICES   0x11d4
 #define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010
 
 #define PCI_VENDOR_ID_COMPUTONE                0x8e0e
-#define PCI_DEVICE_ID_COMPUTONE_IP2EX  0x0291
 #define PCI_DEVICE_ID_COMPUTONE_PG     0x0302
 #define PCI_SUBVENDOR_ID_COMPUTONE     0x8e0e
 #define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001
index 4d0221fd0688df5d572072d8b9f871a5637ff460..864ddafad8cc2f0697b181d9c113ca02ef715613 100644 (file)
@@ -198,6 +198,13 @@ static inline struct mii_bus *mdiobus_alloc(void)
 int mdiobus_register(struct mii_bus *bus);
 void mdiobus_unregister(struct mii_bus *bus);
 void mdiobus_free(struct mii_bus *bus);
+struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv);
+static inline struct mii_bus *devm_mdiobus_alloc(struct device *dev)
+{
+       return devm_mdiobus_alloc_size(dev, 0);
+}
+
+void devm_mdiobus_free(struct device *dev, struct mii_bus *bus);
 struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
 int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
 int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
@@ -666,6 +673,7 @@ static inline int phy_read_status(struct phy_device *phydev)
        return phydev->drv->read_status(phydev);
 }
 
+int genphy_config_init(struct phy_device *phydev);
 int genphy_setup_forced(struct phy_device *phydev);
 int genphy_restart_aneg(struct phy_device *phydev);
 int genphy_config_aneg(struct phy_device *phydev);
index f50821cb64be8c11165659b0f0719398bfa004cf..12f134b1493c40e94a743c0772b93a9b199b40fa 100644 (file)
 
 /* PaRAM slots are laid out like this */
 struct edmacc_param {
-       unsigned int opt;
-       unsigned int src;
-       unsigned int a_b_cnt;
-       unsigned int dst;
-       unsigned int src_dst_bidx;
-       unsigned int link_bcntrld;
-       unsigned int src_dst_cidx;
-       unsigned int ccnt;
-};
+       u32 opt;
+       u32 src;
+       u32 a_b_cnt;
+       u32 dst;
+       u32 src_dst_bidx;
+       u32 link_bcntrld;
+       u32 src_dst_cidx;
+       u32 ccnt;
+} __packed;
 
 /* fields in edmacc_param.opt */
 #define SAM            BIT(0)
@@ -130,7 +130,7 @@ void edma_set_src(unsigned slot, dma_addr_t src_port,
                                enum address_mode mode, enum fifo_width);
 void edma_set_dest(unsigned slot, dma_addr_t dest_port,
                                 enum address_mode mode, enum fifo_width);
-void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst);
+dma_addr_t edma_get_position(unsigned slot, bool dst);
 void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx);
 void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx);
 void edma_set_transfer_params(unsigned slot, u16 acnt, u16 bcnt, u16 ccnt,
index 6478ce3252c7d83fdd853ff2797a54d3cc591db6..9c6b9722ff48d5a2304367f5f2448a7201ea55b4 100644 (file)
@@ -1708,7 +1708,7 @@ struct security_operations {
        void (*key_free) (struct key *key);
        int (*key_permission) (key_ref_t key_ref,
                               const struct cred *cred,
-                              key_perm_t perm);
+                              unsigned perm);
        int (*key_getsecurity)(struct key *key, char **_buffer);
 #endif /* CONFIG_KEYS */
 
@@ -3034,7 +3034,7 @@ static inline int security_path_chroot(struct path *path)
 int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags);
 void security_key_free(struct key *key);
 int security_key_permission(key_ref_t key_ref,
-                           const struct cred *cred, key_perm_t perm);
+                           const struct cred *cred, unsigned perm);
 int security_key_getsecurity(struct key *key, char **_buffer);
 
 #else
@@ -3052,7 +3052,7 @@ static inline void security_key_free(struct key *key)
 
 static inline int security_key_permission(key_ref_t key_ref,
                                          const struct cred *cred,
-                                         key_perm_t perm)
+                                         unsigned perm)
 {
        return 0;
 }
index f92c0a43c54cb9ee2465e8e4c726cc1a1e630096..abdf1f229dc3d04e7197d197595fda0eac060098 100644 (file)
@@ -54,6 +54,7 @@ struct shdma_desc {
        dma_cookie_t cookie;
        int chunks;
        int mark;
+       bool cyclic;                    /* used as cyclic transfer */
 };
 
 struct shdma_chan {
index 08074a8101646d0c438415979124b3a5ff8283bb..3ca0dda5a42e8cc110af03f73cd64c141ac44f33 100644 (file)
@@ -2741,6 +2741,99 @@ static inline __sum16 skb_checksum_complete(struct sk_buff *skb)
               0 : __skb_checksum_complete(skb);
 }
 
+/* Check if we need to perform checksum complete validation.
+ *
+ * Returns true if checksum complete is needed, false otherwise
+ * (either checksum is unnecessary or zero checksum is allowed).
+ */
+static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
+                                                 bool zero_okay,
+                                                 __sum16 check)
+{
+       if (skb_csum_unnecessary(skb)) {
+               return false;
+       } else if (zero_okay && !check) {
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               return false;
+       }
+
+       return true;
+}
+
+/* For small packets <= CHECKSUM_BREAK peform checksum complete directly
+ * in checksum_init.
+ */
+#define CHECKSUM_BREAK 76
+
+/* Validate (init) checksum based on checksum complete.
+ *
+ * Return values:
+ *   0: checksum is validated or try to in skb_checksum_complete. In the latter
+ *     case the ip_summed will not be CHECKSUM_UNNECESSARY and the pseudo
+ *     checksum is stored in skb->csum for use in __skb_checksum_complete
+ *   non-zero: value of invalid checksum
+ *
+ */
+static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb,
+                                                      bool complete,
+                                                      __wsum psum)
+{
+       if (skb->ip_summed == CHECKSUM_COMPLETE) {
+               if (!csum_fold(csum_add(psum, skb->csum))) {
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       return 0;
+               }
+       }
+
+       skb->csum = psum;
+
+       if (complete || skb->len <= CHECKSUM_BREAK)
+               return __skb_checksum_complete(skb);
+
+       return 0;
+}
+
+static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       return 0;
+}
+
+/* Perform checksum validate (init). Note that this is a macro since we only
+ * want to calculate the pseudo header which is an input function if necessary.
+ * First we try to validate without any computation (checksum unnecessary) and
+ * then calculate based on checksum complete calling the function to compute
+ * pseudo header.
+ *
+ * Return values:
+ *   0: checksum is validated or try to in skb_checksum_complete
+ *   non-zero: value of invalid checksum
+ */
+#define __skb_checksum_validate(skb, proto, complete,                  \
+                               zero_okay, check, compute_pseudo)       \
+({                                                                     \
+       __sum16 __ret = 0;                                              \
+       if (__skb_checksum_validate_needed(skb, zero_okay, check))      \
+               __ret = __skb_checksum_validate_complete(skb,           \
+                               complete, compute_pseudo(skb, proto));  \
+       __ret;                                                          \
+})
+
+#define skb_checksum_init(skb, proto, compute_pseudo)                  \
+       __skb_checksum_validate(skb, proto, false, false, 0, compute_pseudo)
+
+#define skb_checksum_init_zero_check(skb, proto, check, compute_pseudo)        \
+       __skb_checksum_validate(skb, proto, false, true, check, compute_pseudo)
+
+#define skb_checksum_validate(skb, proto, compute_pseudo)              \
+       __skb_checksum_validate(skb, proto, true, false, 0, compute_pseudo)
+
+#define skb_checksum_validate_zero_check(skb, proto, check,            \
+                                        compute_pseudo)                \
+       __skb_checksum_validate_(skb, proto, true, true, check, compute_pseudo)
+
+#define skb_checksum_simple_validate(skb)                              \
+       __skb_checksum_validate(skb, 0, true, false, 0, null_compute_pseudo)
+
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 void nf_conntrack_destroy(struct nf_conntrack *nfct);
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
index 54f91d35e5fd76f13b94d8297b10be6642e07887..46cca4c06848346ca84753ac182526a4514ff277 100644 (file)
@@ -23,7 +23,7 @@ int sock_diag_check_cookie(void *sk, __u32 *cookie);
 void sock_diag_save_cookie(void *sk, __u32 *cookie);
 
 int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr);
-int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
+int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
                             struct sk_buff *skb, int attrtype);
 
 #endif
index aa327a8105ada0d2502d697c6f66699e8f8c516b..b2b1afbb32024ebbb80be196ea276a7ff53ae43e 100644 (file)
@@ -26,20 +26,6 @@ struct at86rf230_platform_data {
        int rstn;
        int slp_tr;
        int dig2;
-
-       /* Setting the irq_type will configure the driver to request
-        * the platform irq trigger type according to the given value
-        * and configure the interrupt polarity of the device to the
-        * corresponding polarity.
-        *
-        * Allowed values are: IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING,
-        *                     IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW
-        *
-        * Setting it to 0, the driver does not touch the trigger type
-        * configuration of the interrupt and sets the interrupt polarity
-        * of the device to high active (the default value).
-        */
-       int irq_type;
 };
 
 #endif
index 0e43906d2fda6dc68cffc6343594178465d6e461..da2751d3b93db503b5572b27e97a0e7cc516fc91 100644 (file)
@@ -70,16 +70,6 @@ extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *,
                                splice_actor *);
 extern ssize_t __splice_from_pipe(struct pipe_inode_info *,
                                  struct splice_desc *, splice_actor *);
-extern int splice_from_pipe_feed(struct pipe_inode_info *, struct splice_desc *,
-                                splice_actor *);
-extern int splice_from_pipe_next(struct pipe_inode_info *,
-                                struct splice_desc *);
-extern void splice_from_pipe_begin(struct splice_desc *);
-extern void splice_from_pipe_end(struct pipe_inode_info *,
-                                struct splice_desc *);
-extern int pipe_to_file(struct pipe_inode_info *, struct pipe_buffer *,
-                       struct splice_desc *);
-
 extern ssize_t splice_to_pipe(struct pipe_inode_info *,
                              struct splice_pipe_desc *);
 extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
index f73cabf59012f1ead45eee1eb7aa97600b1bb902..38bbf95109daba438a85675dfac74822ab265d24 100644 (file)
@@ -320,6 +320,8 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
 extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
 extern int hibernate(void);
 extern bool system_entering_hibernation(void);
+asmlinkage int swsusp_save(void);
+extern struct pbe *restore_pblist;
 #else /* CONFIG_HIBERNATION */
 static inline void register_nosave_region(unsigned long b, unsigned long e) {}
 static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
index 239946868142cec2893e89259555d3b86884d616..4e37c71ecd746c63f69dc5119df9e9d393734bd7 100644 (file)
@@ -230,6 +230,7 @@ struct tcp_sock {
        u32     snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */
        u32     snd_cwnd_used;
        u32     snd_cwnd_stamp;
+       u32     lsnd_pending;   /* packets inflight or unsent since last xmit */
        u32     prior_cwnd;     /* Congestion window at start of Recovery. */
        u32     prr_delivered;  /* Number of newly delivered packets to
                                 * receiver in Recovery. */
index 036cccd80d9ffa0c6c1a356fff4a53418643b7ae..1c3316a47d7e0386d1ede163c4f795275efc8130 100644 (file)
@@ -61,7 +61,6 @@ struct tty_bufhead {
        struct tty_buffer *head;        /* Queue head */
        struct work_struct work;
        struct mutex       lock;
-       spinlock_t         flush_lock;
        atomic_t           priority;
        struct tty_buffer sentinel;
        struct llist_head free;         /* Free queue head */
index 199bcc34241ba0155a367f11d05edf5d9c138a02..e2231e47cec131f8de84459568b11aa6d294f62d 100644 (file)
@@ -19,11 +19,21 @@ struct kvec {
        size_t iov_len;
 };
 
+enum {
+       ITER_IOVEC = 0,
+       ITER_KVEC = 2,
+       ITER_BVEC = 4,
+};
+
 struct iov_iter {
-       const struct iovec *iov;
-       unsigned long nr_segs;
+       int type;
        size_t iov_offset;
        size_t count;
+       union {
+               const struct iovec *iov;
+               const struct bio_vec *bvec;
+       };
+       unsigned long nr_segs;
 };
 
 /*
@@ -53,6 +63,7 @@ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter)
 }
 
 #define iov_for_each(iov, iter, start)                         \
+       if (!((start).type & ITER_BVEC))                        \
        for (iter = (start);                                    \
             (iter).count &&                                    \
             ((iov = iov_iter_iovec(&(iter))), 1);              \
@@ -62,32 +73,44 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to);
 
 size_t iov_iter_copy_from_user_atomic(struct page *page,
                struct iov_iter *i, unsigned long offset, size_t bytes);
-size_t iov_iter_copy_from_user(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes);
 void iov_iter_advance(struct iov_iter *i, size_t bytes);
 int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
 size_t iov_iter_single_seg_count(const struct iov_iter *i);
 size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i);
+size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i);
+unsigned long iov_iter_alignment(const struct iov_iter *i);
+void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov,
+                       unsigned long nr_segs, size_t count);
+ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
+                       size_t maxsize, size_t *start);
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
+                       size_t maxsize, size_t *start);
+int iov_iter_npages(const struct iov_iter *i, int maxpages);
 
-static inline void iov_iter_init(struct iov_iter *i,
-                       const struct iovec *iov, unsigned long nr_segs,
-                       size_t count, size_t written)
+static inline size_t iov_iter_count(struct iov_iter *i)
 {
-       i->iov = iov;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count + written;
+       return i->count;
+}
 
-       iov_iter_advance(i, written);
+static inline void iov_iter_truncate(struct iov_iter *i, size_t count)
+{
+       if (i->count > count)
+               i->count = count;
 }
 
-static inline size_t iov_iter_count(struct iov_iter *i)
+/*
+ * reexpand a previously truncated iterator; count must be no more than how much
+ * we had shrunk it.
+ */
+static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
 {
-       return i->count;
+       i->count = count;
 }
 
 int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
 int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len);
 
+
 #endif
index e4abb84199bea7599940a4fe4ee026ee40f6a48d..b46671e28de29a39d52810e2d51ca36562692889 100644 (file)
@@ -106,6 +106,8 @@ static inline struct virtio_device *dev_to_virtio(struct device *_dev)
 int register_virtio_device(struct virtio_device *dev);
 void unregister_virtio_device(struct virtio_device *dev);
 
+void virtio_break_device(struct virtio_device *dev);
+
 /**
  * virtio_driver - operations for a virtio I/O driver
  * @driver: underlying device driver (populate name and owner).
index f7d372b7d4ff672d79a6ce16c437e016449cba4e..79b530fb2c4dd40205595d73831846e5ee56c7ac 100644 (file)
@@ -54,6 +54,7 @@
 #define __6LOWPAN_H__
 
 #include <net/ipv6.h>
+#include <net/net_namespace.h>
 
 #define UIP_802154_SHORTADDR_LEN       2  /* compressed ipv6 address length */
 #define UIP_IPH_LEN                    40 /* ipv6 fixed header size */
index 933a9f22a05ff63abb4379f94cb907c95f6beac4..f679877bb6017dd4a6da7d1fe0e6ea217ba3b3e4 100644 (file)
@@ -306,11 +306,6 @@ static inline void addrconf_addr_solict_mult(const struct in6_addr *addr,
                      htonl(0xFF000000) | addr->s6_addr32[3]);
 }
 
-static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr)
-{
-       return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000);
-}
-
 static inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
 {
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
index 7d64d3609ec97ea76751009e82d43c38a10ab5d8..4282778694006034bccca4ce3fbeba9be29537ec 100644 (file)
@@ -155,7 +155,11 @@ struct vsock_transport {
 
 /**** CORE ****/
 
-int vsock_core_init(const struct vsock_transport *t);
+int __vsock_core_init(const struct vsock_transport *t, struct module *owner);
+static inline int vsock_core_init(const struct vsock_transport *t)
+{
+       return __vsock_core_init(t, THIS_MODULE);
+}
 void vsock_core_exit(void);
 
 /**** UTILS ****/
index be150cf8cd432298d47860268a1d4566af74481d..4261a67682c032f84da321987e30ee97f510ffa8 100644 (file)
@@ -367,6 +367,7 @@ enum {
 #define HCI_ERROR_REMOTE_POWER_OFF     0x15
 #define HCI_ERROR_LOCAL_HOST_TERM      0x16
 #define HCI_ERROR_PAIRING_NOT_ALLOWED  0x18
+#define HCI_ERROR_ADVERTISING_TIMEOUT  0x3c
 
 /* Flow control modes */
 #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
index 5f8bc05694ac665159bb25f7a9eaa704c3784e91..d73f41855ada2cbb7ce9dfc61c72cd9b592083ca 100644 (file)
@@ -68,6 +68,11 @@ struct discovery_state {
        struct list_head        unknown;        /* Name state not known */
        struct list_head        resolve;        /* Name needs to be resolved */
        __u32                   timestamp;
+       bdaddr_t                last_adv_addr;
+       u8                      last_adv_addr_type;
+       s8                      last_adv_rssi;
+       u8                      last_adv_data[HCI_MAX_AD_LENGTH];
+       u8                      last_adv_data_len;
 };
 
 struct hci_conn_hash {
@@ -194,6 +199,7 @@ struct hci_dev {
        __u16           le_scan_window;
        __u16           le_conn_min_interval;
        __u16           le_conn_max_interval;
+       __u16           discov_interleaved_timeout;
        __u8            ssp_debug_mode;
 
        __u16           devid_source;
@@ -1204,8 +1210,8 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
  */
 #define DISCOV_LE_SCAN_WIN             0x12
 #define DISCOV_LE_SCAN_INT             0x12
-#define DISCOV_LE_TIMEOUT              msecs_to_jiffies(10240)
-#define DISCOV_INTERLEAVED_TIMEOUT     msecs_to_jiffies(5120)
+#define DISCOV_LE_TIMEOUT              10240   /* msec */
+#define DISCOV_INTERLEAVED_TIMEOUT     5120    /* msec */
 #define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04
 #define DISCOV_BREDR_INQUIRY_LEN       0x08
 
@@ -1265,7 +1271,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
                                       u8 *randomizer256, u8 status);
 void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                       u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
-                      u8 ssp, u8 *eir, u16 eir_len);
+                      u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
+                      u8 scan_rsp_len);
 void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                      u8 addr_type, s8 rssi, u8 *name, u8 name_len);
 void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
index f3539a15c41103b743c0571913fbb93dc402f40a..7eae46ccec01a4f8c2800c8b459ac5a370ed93e9 100644 (file)
@@ -109,6 +109,13 @@ enum ieee80211_band {
  *     channel as the control or any of the secondary channels.
  *     This may be due to the driver or due to regulatory bandwidth
  *     restrictions.
+ * @IEEE80211_CHAN_INDOOR_ONLY: see %NL80211_FREQUENCY_ATTR_INDOOR_ONLY
+ * @IEEE80211_CHAN_GO_CONCURRENT: see %NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @IEEE80211_CHAN_NO_20MHZ: 20 MHz bandwidth is not permitted
+ *     on this channel.
+ * @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
+ *     on this channel.
+ *
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
@@ -120,6 +127,10 @@ enum ieee80211_channel_flags {
        IEEE80211_CHAN_NO_OFDM          = 1<<6,
        IEEE80211_CHAN_NO_80MHZ         = 1<<7,
        IEEE80211_CHAN_NO_160MHZ        = 1<<8,
+       IEEE80211_CHAN_INDOOR_ONLY      = 1<<9,
+       IEEE80211_CHAN_GO_CONCURRENT    = 1<<10,
+       IEEE80211_CHAN_NO_20MHZ         = 1<<11,
+       IEEE80211_CHAN_NO_10MHZ         = 1<<12,
 };
 
 #define IEEE80211_CHAN_NO_HT40 \
@@ -441,10 +452,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
  * cfg80211_chandef_dfs_required - checks if radar detection is required
  * @wiphy: the wiphy to validate against
  * @chandef: the channel definition to check
- * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
+ * @iftype: the interface type as specified in &enum nl80211_iftype
+ * Returns:
+ *     1 if radar detection is required, 0 if it is not, < 0 on error
  */
 int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-                                 const struct cfg80211_chan_def *chandef);
+                                 const struct cfg80211_chan_def *chandef,
+                                 enum nl80211_iftype);
 
 /**
  * ieee80211_chandef_rate_flags - returns rate flags for a channel
@@ -654,7 +668,6 @@ struct cfg80211_acl_data {
  * @p2p_opp_ps: P2P opportunistic PS
  * @acl: ACL configuration used by the drivers which has support for
  *     MAC address based access control
- * @radar_required: set if radar detection is required
  */
 struct cfg80211_ap_settings {
        struct cfg80211_chan_def chandef;
@@ -672,7 +685,6 @@ struct cfg80211_ap_settings {
        u8 p2p_ctwindow;
        bool p2p_opp_ps;
        const struct cfg80211_acl_data *acl;
-       bool radar_required;
 };
 
 /**
@@ -2278,6 +2290,10 @@ struct cfg80211_qos_map {
  * @channel_switch: initiate channel-switch procedure (with CSA)
  *
  * @set_qos_map: Set QoS mapping information to the driver
+ *
+ * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the
+ *     given interface This is used e.g. for dynamic HT 20/40 MHz channel width
+ *     changes during the lifetime of the BSS.
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2521,9 +2537,13 @@ struct cfg80211_ops {
        int     (*channel_switch)(struct wiphy *wiphy,
                                  struct net_device *dev,
                                  struct cfg80211_csa_settings *params);
+
        int     (*set_qos_map)(struct wiphy *wiphy,
                               struct net_device *dev,
                               struct cfg80211_qos_map *qos_map);
+
+       int     (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
+                                   struct cfg80211_chan_def *chandef);
 };
 
 /*
@@ -3194,6 +3214,7 @@ struct cfg80211_cached_keys;
  * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
  * @event_list: (private) list for internal event processing
  * @event_lock: (private) lock for event list
+ * @owner_nlportid: (private) owner socket port ID
  */
 struct wireless_dev {
        struct wiphy *wiphy;
@@ -3241,6 +3262,8 @@ struct wireless_dev {
        unsigned long cac_start_time;
        unsigned int cac_time_ms;
 
+       u32 owner_nlportid;
+
 #ifdef CONFIG_CFG80211_WEXT
        /* wext data */
        struct {
@@ -3600,7 +3623,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
  * default channel settings will be disregarded. If no rule is found for a
  * channel on the regulatory domain the channel will be disabled.
  * Drivers using this for a wiphy should also set the wiphy flag
- * WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy
+ * REGULATORY_CUSTOM_REG or cfg80211 will set it for the wiphy
  * that called this helper.
  */
 void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
@@ -4531,12 +4554,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
  * cfg80211_reg_can_beacon - check if beaconing is allowed
  * @wiphy: the wiphy
  * @chandef: the channel definition
+ * @iftype: interface type
  *
  * Return: %true if there is no secondary channel or the secondary channel(s)
  * can be used for beaconing (i.e. is not a radar channel etc.)
  */
 bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
-                            struct cfg80211_chan_def *chandef);
+                            struct cfg80211_chan_def *chandef,
+                            enum nl80211_iftype iftype);
 
 /*
  * cfg80211_ch_switch_notify - update wdev channel and notify userspace
@@ -4682,6 +4707,55 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
  */
 unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
 
+/**
+ * cfg80211_check_combinations - check interface combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *     to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *     width where radar detection is needed, as in the definition of
+ *     &struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *     type.  The index is the interface type as specified in &enum
+ *     nl80211_iftype.
+ *
+ * This function can be called by the driver to check whether a
+ * combination of interfaces and their types are allowed according to
+ * the interface combinations.
+ */
+int cfg80211_check_combinations(struct wiphy *wiphy,
+                               const int num_different_channels,
+                               const u8 radar_detect,
+                               const int iftype_num[NUM_NL80211_IFTYPES]);
+
+/**
+ * cfg80211_iter_combinations - iterate over matching combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *     to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *     width where radar detection is needed, as in the definition of
+ *     &struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *     type.  The index is the interface type as specified in &enum
+ *     nl80211_iftype.
+ * @iter: function to call for each matching combination
+ * @data: pointer to pass to iter function
+ *
+ * This function can be called by the driver to check what possible
+ * combinations it fits in at a given moment, e.g. for channel switching
+ * purposes.
+ */
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+                              const int num_different_channels,
+                              const u8 radar_detect,
+                              const int iftype_num[NUM_NL80211_IFTYPES],
+                              void (*iter)(const struct ieee80211_iface_combination *c,
+                                           void *data),
+                              void *data);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index a28f4e0f625193b0682932207a46578f094f52a9..87cb1903640d63ccfed890c957294af46a93cf24 100644 (file)
@@ -57,12 +57,14 @@ static __inline__ __wsum csum_and_copy_to_user
 }
 #endif
 
+#ifndef HAVE_ARCH_CSUM_ADD
 static inline __wsum csum_add(__wsum csum, __wsum addend)
 {
        u32 res = (__force u32)csum;
        res += (__force u32)addend;
        return (__force __wsum)(res + (res < (__force u32)addend));
 }
+#endif
 
 static inline __wsum csum_sub(__wsum csum, __wsum addend)
 {
index 7828ebf99ee132241b76e500681a43188143da99..6efce384451e56f16d8aab0847a6a7be4e94e0a0 100644 (file)
@@ -181,6 +181,11 @@ struct dsa_switch_driver {
 void register_switch_driver(struct dsa_switch_driver *type);
 void unregister_switch_driver(struct dsa_switch_driver *type);
 
+static inline void *ds_to_priv(struct dsa_switch *ds)
+{
+       return (void *)(ds + 1);
+}
+
 /*
  * The original DSA tag format and some other tag formats have no
  * ethertype, which means that we need to add a little hack to the
index 3ec2b0fb9d8395384373917691f49c433262a8db..1988cefdbb707f9c55ddba7d95f1f1e46b437743 100644 (file)
@@ -342,6 +342,12 @@ static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *d
                __ip_select_ident(iph, dst, more);
 }
 
+static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       return csum_tcpudp_nofold(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
+                                 skb->len, proto, 0);
+}
+
 /*
  *     Map a multicast IP onto multicast MAC for type ethernet.
  */
index 9e3c540c1b110c71b65003a6aac22cc6c333be5a..8ac5c21f84563faeda028606034f2c69d23dc2a6 100644 (file)
@@ -41,6 +41,13 @@ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
                        __wsum csum);
 #endif
 
+static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       return ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                           &ipv6_hdr(skb)->daddr,
+                                           skb->len, proto, 0));
+}
+
 static __inline__ __sum16 tcp_v6_check(int len,
                                   const struct in6_addr *saddr,
                                   const struct in6_addr *daddr,
index d640925bc4543bdfb30bf15d164bececbda7e798..5b40ad297b8ce22c64aa44d70a75f86244a3ea13 100644 (file)
@@ -583,6 +583,11 @@ static inline bool ipv6_addr_orchid(const struct in6_addr *a)
        return (a->s6_addr32[0] & htonl(0xfffffff0)) == htonl(0x20010010);
 }
 
+static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr)
+{
+       return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000);
+}
+
 static inline void ipv6_addr_set_v4mapped(const __be32 addr,
                                          struct in6_addr *v4mapped)
 {
@@ -664,6 +669,20 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
 
 int ip6_dst_hoplimit(struct dst_entry *dst);
 
+static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
+                                     struct dst_entry *dst)
+{
+       int hlimit;
+
+       if (ipv6_addr_is_multicast(&fl6->daddr))
+               hlimit = np->mcast_hops;
+       else
+               hlimit = np->hop_limit;
+       if (hlimit < 0)
+               hlimit = ip6_dst_hoplimit(dst);
+       return hlimit;
+}
+
 /*
  *     Header manipulation
  */
index 8248e3909fdf7d8531890e15bc3f18c5b90ac95f..451c1bf00df93317a358d4576ebee0c423828889 100644 (file)
@@ -1202,14 +1202,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  *     fall back to software crypto. Note that this flag deals only with
  *     RX, if your crypto engine can't deal with TX you can also set the
  *     %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW.
+ * @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the
+ *     driver for a CCMP key to indicate that is requires IV generation
+ *     only for managment frames (MFP).
  */
 enum ieee80211_key_flags {
-       IEEE80211_KEY_FLAG_GENERATE_IV  = 1<<1,
-       IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
-       IEEE80211_KEY_FLAG_PAIRWISE     = 1<<3,
-       IEEE80211_KEY_FLAG_SW_MGMT_TX   = 1<<4,
-       IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5,
-       IEEE80211_KEY_FLAG_RX_MGMT      = 1<<6,
+       IEEE80211_KEY_FLAG_GENERATE_IV_MGMT     = BIT(0),
+       IEEE80211_KEY_FLAG_GENERATE_IV          = BIT(1),
+       IEEE80211_KEY_FLAG_GENERATE_MMIC        = BIT(2),
+       IEEE80211_KEY_FLAG_PAIRWISE             = BIT(3),
+       IEEE80211_KEY_FLAG_SW_MGMT_TX           = BIT(4),
+       IEEE80211_KEY_FLAG_PUT_IV_SPACE         = BIT(5),
+       IEEE80211_KEY_FLAG_RX_MGMT              = BIT(6),
 };
 
 /**
@@ -1555,6 +1559,12 @@ struct ieee80211_tx_control {
  *     for a single active channel while using channel contexts. When support
  *     is not enabled the default action is to disconnect when getting the
  *     CSA frame.
+ *
+ * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
+ *     channel context on-the-fly.  This is needed for channel switch
+ *     on single-channel hardware.  It can also be used as an
+ *     optimization in certain channel switch cases with
+ *     multi-channel.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
@@ -1586,6 +1596,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_TIMING_BEACON_ONLY                 = 1<<26,
        IEEE80211_HW_SUPPORTS_HT_CCK_RATES              = 1<<27,
        IEEE80211_HW_CHANCTX_STA_CSA                    = 1<<28,
+       IEEE80211_HW_CHANGE_RUNNING_CHANCTX             = 1<<29,
 };
 
 /**
@@ -2609,6 +2620,7 @@ enum ieee80211_roc_type {
  *     of queues to flush, which is useful if different virtual interfaces
  *     use different hardware queues; it may also indicate all queues.
  *     If the parameter @drop is set to %true, pending frames may be dropped.
+ *     Note that vif can be NULL.
  *     The callback can sleep.
  *
  * @channel_switch: Drivers that need (or want) to offload the channel
@@ -2871,7 +2883,8 @@ struct ieee80211_ops {
                             struct netlink_callback *cb,
                             void *data, int len);
 #endif
-       void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
+       void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                     u32 queues, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
                               struct ieee80211_channel_switch *ch_switch);
        int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
@@ -4576,7 +4589,9 @@ conf_is_ht40(struct ieee80211_conf *conf)
 static inline bool
 conf_is_ht(struct ieee80211_conf *conf)
 {
-       return conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
+       return (conf->chandef.width != NL80211_CHAN_WIDTH_5) &&
+               (conf->chandef.width != NL80211_CHAN_WIDTH_10) &&
+               (conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT);
 }
 
 static inline enum nl80211_iftype
index 5f9eb260990f6507d61f42d2463d45455346e812..361d26077196678af5bd7ce217715a2cc847f2af 100644 (file)
@@ -373,6 +373,14 @@ static inline void rt_genid_bump_ipv6(struct net *net)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN)
+static inline struct netns_ieee802154_lowpan *
+net_ieee802154_lowpan(struct net *net)
+{
+       return &net->ieee802154_lowpan;
+}
+#endif
+
 /* For callers who don't really care about whether it's IPv4 or IPv6 */
 static inline void rt_genid_bump_all(struct net *net)
 {
index a2441fb1428f3f2e181df63319ca2b3fdc15dc4e..6da46dcf1049789f492cefd9472d0df84d4db91d 100644 (file)
@@ -136,7 +136,7 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
 
 int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
                      struct nlattr **tb, struct nlattr *rate_tlv,
-                     struct tcf_exts *exts);
+                     struct tcf_exts *exts, bool ovr);
 void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts);
 void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
                     struct tcf_exts *src);
index 75fc1f5a948d685fcfff12e04cc6b85e194cd541..259992444e80ae0b88eaec4ff345d23fd8f81c75 100644 (file)
@@ -131,6 +131,11 @@ struct regulatory_request {
  *     all country IE information processed by the regulatory core. This will
  *     override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will
  *     be ignored.
+ * @REGULATORY_ENABLE_RELAX_NO_IR: for devices that wish to allow the
+ *      NO_IR relaxation, which enables transmissions on channels on which
+ *      otherwise initiating radiation is not allowed. This will enable the
+ *      relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
+ *      option
  */
 enum ieee80211_regulatory_flags {
        REGULATORY_CUSTOM_REG                   = BIT(0),
@@ -138,6 +143,7 @@ enum ieee80211_regulatory_flags {
        REGULATORY_DISABLE_BEACON_HINTS         = BIT(2),
        REGULATORY_COUNTRY_IE_FOLLOW_POWER      = BIT(3),
        REGULATORY_COUNTRY_IE_IGNORE            = BIT(4),
+       REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
 };
 
 struct ieee80211_freq_range {
index d062f81c692f1ee3e61ba1a06bd27e3a9edb761a..624f9857c83e3d7f2987ef95ecc410ad6f8c744f 100644 (file)
@@ -199,7 +199,7 @@ struct tcf_proto_ops {
        int                     (*change)(struct net *net, struct sk_buff *,
                                        struct tcf_proto*, unsigned long,
                                        u32 handle, struct nlattr **,
-                                       unsigned long *);
+                                       unsigned long *, bool);
        int                     (*delete)(struct tcf_proto*, unsigned long);
        void                    (*walk)(struct tcf_proto*, struct tcf_walker *arg);
 
index 8338a14e48053d853a57af674f7edca1e085fdc5..21569cf456ed54459a537e5a6cf02349a2a8413c 100644 (file)
@@ -2255,6 +2255,11 @@ int sock_get_timestampns(struct sock *, struct timespec __user *);
 int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level,
                       int type);
 
+bool sk_ns_capable(const struct sock *sk,
+                  struct user_namespace *user_ns, int cap);
+bool sk_capable(const struct sock *sk, int cap);
+bool sk_net_capable(const struct sock *sk, int cap);
+
 /*
  *     Enable debug/info messages
  */
index 87d87740818867b8b50074c8a5634658be46199c..3c94184566408188a35517af671c2d6511a64ecf 100644 (file)
@@ -558,7 +558,6 @@ void tcp_send_loss_probe(struct sock *sk);
 bool tcp_schedule_loss_probe(struct sock *sk);
 
 /* tcp_input.c */
-void tcp_cwnd_application_limited(struct sock *sk);
 void tcp_resume_early_retransmit(struct sock *sk);
 void tcp_rearm_rto(struct sock *sk);
 void tcp_reset(struct sock *sk);
@@ -797,7 +796,7 @@ struct tcp_congestion_ops {
        /* return slow start threshold (required) */
        u32 (*ssthresh)(struct sock *sk);
        /* do new cwnd calculation (required) */
-       void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked, u32 in_flight);
+       void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked);
        /* call before changing ca_state (optional) */
        void (*set_state)(struct sock *sk, u8 new_state);
        /* call when cwnd event occurs (optional) */
@@ -829,7 +828,7 @@ void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w);
 
 extern struct tcp_congestion_ops tcp_init_congestion_ops;
 u32 tcp_reno_ssthresh(struct sock *sk);
-void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight);
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked);
 extern struct tcp_congestion_ops tcp_reno;
 
 static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state)
@@ -975,7 +974,25 @@ static inline u32 tcp_wnd_end(const struct tcp_sock *tp)
 {
        return tp->snd_una + tp->snd_wnd;
 }
-bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight);
+
+/* We follow the spirit of RFC2861 to validate cwnd but implement a more
+ * flexible approach. The RFC suggests cwnd should not be raised unless
+ * it was fully used previously. But we allow cwnd to grow as long as the
+ * application has used half the cwnd.
+ * Example :
+ *    cwnd is 10 (IW10), but application sends 9 frames.
+ *    We allow cwnd to reach 18 when all frames are ACKed.
+ * This check is safe because it's as aggressive as slow start which already
+ * risks 100% overshoot. The advantage is that we discourage application to
+ * either send more filler packets or data to artificially blow up the cwnd
+ * usage, and allow application-limited process to probe bw more aggressively.
+ */
+static inline bool tcp_is_cwnd_limited(const struct sock *sk)
+{
+       const struct tcp_sock *tp = tcp_sk(sk);
+
+       return tp->snd_cwnd < 2 * tp->lsnd_pending;
+}
 
 static inline void tcp_check_probe_timer(struct sock *sk)
 {
index 5deef1ae78c964608d629d29d5628dfef52fdf6e..7bb4084b1bd0c036250e002c59ef35613db3aad7 100644 (file)
@@ -33,7 +33,7 @@ void vxlan_sock_release(struct vxlan_sock *vs);
 int vxlan_xmit_skb(struct vxlan_sock *vs,
                   struct rtable *rt, struct sk_buff *skb,
                   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
-                  __be16 src_port, __be16 dst_port, __be32 vni);
+                  __be16 src_port, __be16 dst_port, __be32 vni, bool xnet);
 
 __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb);
 
index 116e9c7e19cbbe00272bbf4adc6de7681b0c27ee..721e9c3b11bddb208927852d223a36f548a3cade 100644 (file)
@@ -691,13 +691,6 @@ struct xfrm_spi_skb_cb {
 
 #define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0]))
 
-/* Audit Information */
-struct xfrm_audit {
-       u32     secid;
-       kuid_t  loginuid;
-       unsigned int sessionid;
-};
-
 #ifdef CONFIG_AUDITSYSCALL
 static inline struct audit_buffer *xfrm_audit_start(const char *op)
 {
@@ -713,30 +706,24 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
        return audit_buf;
 }
 
-static inline void xfrm_audit_helper_usrinfo(kuid_t auid, unsigned int ses, u32 secid,
+static inline void xfrm_audit_helper_usrinfo(bool task_valid,
                                             struct audit_buffer *audit_buf)
 {
-       char *secctx;
-       u32 secctx_len;
-
-       audit_log_format(audit_buf, " auid=%u ses=%u",
-                        from_kuid(&init_user_ns, auid), ses);
-       if (secid != 0 &&
-           security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) {
-               audit_log_format(audit_buf, " subj=%s", secctx);
-               security_release_secctx(secctx, secctx_len);
-       } else
-               audit_log_task_context(audit_buf);
-}
-
-void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, kuid_t auid,
-                          unsigned int ses, u32 secid);
-void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, kuid_t auid,
-                             unsigned int ses, u32 secid);
-void xfrm_audit_state_add(struct xfrm_state *x, int result, kuid_t auid,
-                         unsigned int ses, u32 secid);
-void xfrm_audit_state_delete(struct xfrm_state *x, int result, kuid_t auid,
-                            unsigned int ses, u32 secid);
+       const unsigned int auid = from_kuid(&init_user_ns, task_valid ?
+                                           audit_get_loginuid(current) :
+                                           INVALID_UID);
+       const unsigned int ses = task_valid ? audit_get_sessionid(current) :
+               (unsigned int) -1;
+
+       audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
+       audit_log_task_context(audit_buf);
+}
+
+void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid);
+void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
+                             bool task_valid);
+void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid);
+void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid);
 void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
                                      struct sk_buff *skb);
 void xfrm_audit_state_replay(struct xfrm_state *x, struct sk_buff *skb,
@@ -749,22 +736,22 @@ void xfrm_audit_state_icvfail(struct xfrm_state *x, struct sk_buff *skb,
 #else
 
 static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
-                                 kuid_t auid, unsigned int ses, u32 secid)
+                                        bool task_valid)
 {
 }
 
 static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
-                                 kuid_t auid, unsigned int ses, u32 secid)
+                                           bool task_valid)
 {
 }
 
 static inline void xfrm_audit_state_add(struct xfrm_state *x, int result,
-                                kuid_t auid, unsigned int ses, u32 secid)
+                                       bool task_valid)
 {
 }
 
 static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result,
-                                   kuid_t auid, unsigned int ses, u32 secid)
+                                          bool task_valid)
 {
 }
 
@@ -1508,7 +1495,7 @@ struct xfrmk_spdinfo {
 
 struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
 int xfrm_state_delete(struct xfrm_state *x);
-int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info);
+int xfrm_state_flush(struct net *net, u8 proto, bool task_valid);
 void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
 void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
 u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
@@ -1603,7 +1590,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
                                          int *err);
 struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
                                     u32 id, int delete, int *err);
-int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info);
+int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
 u32 xfrm_get_acqseq(void);
 int verify_spi_info(u8 proto, u32 min, u32 max);
 int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
index e6aabdb458653ff2b817c7a5b1e87c15048085a4..00e6c289a9363c14caeed87c739e68c5f73d0a11 100644 (file)
@@ -23,7 +23,6 @@
  * @reset_pin: GPIO pin wired to the reset input on the external AC97 codec,
  *             optional to use, set to -ENODEV if not in use. AC97 layer will
  *             try to do a software reset of the external codec anyway.
- * @flags: Flags for which directions should be enabled.
  *
  * If the user do not want to use a DMA channel for playback or capture, i.e.
  * only one feature is required on the board. The slave for playback or capture
@@ -33,7 +32,6 @@
 struct ac97c_platform_data {
        struct dw_dma_slave     rx_dws;
        struct dw_dma_slave     tx_dws;
-       unsigned int            flags;
        int                     reset_pin;
 };
 
index 27cc75ed67f87a321b21b0cd247cad0ab6b371cf..59d26dd81e45333e1730910a30493df4480059d5 100644 (file)
@@ -16,6 +16,10 @@ struct rt5640_platform_data {
        bool in1_diff;
        bool in2_diff;
 
+       bool dmic_en;
+       bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */
+       bool dmic2_data_pin; /* 0 = IN1N; 1 = GPIO4 */
+
        int ldo1_en; /* GPIO for LDO1_EN */
 };
 
diff --git a/include/sound/rt5651.h b/include/sound/rt5651.h
new file mode 100644 (file)
index 0000000..d35de75
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * linux/sound/rt286.h -- Platform data for RT286
+ *
+ * Copyright 2013 Realtek Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_RT5651_H
+#define __LINUX_SND_RT5651_H
+
+struct rt5651_platform_data {
+       /* IN2 can optionally be differential */
+       bool in2_diff;
+
+       bool dmic_en;
+};
+
+#endif
index ef78f562f4a88b1c63bd3e6c4a19cc223fdf50f1..b041fc6778517d5cc8992fafeffcef365538cffc 100644 (file)
@@ -107,10 +107,6 @@ struct device;
 {      .id = snd_soc_dapm_mux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
-#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
-       SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
-#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
-       SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
@@ -166,10 +162,6 @@ struct device;
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
-#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
-       wevent, wflags) \
-       SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, wevent, \
-               wflags)
 
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
@@ -305,16 +297,12 @@ struct device;
        .get = snd_soc_dapm_get_enum_double, \
        .put = snd_soc_dapm_put_enum_double, \
        .private_value = (unsigned long)&xenum }
-#define SOC_DAPM_ENUM_VIRT(xname, xenum) \
-       SOC_DAPM_ENUM(xname, xenum)
 #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
        .get = xget, \
        .put = xput, \
        .private_value = (unsigned long)&xenum }
-#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
-       SOC_DAPM_ENUM(xname, xenum)
 #define SOC_DAPM_PIN_SWITCH(xname) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \
        .info = snd_soc_dapm_info_pin_switch, \
@@ -606,6 +594,7 @@ struct snd_soc_dapm_context {
                             enum snd_soc_dapm_type, int);
 
        struct device *dev; /* from parent - for debug */
+       struct snd_soc_component *component; /* parent component */
        struct snd_soc_codec *codec; /* parent codec */
        struct snd_soc_platform *platform; /* parent platform */
        struct snd_soc_card *card; /* parent card */
index 0b83168d8ff45a2ff394057ef0d172ab783f84d8..f83208d6bbe37d6525bd9242ca4baea044ea698c 100644 (file)
        .info = snd_soc_info_enum_double, \
        .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
        .private_value = (unsigned long)&xenum }
-#define SOC_VALUE_ENUM(xname, xenum) \
-       SOC_ENUM(xname, xenum)
 #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
                {.base = xbase, .num_regs = xregs,            \
                 .mask = xmask }) }
 
+#define SND_SOC_BYTES_EXT(xname, xcount, xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_bytes_info_ext, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct soc_bytes_ext) \
+               {.max = xcount} }
+
 #define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \
                xmin, xmax, xinvert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -377,6 +382,8 @@ int snd_soc_resume(struct device *dev);
 int snd_soc_poweroff(struct device *dev);
 int snd_soc_register_platform(struct device *dev,
                const struct snd_soc_platform_driver *platform_drv);
+int devm_snd_soc_register_platform(struct device *dev,
+               const struct snd_soc_platform_driver *platform_drv);
 void snd_soc_unregister_platform(struct device *dev);
 int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
                const struct snd_soc_platform_driver *platform_drv);
@@ -393,14 +400,6 @@ int devm_snd_soc_register_component(struct device *dev,
                         const struct snd_soc_component_driver *cmpnt_drv,
                         struct snd_soc_dai_driver *dai_drv, int num_dai);
 void snd_soc_unregister_component(struct device *dev);
-int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
-                                   unsigned int reg);
-int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg);
-int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg);
-int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              struct regmap *regmap);
 int snd_soc_cache_sync(struct snd_soc_codec *codec);
 int snd_soc_cache_init(struct snd_soc_codec *codec);
 int snd_soc_cache_exit(struct snd_soc_codec *codec);
@@ -469,12 +468,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
 #endif
 
 /* codec register bit access */
-int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
                                unsigned int mask, unsigned int value);
 int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
-                              unsigned short reg, unsigned int mask,
+                              unsigned int reg, unsigned int mask,
                               unsigned int value);
-int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
                                unsigned int mask, unsigned int value);
 
 int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
@@ -540,6 +539,8 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol);
 int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol);
+int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *ucontrol);
 int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
@@ -668,6 +669,7 @@ struct snd_soc_component {
        unsigned int active;
 
        unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
+       unsigned int registered_as_component:1;
 
        struct list_head list;
 
@@ -677,6 +679,14 @@ struct snd_soc_component {
        const struct snd_soc_component_driver *driver;
 
        struct list_head dai_list;
+
+       int (*read)(struct snd_soc_component *, unsigned int, unsigned int *);
+       int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
+
+       struct regmap *regmap;
+       int val_bytes;
+
+       struct mutex io_mutex;
 };
 
 /* SoC Audio Codec device */
@@ -692,9 +702,6 @@ struct snd_soc_codec {
        struct list_head list;
        struct list_head card_list;
        int num_dai;
-       int (*volatile_register)(struct snd_soc_codec *, unsigned int);
-       int (*readable_register)(struct snd_soc_codec *, unsigned int);
-       int (*writable_register)(struct snd_soc_codec *, unsigned int);
 
        /* runtime */
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
@@ -704,18 +711,14 @@ struct snd_soc_codec {
        unsigned int ac97_registered:1; /* Codec has been AC97 registered */
        unsigned int ac97_created:1; /* Codec has been created by SoC */
        unsigned int cache_init:1; /* codec cache has been initialized */
-       unsigned int using_regmap:1; /* using regmap access */
        u32 cache_only;  /* Suppress writes to hardware */
        u32 cache_sync; /* Cache needs to be synced to hardware */
 
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
        hw_write_t hw_write;
-       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
-       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
        void *reg_cache;
        struct mutex cache_rw_mutex;
-       int val_bytes;
 
        /* component */
        struct snd_soc_component component;
@@ -754,13 +757,9 @@ struct snd_soc_codec_driver {
                unsigned int freq_in, unsigned int freq_out);
 
        /* codec IO */
+       struct regmap *(*get_regmap)(struct device *);
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
-       int (*display_register)(struct snd_soc_codec *, char *,
-                               size_t, unsigned int);
-       int (*volatile_register)(struct snd_soc_codec *, unsigned int);
-       int (*readable_register)(struct snd_soc_codec *, unsigned int);
-       int (*writable_register)(struct snd_soc_codec *, unsigned int);
        unsigned int reg_cache_size;
        short reg_cache_step;
        short reg_word_size;
@@ -791,6 +790,7 @@ struct snd_soc_platform_driver {
        int (*remove)(struct snd_soc_platform *);
        int (*suspend)(struct snd_soc_dai *dai);
        int (*resume)(struct snd_soc_dai *dai);
+       struct snd_soc_component_driver component_driver;
 
        /* pcm creation and destruction */
        int (*pcm_new)(struct snd_soc_pcm_runtime *);
@@ -835,7 +835,6 @@ struct snd_soc_platform {
        int id;
        struct device *dev;
        const struct snd_soc_platform_driver *driver;
-       struct mutex mutex;
 
        unsigned int suspended:1; /* platform is suspended */
        unsigned int probed:1;
@@ -844,6 +843,8 @@ struct snd_soc_platform {
        struct list_head list;
        struct list_head card_list;
 
+       struct snd_soc_component component;
+
        struct snd_soc_dapm_context dapm;
 
 #ifdef CONFIG_DEBUG_FS
@@ -931,7 +932,12 @@ struct snd_soc_dai_link {
 };
 
 struct snd_soc_codec_conf {
+       /*
+        * specify device either by device name, or by
+        * DT/OF node, but not both.
+        */
        const char *dev_name;
+       const struct device_node *of_node;
 
        /*
         * optional map of kcontrol, widget and path name prefixes that are
@@ -942,7 +948,13 @@ struct snd_soc_codec_conf {
 
 struct snd_soc_aux_dev {
        const char *name;               /* Codec name */
-       const char *codec_name;         /* for multi-codec */
+
+       /*
+        * specify multi-codec either by device name, or by
+        * DT/OF node, but not both.
+        */
+       const char *codec_name;
+       const struct device_node *codec_of_node;
 
        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_dapm_context *dapm);
@@ -1090,6 +1102,10 @@ struct soc_bytes {
        u32 mask;
 };
 
+struct soc_bytes_ext {
+       int max;
+};
+
 /* multi register control */
 struct soc_mreg_control {
        long min, max;
@@ -1120,10 +1136,39 @@ static inline struct snd_soc_codec *snd_soc_component_to_codec(
        return container_of(component, struct snd_soc_codec, component);
 }
 
+/**
+ * snd_soc_component_to_platform() - Casts a component to the platform it is embedded in
+ * @component: The component to cast to a platform
+ *
+ * This function must only be used on components that are known to be platforms.
+ * Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_platform *snd_soc_component_to_platform(
+       struct snd_soc_component *component)
+{
+       return container_of(component, struct snd_soc_platform, component);
+}
+
 /* codec IO */
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
-unsigned int snd_soc_write(struct snd_soc_codec *codec,
-                          unsigned int reg, unsigned int val);
+int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int val);
+
+/* component IO */
+int snd_soc_component_read(struct snd_soc_component *component,
+       unsigned int reg, unsigned int *val);
+int snd_soc_component_write(struct snd_soc_component *component,
+       unsigned int reg, unsigned int val);
+int snd_soc_component_update_bits(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int val);
+int snd_soc_component_update_bits_async(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int val);
+void snd_soc_component_async_complete(struct snd_soc_component *component);
+int snd_soc_component_test_bits(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int value);
+
+int snd_soc_component_init_io(struct snd_soc_component *component,
+       struct regmap *regmap);
 
 /* device driver data */
 
@@ -1228,6 +1273,50 @@ static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
        return snd_soc_component_is_active(&codec->component);
 }
 
+/**
+ * snd_soc_kcontrol_component() - Returns the component that registered the
+ *  control
+ * @kcontrol: The control for which to get the component
+ *
+ * Note: This function will work correctly if the control has been registered
+ * for a component. Either with snd_soc_add_codec_controls() or
+ * snd_soc_add_platform_controls() or via  table based setup for either a
+ * CODEC, a platform or component driver. Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_component *snd_soc_kcontrol_component(
+       struct snd_kcontrol *kcontrol)
+{
+       return snd_kcontrol_chip(kcontrol);
+}
+
+/**
+ * snd_soc_kcontrol_codec() - Returns the CODEC that registered the control
+ * @kcontrol: The control for which to get the CODEC
+ *
+ * Note: This function will only work correctly if the control has been
+ * registered with snd_soc_add_codec_controls() or via table based setup of
+ * snd_soc_codec_driver. Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_codec *snd_soc_kcontrol_codec(
+       struct snd_kcontrol *kcontrol)
+{
+       return snd_soc_component_to_codec(snd_soc_kcontrol_component(kcontrol));
+}
+
+/**
+ * snd_soc_kcontrol_platform() - Returns the platform that registerd the control
+ * @kcontrol: The control for which to get the platform
+ *
+ * Note: This function will only work correctly if the control has been
+ * registered with snd_soc_add_platform_controls() or via table based setup of
+ * a snd_soc_platform_driver. Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
+       struct snd_kcontrol *kcontrol)
+{
+       return snd_soc_component_to_platform(snd_soc_kcontrol_component(kcontrol));
+}
+
 int snd_soc_util_init(void);
 void snd_soc_util_exit(void);
 
@@ -1241,7 +1330,9 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname);
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
-                                    const char *prefix);
+                                    const char *prefix,
+                                    struct device_node **bitclkmaster,
+                                    struct device_node **framemaster);
 int snd_soc_of_get_dai_name(struct device_node *of_node,
                            const char **dai_name);
 
diff --git a/include/sound/sta350.h b/include/sound/sta350.h
new file mode 100644 (file)
index 0000000..3a32981
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Platform data for ST STA350 ASoC codec driver.
+ *
+ * Copyright: 2014 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __LINUX_SND__STA350_H
+#define __LINUX_SND__STA350_H
+
+#define STA350_OCFG_2CH                0
+#define STA350_OCFG_2_1CH      1
+#define STA350_OCFG_1CH                3
+
+#define STA350_OM_CH1          0
+#define STA350_OM_CH2          1
+#define STA350_OM_CH3          2
+
+#define STA350_THERMAL_ADJUSTMENT_ENABLE       1
+#define STA350_THERMAL_RECOVERY_ENABLE         2
+#define STA350_FAULT_DETECT_RECOVERY_BYPASS    1
+
+#define STA350_FFX_PM_DROP_COMP                        0
+#define STA350_FFX_PM_TAPERED_COMP             1
+#define STA350_FFX_PM_FULL_POWER               2
+#define STA350_FFX_PM_VARIABLE_DROP_COMP       3
+
+
+struct sta350_platform_data {
+       u8 output_conf;
+       u8 ch1_output_mapping;
+       u8 ch2_output_mapping;
+       u8 ch3_output_mapping;
+       u8 ffx_power_output_mode;
+       u8 drop_compensation_ns;
+       unsigned int thermal_warning_recovery:1;
+       unsigned int thermal_warning_adjustment:1;
+       unsigned int fault_detect_recovery:1;
+       unsigned int oc_warning_adjustment:1;
+       unsigned int max_power_use_mpcc:1;
+       unsigned int max_power_correction:1;
+       unsigned int am_reduction_mode:1;
+       unsigned int odd_pwm_speed_mode:1;
+       unsigned int distortion_compensation:1;
+       unsigned int invalid_input_detect_mute:1;
+};
+
+#endif /* __LINUX_SND__STA350_H */
index 03996b2bb04f86bcb4cea7c1aab4971b2d4c310d..c75c795a377b5c383b59c945c8608e4d8635da6f 100644 (file)
 
 struct snd_soc_jack;
 struct snd_soc_codec;
-struct snd_soc_platform;
 struct snd_soc_card;
 struct snd_soc_dapm_widget;
 struct snd_soc_dapm_path;
 
-/*
- * Log register events
- */
-DECLARE_EVENT_CLASS(snd_soc_reg,
-
-       TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
-                unsigned int val),
-
-       TP_ARGS(codec, reg, val),
-
-       TP_STRUCT__entry(
-               __string(       name,           codec->name     )
-               __field(        int,            id              )
-               __field(        unsigned int,   reg             )
-               __field(        unsigned int,   val             )
-       ),
-
-       TP_fast_assign(
-               __assign_str(name, codec->name);
-               __entry->id = codec->id;
-               __entry->reg = reg;
-               __entry->val = val;
-       ),
-
-       TP_printk("codec=%s.%d reg=%x val=%x", __get_str(name),
-                 (int)__entry->id, (unsigned int)__entry->reg,
-                 (unsigned int)__entry->val)
-);
-
-DEFINE_EVENT(snd_soc_reg, snd_soc_reg_write,
-
-       TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
-                unsigned int val),
-
-       TP_ARGS(codec, reg, val)
-
-);
-
-DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
-
-       TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
-                unsigned int val),
-
-       TP_ARGS(codec, reg, val)
-
-);
-
-DECLARE_EVENT_CLASS(snd_soc_preg,
-
-       TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
-                unsigned int val),
-
-       TP_ARGS(platform, reg, val),
-
-       TP_STRUCT__entry(
-               __string(       name,           platform->name  )
-               __field(        int,            id              )
-               __field(        unsigned int,   reg             )
-               __field(        unsigned int,   val             )
-       ),
-
-       TP_fast_assign(
-               __assign_str(name, platform->name);
-               __entry->id = platform->id;
-               __entry->reg = reg;
-               __entry->val = val;
-       ),
-
-       TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name),
-                 (int)__entry->id, (unsigned int)__entry->reg,
-                 (unsigned int)__entry->val)
-);
-
-DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write,
-
-       TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
-                unsigned int val),
-
-       TP_ARGS(platform, reg, val)
-
-);
-
-DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read,
-
-       TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
-                unsigned int val),
-
-       TP_ARGS(platform, reg, val)
-
-);
-
 DECLARE_EVENT_CLASS(snd_soc_card,
 
        TP_PROTO(struct snd_soc_card *card, int val),
index 6a1a0245474feee8f32fe040e56f0044f53a20f4..d4f70a7fe8761a73e7128964e83b29f7809bd4e9 100644 (file)
@@ -36,7 +36,7 @@ struct extent_status;
 
 #define show_map_flags(flags) __print_flags(flags, "|",                        \
        { EXT4_GET_BLOCKS_CREATE,               "CREATE" },             \
-       { EXT4_GET_BLOCKS_UNINIT_EXT,           "UNINIT" },             \
+       { EXT4_GET_BLOCKS_UNWRIT_EXT,           "UNWRIT" },             \
        { EXT4_GET_BLOCKS_DELALLOC_RESERVE,     "DELALLOC" },           \
        { EXT4_GET_BLOCKS_PRE_IO,               "PRE_IO" },             \
        { EXT4_GET_BLOCKS_CONVERT,              "CONVERT" },            \
@@ -51,7 +51,6 @@ struct extent_status;
        { EXT4_MAP_MAPPED,      "M" },                  \
        { EXT4_MAP_UNWRITTEN,   "U" },                  \
        { EXT4_MAP_BOUNDARY,    "B" },                  \
-       { EXT4_MAP_UNINIT,      "u" },                  \
        { EXT4_MAP_FROM_CLUSTER, "C" })
 
 #define show_free_flags(flags) __print_flags(flags, "|",       \
@@ -1497,7 +1496,7 @@ DEFINE_EVENT(ext4__truncate, ext4_truncate_exit,
        TP_ARGS(inode)
 );
 
-/* 'ux' is the uninitialized extent. */
+/* 'ux' is the unwritten extent. */
 TRACE_EVENT(ext4_ext_convert_to_initialized_enter,
        TP_PROTO(struct inode *inode, struct ext4_map_blocks *map,
                 struct ext4_extent *ux),
@@ -1533,7 +1532,7 @@ TRACE_EVENT(ext4_ext_convert_to_initialized_enter,
 );
 
 /*
- * 'ux' is the uninitialized extent.
+ * 'ux' is the unwritten extent.
  * 'ix' is the initialized extent to which blocks are transferred.
  */
 TRACE_EVENT(ext4_ext_convert_to_initialized_fastpath,
@@ -1811,7 +1810,7 @@ DEFINE_EVENT(ext4__trim, ext4_trim_all_free,
        TP_ARGS(sb, group, start, len)
 );
 
-TRACE_EVENT(ext4_ext_handle_uninitialized_extents,
+TRACE_EVENT(ext4_ext_handle_unwritten_extents,
        TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, int flags,
                 unsigned int allocated, ext4_fsblk_t newblock),
 
diff --git a/include/trace/events/filelock.h b/include/trace/events/filelock.h
new file mode 100644 (file)
index 0000000..d1e9d3e
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Events for filesystem locks
+ *
+ * Copyright 2013 Jeff Layton <jlayton@poochiereds.net>
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM filelock
+
+#if !defined(_TRACE_FILELOCK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FILELOCK_H
+
+#include <linux/tracepoint.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kdev_t.h>
+
+#define show_fl_flags(val)                                             \
+       __print_flags(val, "|",                                         \
+               { FL_POSIX,             "FL_POSIX" },                   \
+               { FL_FLOCK,             "FL_FLOCK" },                   \
+               { FL_DELEG,             "FL_DELEG" },                   \
+               { FL_ACCESS,            "FL_ACCESS" },                  \
+               { FL_EXISTS,            "FL_EXISTS" },                  \
+               { FL_LEASE,             "FL_LEASE" },                   \
+               { FL_CLOSE,             "FL_CLOSE" },                   \
+               { FL_SLEEP,             "FL_SLEEP" },                   \
+               { FL_DOWNGRADE_PENDING, "FL_DOWNGRADE_PENDING" },       \
+               { FL_UNLOCK_PENDING,    "FL_UNLOCK_PENDING" },          \
+               { FL_OFDLCK,            "FL_OFDLCK" })
+
+#define show_fl_type(val)                              \
+       __print_symbolic(val,                           \
+                       { F_RDLCK, "F_RDLCK" },         \
+                       { F_WRLCK, "F_WRLCK" },         \
+                       { F_UNLCK, "F_UNLCK" })
+
+DECLARE_EVENT_CLASS(filelock_lease,
+
+       TP_PROTO(struct inode *inode, struct file_lock *fl),
+
+       TP_ARGS(inode, fl),
+
+       TP_STRUCT__entry(
+               __field(struct file_lock *, fl)
+               __field(unsigned long, i_ino)
+               __field(dev_t, s_dev)
+               __field(struct file_lock *, fl_next)
+               __field(fl_owner_t, fl_owner)
+               __field(unsigned int, fl_flags)
+               __field(unsigned char, fl_type)
+               __field(unsigned long, fl_break_time)
+               __field(unsigned long, fl_downgrade_time)
+       ),
+
+       TP_fast_assign(
+               __entry->fl = fl;
+               __entry->s_dev = inode->i_sb->s_dev;
+               __entry->i_ino = inode->i_ino;
+               __entry->fl_next = fl->fl_next;
+               __entry->fl_owner = fl->fl_owner;
+               __entry->fl_flags = fl->fl_flags;
+               __entry->fl_type = fl->fl_type;
+               __entry->fl_break_time = fl->fl_break_time;
+               __entry->fl_downgrade_time = fl->fl_downgrade_time;
+       ),
+
+       TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu",
+               __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
+               __entry->i_ino, __entry->fl_next, __entry->fl_owner,
+               show_fl_flags(__entry->fl_flags),
+               show_fl_type(__entry->fl_type),
+               __entry->fl_break_time, __entry->fl_downgrade_time)
+);
+
+DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl),
+               TP_ARGS(inode, fl));
+
+DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl),
+               TP_ARGS(inode, fl));
+
+DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl),
+               TP_ARGS(inode, fl));
+
+DEFINE_EVENT(filelock_lease, generic_add_lease, TP_PROTO(struct inode *inode, struct file_lock *fl),
+               TP_ARGS(inode, fl));
+
+DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl),
+               TP_ARGS(inode, fl));
+
+#endif /* _TRACE_FILELOCK_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 11fd51b413de25a6a2415c1724dee458d3314ddc..ed0b2c599a64f7d701117bf54ba6a4dcd56edb31 100644 (file)
@@ -25,7 +25,7 @@ struct module;
        { (1UL << TAINT_OOT_MODULE),            "O" },          \
        { (1UL << TAINT_FORCED_MODULE),         "F" },          \
        { (1UL << TAINT_CRAP),                  "C" },          \
-       { (1UL << TAINT_UNSIGNED_MODULE),       "X" })
+       { (1UL << TAINT_UNSIGNED_MODULE),       "E" })
 
 TRACE_EVENT(module_load,
 
index 126bfaa8bb6be45caf723889c077673da8c992f4..8a3e4ef00c3db418b832a709ca3a3a9eb6c1668b 100644 (file)
@@ -337,6 +337,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_EXEC_NO_RELOC    25
 #define I915_PARAM_HAS_EXEC_HANDLE_LUT   26
 #define I915_PARAM_HAS_WT               27
+#define I915_PARAM_CMD_PARSER_VERSION   28
 
 typedef struct drm_i915_getparam {
        int param;
index 11917f747cb401be5b7dc8ab788fa5d0d4e8e47c..dfa4c860ccefd1af49a3fff7a0a0328db295c647 100644 (file)
@@ -373,6 +373,14 @@ enum {
  */
 #define AUDIT_MESSAGE_TEXT_MAX 8560
 
+/* Multicast Netlink socket groups (default up to 32) */
+enum audit_nlgrps {
+       AUDIT_NLGRP_NONE,       /* Group 0 not used */
+       AUDIT_NLGRP_READLOG,    /* "best effort" read only socket */
+       __AUDIT_NLGRP_MAX
+};
+#define AUDIT_NLGRP_MAX                (__AUDIT_NLGRP_MAX - 1)
+
 struct audit_status {
        __u32           mask;           /* Bit mask for valid entries */
        __u32           enabled;        /* 1 = enabled, 0 = disabled */
index 154dd6d3c8fedaa54a04817567580b11727f2807..12c37a197d247ca980fef9c6e81ed0c067f27987 100644 (file)
@@ -347,7 +347,12 @@ struct vfs_cap_data {
 
 #define CAP_BLOCK_SUSPEND    36
 
-#define CAP_LAST_CAP         CAP_BLOCK_SUSPEND
+/* Allow reading the audit log via multicast netlink socket */
+
+#define CAP_AUDIT_READ         37
+
+
+#define CAP_LAST_CAP         CAP_AUDIT_READ
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
index fd161e91b6d7e711270da030ed84b38f9b718f0c..d47d31d6fa0edcb3bd7c06a84cb8eb1a767afa3e 100644 (file)
@@ -846,6 +846,35 @@ struct ethtool_rxfh_indir {
        __u32   ring_index[0];
 };
 
+/**
+ * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key.
+ * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH
+ * @rss_context: RSS context identifier.
+ * @indir_size: On entry, the array size of the user buffer, which may be zero.
+ *             On return from %ETHTOOL_GRSSH, the array size of the hardware
+ *             indirection table.
+ * @key_size:  On entry, the array size of the user buffer in bytes,
+ *             which may be zero.
+ *             On return from %ETHTOOL_GRSSH, the size of the RSS hash key.
+ * @rsvd:      Reserved for future extensions.
+ * @rss_config: RX ring/queue index for each hash value i.e., indirection table
+ *             of size @indir_size followed by hash key of size @key_size.
+ *
+ * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the
+ * size should be returned.  For %ETHTOOL_SRSSH, a @indir_size of 0xDEADBEEF
+ * means that indir table setting is not requested and a @indir_size of zero
+ * means the indir table should be reset to default values.  This last feature
+ * is not supported by the original implementations.
+ */
+struct ethtool_rxfh {
+       __u32   cmd;
+       __u32   rss_context;
+       __u32   indir_size;
+       __u32   key_size;
+       __u32   rsvd[2];
+       __u32   rss_config[0];
+};
+
 /**
  * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter
  * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
@@ -1118,6 +1147,9 @@ enum ethtool_sfeatures_retval_bits {
 #define ETHTOOL_GEEE           0x00000044 /* Get EEE settings */
 #define ETHTOOL_SEEE           0x00000045 /* Set EEE settings */
 
+#define ETHTOOL_GRSSH          0x00000046 /* Get RX flow hash configuration */
+#define ETHTOOL_SRSSH          0x00000047 /* Set RX flow hash configuration */
+
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
 #define SPARC_ETH_SSET         ETHTOOL_SSET
index 8eb9ccaa5b48124b716e5abe7741aef4ca711d9f..253b4d42cf2bb31517a8a159f5e1c37f13c075f2 100644 (file)
@@ -130,7 +130,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
 #define SKF_AD_VLAN_TAG        44
 #define SKF_AD_VLAN_TAG_PRESENT 48
 #define SKF_AD_PAY_OFFSET      52
-#define SKF_AD_MAX     56
+#define SKF_AD_RANDOM  56
+#define SKF_AD_MAX     60
 #define SKF_NET_OFF   (-0x100000)
 #define SKF_LL_OFF    (-0x200000)
 
index cf4750e1bb4971d03a0e870d323aa3f53c683ba9..40b5ca8a1b1f3028e5e03c5b3372f98e39437422 100644 (file)
  *
  * 7.23
  *  - add FUSE_WRITEBACK_CACHE
+ *  - add time_gran to fuse_init_out
+ *  - add reserved space to fuse_init_out
+ *  - add FATTR_CTIME
+ *  - add ctime and ctimensec to fuse_setattr_in
+ *  - add FUSE_RENAME2 request
  */
 
 #ifndef _LINUX_FUSE_H
@@ -191,6 +196,7 @@ struct fuse_file_lock {
 #define FATTR_ATIME_NOW        (1 << 7)
 #define FATTR_MTIME_NOW        (1 << 8)
 #define FATTR_LOCKOWNER        (1 << 9)
+#define FATTR_CTIME    (1 << 10)
 
 /**
  * Flags returned by the OPEN request
@@ -348,6 +354,7 @@ enum fuse_opcode {
        FUSE_BATCH_FORGET  = 42,
        FUSE_FALLOCATE     = 43,
        FUSE_READDIRPLUS   = 44,
+       FUSE_RENAME2       = 45,
 
        /* CUSE specific operations */
        CUSE_INIT          = 4096,
@@ -426,6 +433,12 @@ struct fuse_rename_in {
        uint64_t        newdir;
 };
 
+struct fuse_rename2_in {
+       uint64_t        newdir;
+       uint32_t        flags;
+       uint32_t        padding;
+};
+
 struct fuse_link_in {
        uint64_t        oldnodeid;
 };
@@ -438,10 +451,10 @@ struct fuse_setattr_in {
        uint64_t        lock_owner;
        uint64_t        atime;
        uint64_t        mtime;
-       uint64_t        unused2;
+       uint64_t        ctime;
        uint32_t        atimensec;
        uint32_t        mtimensec;
-       uint32_t        unused3;
+       uint32_t        ctimensec;
        uint32_t        mode;
        uint32_t        unused4;
        uint32_t        uid;
@@ -559,6 +572,9 @@ struct fuse_init_in {
        uint32_t        flags;
 };
 
+#define FUSE_COMPAT_INIT_OUT_SIZE 8
+#define FUSE_COMPAT_22_INIT_OUT_SIZE 24
+
 struct fuse_init_out {
        uint32_t        major;
        uint32_t        minor;
@@ -567,6 +583,8 @@ struct fuse_init_out {
        uint16_t        max_background;
        uint16_t        congestion_threshold;
        uint32_t        max_write;
+       uint32_t        time_gran;
+       uint32_t        unused[9];
 };
 
 #define CUSE_INIT_INFO_MAX 4096
index 0d36909c3aefa27f26aaf60d1d356d462ae94d0e..1086cd9f675473b21f2c316eac16d591743af777 100644 (file)
  *  Define max and min legal sizes.  The frame sizes do not include
  *  4 byte FCS/CRC (frame check sequence).
  */
-#define FDDI_K_ALEN                    6               /* Octets in one FDDI address */
-#define FDDI_K_8022_HLEN       16              /* Total octets in 802.2 header */
-#define FDDI_K_SNAP_HLEN       21              /* Total octets in 802.2 SNAP header */
-#define FDDI_K_8022_ZLEN       16              /* Min octets in 802.2 frame sans FCS */
-#define FDDI_K_SNAP_ZLEN       21              /* Min octets in 802.2 SNAP frame sans FCS */
+#define FDDI_K_ALEN            6       /* Octets in one FDDI address */
+#define FDDI_K_8022_HLEN       16      /* Total octets in 802.2 header */
+#define FDDI_K_SNAP_HLEN       21      /* Total octets in 802.2 SNAP header */
+#define FDDI_K_8022_ZLEN       16      /* Min octets in 802.2 frame sans
+                                          FCS */
+#define FDDI_K_SNAP_ZLEN       21      /* Min octets in 802.2 SNAP frame sans
+                                          FCS */
 #define FDDI_K_8022_DLEN       4475    /* Max octets in 802.2 payload */
 #define FDDI_K_SNAP_DLEN       4470    /* Max octets in 802.2 SNAP payload */
-#define FDDI_K_LLC_ZLEN                13              /* Min octets in LLC frame sans FCS */
+#define FDDI_K_LLC_ZLEN                13      /* Min octets in LLC frame sans FCS */
 #define FDDI_K_LLC_LEN         4491    /* Max octets in LLC frame sans FCS */
+#define FDDI_K_OUI_LEN         3       /* Octets in OUI in 802.2 SNAP
+                                          header */
 
 /* Define FDDI Frame Control (FC) Byte values */
-#define FDDI_FC_K_VOID                                 0x00    
-#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80    
-#define FDDI_FC_K_RESTRICTED_TOKEN             0xC0    
-#define FDDI_FC_K_SMT_MIN                              0x41
-#define FDDI_FC_K_SMT_MAX                              0x4F
-#define FDDI_FC_K_MAC_MIN                              0xC1
-#define FDDI_FC_K_MAC_MAX                              0xCF    
-#define FDDI_FC_K_ASYNC_LLC_MIN                        0x50
-#define FDDI_FC_K_ASYNC_LLC_DEF                        0x54
-#define FDDI_FC_K_ASYNC_LLC_MAX                        0x5F
-#define FDDI_FC_K_SYNC_LLC_MIN                 0xD0
-#define FDDI_FC_K_SYNC_LLC_MAX                 0xD7
-#define FDDI_FC_K_IMPLEMENTOR_MIN              0x60
-#define FDDI_FC_K_IMPLEMENTOR_MAX              0x6F
-#define FDDI_FC_K_RESERVED_MIN                 0x70
-#define FDDI_FC_K_RESERVED_MAX                 0x7F
+#define FDDI_FC_K_VOID                 0x00
+#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80
+#define FDDI_FC_K_RESTRICTED_TOKEN     0xC0
+#define FDDI_FC_K_SMT_MIN              0x41
+#define FDDI_FC_K_SMT_MAX              0x4F
+#define FDDI_FC_K_MAC_MIN              0xC1
+#define FDDI_FC_K_MAC_MAX              0xCF
+#define FDDI_FC_K_ASYNC_LLC_MIN                0x50
+#define FDDI_FC_K_ASYNC_LLC_DEF                0x54
+#define FDDI_FC_K_ASYNC_LLC_MAX                0x5F
+#define FDDI_FC_K_SYNC_LLC_MIN         0xD0
+#define FDDI_FC_K_SYNC_LLC_MAX         0xD7
+#define FDDI_FC_K_IMPLEMENTOR_MIN      0x60
+#define FDDI_FC_K_IMPLEMENTOR_MAX      0x6F
+#define FDDI_FC_K_RESERVED_MIN         0x70
+#define FDDI_FC_K_RESERVED_MAX         0x7F
 
 /* Define LLC and SNAP constants */
-#define FDDI_EXTENDED_SAP      0xAA
+#define FDDI_EXTENDED_SAP              0xAA
 #define FDDI_UI_CMD                    0x03
 
 /* Define 802.2 Type 1 header */
 struct fddi_8022_1_hdr {
-       __u8    dsap;                                   /* destination service access point */
-       __u8    ssap;                                   /* source service access point */
-       __u8    ctrl;                                   /* control byte #1 */
+       __u8    dsap;                   /* destination service access point */
+       __u8    ssap;                   /* source service access point */
+       __u8    ctrl;                   /* control byte #1 */
 } __attribute__((packed));
 
 /* Define 802.2 Type 2 header */
 struct fddi_8022_2_hdr {
-       __u8    dsap;                                   /* destination service access point */
-       __u8    ssap;                                   /* source service access point */
-       __u8    ctrl_1;                                 /* control byte #1 */
-       __u8    ctrl_2;                                 /* control byte #2 */
+       __u8    dsap;                   /* destination service access point */
+       __u8    ssap;                   /* source service access point */
+       __u8    ctrl_1;                 /* control byte #1 */
+       __u8    ctrl_2;                 /* control byte #2 */
 } __attribute__((packed));
 
 /* Define 802.2 SNAP header */
-#define FDDI_K_OUI_LEN 3
 struct fddi_snap_hdr {
-       __u8    dsap;                                   /* always 0xAA */
-       __u8    ssap;                                   /* always 0xAA */
-       __u8    ctrl;                                   /* always 0x03 */
+       __u8    dsap;                   /* always 0xAA */
+       __u8    ssap;                   /* always 0xAA */
+       __u8    ctrl;                   /* always 0x03 */
        __u8    oui[FDDI_K_OUI_LEN];    /* organizational universal id */
-       __be16  ethertype;                              /* packet type ID field */
+       __be16  ethertype;              /* packet type ID field */
 } __attribute__((packed));
 
 /* Define FDDI LLC frame header */
 struct fddihdr {
-       __u8    fc;                                             /* frame control */
-       __u8    daddr[FDDI_K_ALEN];             /* destination address */
-       __u8    saddr[FDDI_K_ALEN];             /* source address */
-       union
-               {
-               struct fddi_8022_1_hdr          llc_8022_1;
-               struct fddi_8022_2_hdr          llc_8022_2;
-               struct fddi_snap_hdr            llc_snap;
-               } hdr;
+       __u8    fc;                     /* frame control */
+       __u8    daddr[FDDI_K_ALEN];     /* destination address */
+       __u8    saddr[FDDI_K_ALEN];     /* source address */
+       union {
+               struct fddi_8022_1_hdr  llc_8022_1;
+               struct fddi_8022_2_hdr  llc_8022_2;
+               struct fddi_snap_hdr    llc_snap;
+       } hdr;
 } __attribute__((packed));
 
 
index f4849525519c7a301f4202f68a8eea9fb0e9d296..19df18c9b8be371ec5d13fc09f69fc33f2ff7769 100644 (file)
@@ -462,7 +462,10 @@ struct input_keymap_entry {
 #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_BRIGHTNESS_AUTO    244     /* Set Auto Brightness: manual
+                                         brightness control is off,
+                                         rely on ambient */
+#define KEY_BRIGHTNESS_ZERO    KEY_BRIGHTNESS_AUTO
 #define KEY_DISPLAY_OFF                245     /* display device to off state */
 
 #define KEY_WWAN               246     /* Wireless WAN (LTE, UMTS, GSM, etc.) */
@@ -632,6 +635,7 @@ struct input_keymap_entry {
 #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_BRIGHTNESS_TOGGLE  KEY_DISPLAYTOGGLE
 #define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
 #define KEY_LOGOFF             0x1b1   /* AL Logoff */
 
@@ -723,6 +727,17 @@ struct input_keymap_entry {
 
 #define KEY_ALS_TOGGLE         0x230   /* Ambient light sensor */
 
+#define KEY_BUTTONCONFIG               0x240   /* AL Button Configuration */
+#define KEY_TASKMANAGER                0x241   /* AL Task/Project Manager */
+#define KEY_JOURNAL            0x242   /* AL Log/Journal/Timecard */
+#define KEY_CONTROLPANEL               0x243   /* AL Control Panel */
+#define KEY_APPSELECT          0x244   /* AL Select Task/Application */
+#define KEY_SCREENSAVER                0x245   /* AL Screen Saver */
+#define KEY_VOICECOMMAND               0x246   /* Listening Voice Command */
+
+#define KEY_BRIGHTNESS_MIN             0x250   /* Set Brightness to Minimum */
+#define KEY_BRIGHTNESS_MAX             0x251   /* Set Brightness to Maximum */
+
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
 #define BTN_TRIGGER_HAPPY2             0x2c1
index 1ba9d626aa833db91c462560f27054b30e91939d..406010d4def049d3880b49a0b4362e75b93c47c1 100644 (file)
@@ -1579,6 +1579,10 @@ enum nl80211_commands {
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  *     As specified in the &enum nl80211_tdls_peer_capability.
  *
+ * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ *     creation then the new interface will be owned by the netlink socket
+ *     that created it and will be destroyed when the socket is closed
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1914,6 +1918,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
+       NL80211_ATTR_IFACE_SOCKET_OWNER,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2336,9 +2342,34 @@ enum nl80211_band_attr {
  *     using this channel as the primary or any of the secondary channels
  *     isn't possible
  * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
+ * @NL80211_FREQUENCY_ATTR_INDOOR_ONLY: Only indoor use is permitted on this
+ *     channel. A channel that has the INDOOR_ONLY attribute can only be
+ *     used when there is a clear assessment that the device is operating in
+ *     an indoor surroundings, i.e., it is connected to AC power (and not
+ *     through portable DC inverters) or is under the control of a master
+ *     that is acting as an AP and is connected to AC power.
+ * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
+ *     channel if it's connected concurrently to a BSS on the same channel on
+ *     the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
+ *     band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
+ *     channel that has the GO_CONCURRENT attribute set can be done when there
+ *     is a clear assessment that the device is operating under the guidance of
+ *     an authorized master, i.e., setting up a GO while the device is also
+ *     connected to an AP with DFS and radar detection on the UNII band (it is
+ *     up to user-space, i.e., wpa_supplicant to perform the required
+ *     verifications)
+ * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
+ *     on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
+ *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
  *     currently defined
  * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+ *
+ * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
+ * for more information on the FCC description of the relaxations allowed
+ * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
+ * NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
  */
 enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
@@ -2355,6 +2386,10 @@ enum nl80211_frequency_attr {
        NL80211_FREQUENCY_ATTR_NO_80MHZ,
        NL80211_FREQUENCY_ATTR_NO_160MHZ,
        NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
+       NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
+       NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
+       NL80211_FREQUENCY_ATTR_NO_20MHZ,
+       NL80211_FREQUENCY_ATTR_NO_10MHZ,
 
        /* keep last */
        __NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2573,10 +2608,13 @@ enum nl80211_dfs_regions {
  *     present has been registered with the wireless core that
  *     has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
  *     supported feature.
+ * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
+ *     platform is operating in an indoor environment.
  */
 enum nl80211_user_reg_hint_type {
        NL80211_USER_REG_HINT_USER      = 0,
        NL80211_USER_REG_HINT_CELL_BASE = 1,
+       NL80211_USER_REG_HINT_INDOOR    = 2,
 };
 
 /**
@@ -3891,6 +3929,9 @@ enum nl80211_ap_sme_features {
  *     interface. An active monitor interface behaves like a normal monitor
  *     interface, but gets added to the driver. It ensures that incoming
  *     unicast packets directed at the configured interface address get ACKed.
+ * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic
+ *     channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the
+ *     lifetime of a BSS.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3911,6 +3952,7 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_FULL_AP_CLIENT_STATE            = 1 << 15,
        NL80211_FEATURE_USERSPACE_MPM                   = 1 << 16,
        NL80211_FEATURE_ACTIVE_MONITOR                  = 1 << 17,
+       NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE       = 1 << 18,
 };
 
 /**
index 852373d27dbb2bdd2016bf6a9d2ba00cd68e2954..6f71b9b4159581eac01241f9c443948584f30f6e 100644 (file)
@@ -38,6 +38,7 @@
 #define _LINUX_TIPC_H_
 
 #include <linux/types.h>
+#include <linux/sockios.h>
 
 /*
  * TIPC addressing primitives
@@ -87,6 +88,7 @@ static inline unsigned int tipc_node(__u32 addr)
 
 #define TIPC_CFG_SRV           0       /* configuration service name type */
 #define TIPC_TOP_SRV           1       /* topology service name type */
+#define TIPC_LINK_STATE                2       /* link state name type */
 #define TIPC_RESERVED_TYPES    64      /* lowest user-publishable name type */
 
 /*
@@ -206,4 +208,25 @@ struct sockaddr_tipc {
 #define TIPC_NODE_RECVQ_DEPTH  131     /* Default: none (read only) */
 #define TIPC_SOCK_RECVQ_DEPTH  132     /* Default: none (read only) */
 
+/*
+ * Maximum sizes of TIPC bearer-related names (including terminating NULL)
+ * The string formatting for each name element is:
+ * media: media
+ * interface: media:interface name
+ * link: Z.C.N:interface-Z.C.N:interface
+ *
+ */
+
+#define TIPC_MAX_MEDIA_NAME    16
+#define TIPC_MAX_IF_NAME       16
+#define TIPC_MAX_BEARER_NAME   32
+#define TIPC_MAX_LINK_NAME     60
+
+#define SIOCGETLINKNAME                SIOCPROTOPRIVATE
+
+struct tipc_sioc_ln_req {
+       __u32 peer;
+       __u32 bearer_id;
+       char linkname[TIPC_MAX_LINK_NAME];
+};
 #endif
index 6b0bff09b3a7ced5dc7cf2c1a07dd4f82112b088..41a76acbb305f85cb4cb0ec6dfab9cab1e20e1d4 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/tipc.h>
 #include <asm/byteorder.h>
 
 #ifndef __KERNEL__
 #define TIPC_TLV_NAME_TBL_QUERY        25      /* struct tipc_name_table_query */
 #define TIPC_TLV_PORT_REF      26      /* 32-bit port reference */
 
-/*
- * Maximum sizes of TIPC bearer-related names (including terminating NUL)
- */
-
-#define TIPC_MAX_MEDIA_NAME    16      /* format = media */
-#define TIPC_MAX_IF_NAME       16      /* format = interface */
-#define TIPC_MAX_BEARER_NAME   32      /* format = media:interface */
-#define TIPC_MAX_LINK_NAME     60      /* format = Z.C.N:interface-Z.C.N:interface */
-
 /*
  * Link priority limits (min, default, max, media default)
  */
index 9d3585bb2a7a3cbb58234d24761f597b0af95c7c..0f0f351029eb88eb110ee4bb03b8be0163759956 100644 (file)
@@ -1255,6 +1255,77 @@ config CC_OPTIMIZE_FOR_SIZE
 
          If unsure, say N.
 
+config LTO_MENU
+       bool "Enable gcc link time optimization (LTO)"
+       # Only tested on X86 for now. For other architectures you likely
+       # have to fix some things first, like adding asmlinkages etc.
+       depends on X86
+       # lto does not support excluding flags for specific files
+       # right now. Can be removed if that is fixed.
+       depends on !FUNCTION_TRACER
+       help
+         With this option gcc will do whole program optimizations for
+         the whole kernel and module. This increases compile time, but can
+         lead to better code. It allows gcc to inline functions between
+         different files and do other optimization.  It might also trigger
+         bugs due to more aggressive optimization. It allows gcc to drop unused
+         code. On smaller monolithic kernel configurations
+         it usually leads to smaller kernels, especially when modules
+         are disabled.
+
+         With this option gcc will also do some global checking over
+         different source files. It also disables a number of kernel
+         features.
+
+         This option is recommended for release builds. With LTO
+         the kernel always has to be re-optimized (but not re-parsed)
+         on each build.
+
+         This requires a gcc 4.8 or later compiler and
+         Linux binutils 2.21.51.0.3 or later.  gcc 4.9 builds significantly
+         faster than 4.8 It does not currently work with a FSF release of
+         binutils or with the gold linker.
+
+         On larger configurations this may need more than 4GB of RAM.
+         It will likely not work on those with a 32bit compiler.
+
+         When the toolchain support is not available this will (hopefully)
+         be automatically disabled.
+
+         For more information see Documentation/lto-build
+
+config LTO_DISABLE
+         bool "Disable LTO again"
+         depends on LTO_MENU
+         default n
+         help
+           This option is merely here so that allyesconfig or allmodconfig do
+           not enable LTO. If you want to actually use LTO do not enable.
+
+config LTO
+       bool
+       default y
+       depends on LTO_MENU && !LTO_DISABLE
+
+config LTO_DEBUG
+       bool "Enable LTO compile time debugging"
+       depends on LTO
+       help
+         Enable LTO debugging in the compiler. The compiler dumps
+         some log files that make it easier to figure out LTO
+         behavior. The log files also allow to reconstruct
+         the global inlining and a global callgraph.
+         They however add some (single threaded) cost to the
+         compilation.  When in doubt do not enable.
+
+config LTO_CP_CLONE
+       bool "Allow aggressive cloning for function specialization"
+       depends on LTO
+       help
+         Allow the compiler to clone and specialize functions for specific
+         arguments when it determines these arguments are very commonly
+         called.  Experimential. Will increase text size.
+
 config SYSCTL
        bool
 
@@ -1744,6 +1815,8 @@ config MODULE_FORCE_UNLOAD
 
 config MODVERSIONS
        bool "Module versioning support"
+       # LTO should work with gcc 4.9
+       depends on !LTO
        help
          Usually, you have to use modules compiled with your kernel.
          Saying Y here makes it sometimes possible to use modules
index 9c7fd4c9249f2c72395fcaf2ac953f782a3e2b59..e9d458b5d77bd34449473d6b777da545aec8a81b 100644 (file)
@@ -252,6 +252,27 @@ static int __init repair_env_string(char *param, char *val, const char *unused)
        return 0;
 }
 
+/* Anything after -- gets handed straight to init. */
+static int __init set_init_arg(char *param, char *val, const char *unused)
+{
+       unsigned int i;
+
+       if (panic_later)
+               return 0;
+
+       repair_env_string(param, val, unused);
+
+       for (i = 0; argv_init[i]; i++) {
+               if (i == MAX_INIT_ARGS) {
+                       panic_later = "init";
+                       panic_param = param;
+                       return 0;
+               }
+       }
+       argv_init[i] = param;
+       return 0;
+}
+
 /*
  * Unknown boot options get handed to init, unless they look like
  * unused parameters (modprobe will find them in /proc/cmdline).
@@ -478,7 +499,7 @@ static void __init mm_init(void)
 
 asmlinkage void __init start_kernel(void)
 {
-       char * command_line;
+       char * command_line, *after_dashes;
        extern const struct kernel_param __start___param[], __stop___param[];
 
        /*
@@ -519,9 +540,13 @@ asmlinkage void __init start_kernel(void)
 
        pr_notice("Kernel command line: %s\n", boot_command_line);
        parse_early_param();
-       parse_args("Booting kernel", static_command_line, __start___param,
-                  __stop___param - __start___param,
-                  -1, -1, &unknown_bootoption);
+       after_dashes = parse_args("Booting kernel",
+                                 static_command_line, __start___param,
+                                 __stop___param - __start___param,
+                                 -1, -1, &unknown_bootoption);
+       if (after_dashes)
+               parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
+                          set_init_arg);
 
        jump_label_init();
 
index 7c2893602d0651f767e1a177dbfd6214e66e8d9c..81f5f49479da7c64625007a0eb086f720959f728 100644 (file)
@@ -423,6 +423,38 @@ static void kauditd_send_skb(struct sk_buff *skb)
                consume_skb(skb);
 }
 
+/*
+ * kauditd_send_multicast_skb - send the skb to multicast userspace listeners
+ *
+ * This function doesn't consume an skb as might be expected since it has to
+ * copy it anyways.
+ */
+static void kauditd_send_multicast_skb(struct sk_buff *skb)
+{
+       struct sk_buff          *copy;
+       struct audit_net        *aunet = net_generic(&init_net, audit_net_id);
+       struct sock             *sock = aunet->nlsk;
+
+       if (!netlink_has_listeners(sock, AUDIT_NLGRP_READLOG))
+               return;
+
+       /*
+        * The seemingly wasteful skb_copy() rather than bumping the refcount
+        * using skb_get() is necessary because non-standard mods are made to
+        * the skb by the original kaudit unicast socket send routine.  The
+        * existing auditd daemon assumes this breakage.  Fixing this would
+        * require co-ordinating a change in the established protocol between
+        * the kaudit kernel subsystem and the auditd userspace code.  There is
+        * no reason for new multicast clients to continue with this
+        * non-compliance.
+        */
+       copy = skb_copy(skb, GFP_KERNEL);
+       if (!copy)
+               return;
+
+       nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, GFP_KERNEL);
+}
+
 /*
  * flush_hold_queue - empty the hold queue if auditd appears
  *
@@ -643,13 +675,13 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
                if ((task_active_pid_ns(current) != &init_pid_ns))
                        return -EPERM;
 
-               if (!capable(CAP_AUDIT_CONTROL))
+               if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
                        err = -EPERM;
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
        case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
-               if (!capable(CAP_AUDIT_WRITE))
+               if (!netlink_capable(skb, CAP_AUDIT_WRITE))
                        err = -EPERM;
                break;
        default:  /* bad msg */
@@ -1076,10 +1108,22 @@ static void audit_receive(struct sk_buff  *skb)
        mutex_unlock(&audit_cmd_mutex);
 }
 
+/* Run custom bind function on netlink socket group connect or bind requests. */
+static int audit_bind(int group)
+{
+       if (!capable(CAP_AUDIT_READ))
+               return -EPERM;
+
+       return 0;
+}
+
 static int __net_init audit_net_init(struct net *net)
 {
        struct netlink_kernel_cfg cfg = {
                .input  = audit_receive,
+               .bind   = audit_bind,
+               .flags  = NL_CFG_F_NONROOT_RECV,
+               .groups = AUDIT_NLGRP_MAX,
        };
 
        struct audit_net *aunet = net_generic(net, audit_net_id);
@@ -1901,10 +1945,10 @@ out:
  * audit_log_end - end one audit record
  * @ab: the audit_buffer
  *
- * The netlink_* functions cannot be called inside an irq context, so
- * the audit buffer is placed on a queue and a tasklet is scheduled to
- * remove them from the queue outside the irq context.  May be called in
- * any context.
+ * netlink_unicast() cannot be called inside an irq context because it blocks
+ * (last arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed
+ * on a queue and a tasklet is scheduled to remove them from the queue outside
+ * the irq context.  May be called in any context.
  */
 void audit_log_end(struct audit_buffer *ab)
 {
@@ -1914,6 +1958,18 @@ void audit_log_end(struct audit_buffer *ab)
                audit_log_lost("rate limit exceeded");
        } else {
                struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+
+               kauditd_send_multicast_skb(ab->skb);
+
+               /*
+                * The original kaudit unicast socket sends up messages with
+                * nlmsg_len set to the payload length rather than the entire
+                * message length.  This breaks the standard set by netlink.
+                * The existing auditd daemon assumes this breakage.  Fixing
+                * this would require co-ordinating a change in the established
+                * protocol between the kaudit kernel subsystem and the auditd
+                * userspace code.
+                */
                nlh->nlmsg_len = ab->skb->len - NLMSG_HDRLEN;
 
                if (audit_pid) {
index d04ce8ac4399260c8e127bd800a5a12dc91f5044..32f65b7aed46ab5becded08e1942377b0b8815a3 100644 (file)
@@ -2,7 +2,7 @@ menu "GCOV-based kernel profiling"
 
 config GCOV_KERNEL
        bool "Enable gcov-based kernel profiling"
-       depends on DEBUG_FS
+       depends on DEBUG_FS && !LTO
        select CONSTRUCTORS if !UML
        default n
        ---help---
index d55092ceee2975c204bcb90e856f9b6504d577ac..6b715c0af1b117b5b61bd32629a00845f0313557 100644 (file)
@@ -234,6 +234,11 @@ again:
                        goto again;
                }
                timer->base = new_base;
+       } else {
+               if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+                       cpu = this_cpu;
+                       goto again;
+               }
        }
        return new_base;
 }
@@ -569,6 +574,23 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
 
        cpu_base->expires_next.tv64 = expires_next.tv64;
 
+       /*
+        * If a hang was detected in the last timer interrupt then we
+        * leave the hang delay active in the hardware. We want the
+        * system to make progress. That also prevents the following
+        * scenario:
+        * T1 expires 50ms from now
+        * T2 expires 5s from now
+        *
+        * T1 is removed, so this code is called and would reprogram
+        * the hardware to 5s from now. Any hrtimer_start after that
+        * will not reprogram the hardware due to hang_detected being
+        * set. So we'd effectivly block all timers until the T2 event
+        * fires.
+        */
+       if (cpu_base->hang_detected)
+               return;
+
        if (cpu_base->expires_next.tv64 != KTIME_MAX)
                tick_program_event(cpu_base->expires_next, 1);
 }
index a7174617616ba6b8f404a1c3f01cf8b7dd90cb4d..bb07f2928f4b9c2ca33803f712c8889ca5823907 100644 (file)
@@ -363,6 +363,13 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
                if (from > irq)
                        return -EINVAL;
                from = irq;
+       } else {
+               /*
+                * For interrupts which are freely allocated the
+                * architecture can force a lower bound to the @from
+                * argument. x86 uses this to exclude the GSI space.
+                */
+               from = arch_dynirq_lower_bound(from);
        }
 
        mutex_lock(&sparse_irq_lock);
index 11869408f79b86abe33e5194d0f5c705b44e9d81..626d164dcf83f6166479440c59cfc530d6b325a0 100644 (file)
@@ -815,9 +815,6 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
                return -EFAULT;
        name[MODULE_NAME_LEN-1] = '\0';
 
-       if (!(flags & O_NONBLOCK))
-               pr_warn("waiting module removal not supported: please upgrade\n");
-
        if (mutex_lock_interruptible(&module_mutex) != 0)
                return -EINTR;
 
@@ -3193,6 +3190,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 {
        struct module *mod;
        long err;
+       char *after_dashes;
 
        err = module_sig_check(info);
        if (err)
@@ -3271,16 +3269,24 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
        dynamic_debug_setup(info->debug, info->num_debug);
 
+       /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
+       ftrace_module_init(mod);
+
        /* Finally it's fully formed, ready to start executing. */
        err = complete_formation(mod, info);
        if (err)
                goto ddebug_cleanup;
 
        /* Module is ready to execute: parsing args may do that. */
-       err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-                        -32768, 32767, unknown_module_param_cb);
-       if (err < 0)
+       after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
+                                 -32768, 32767, unknown_module_param_cb);
+       if (IS_ERR(after_dashes)) {
+               err = PTR_ERR(after_dashes);
                goto bug_cleanup;
+       } else if (after_dashes) {
+               pr_warn("%s: parameters '%s' after `--' ignored\n",
+                      mod->name, after_dashes);
+       }
 
        /* Link in to syfs. */
        err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
index b00142e7f3ba18d52f41e19427f145eb6e95cf2d..1e52ca233fd9a45484418f14820c40b95e89d6ba 100644 (file)
@@ -177,13 +177,13 @@ static char *next_arg(char *args, char **param, char **val)
 }
 
 /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
-int parse_args(const char *doing,
-              char *args,
-              const struct kernel_param *params,
-              unsigned num,
-              s16 min_level,
-              s16 max_level,
-              int (*unknown)(char *param, char *val, const char *doing))
+char *parse_args(const char *doing,
+                char *args,
+                const struct kernel_param *params,
+                unsigned num,
+                s16 min_level,
+                s16 max_level,
+                int (*unknown)(char *param, char *val, const char *doing))
 {
        char *param, *val;
 
@@ -198,6 +198,9 @@ int parse_args(const char *doing,
                int irq_was_disabled;
 
                args = next_arg(args, &param, &val);
+               /* Stop at -- */
+               if (!val && strcmp(param, "--") == 0)
+                       return args;
                irq_was_disabled = irqs_disabled();
                ret = parse_one(param, val, doing, params, num,
                                min_level, max_level, unknown);
@@ -208,22 +211,22 @@ int parse_args(const char *doing,
                switch (ret) {
                case -ENOENT:
                        pr_err("%s: Unknown parameter `%s'\n", doing, param);
-                       return ret;
+                       return ERR_PTR(ret);
                case -ENOSPC:
                        pr_err("%s: `%s' too large for parameter `%s'\n",
                               doing, val ?: "", param);
-                       return ret;
+                       return ERR_PTR(ret);
                case 0:
                        break;
                default:
                        pr_err("%s: `%s' invalid for parameter `%s'\n",
                               doing, val ?: "", param);
-                       return ret;
+                       return ERR_PTR(ret);
                }
        }
 
        /* All parsed OK. */
-       return 0;
+       return NULL;
 }
 
 /* Lazy bastard, eh? */
index f4f2073711d34891645be8dfc997645342c043e4..1f08ac7f55d818fbb301e87fd99707e93764aab1 100644 (file)
@@ -228,19 +228,23 @@ static void platform_recover(int platform_mode)
 void swsusp_show_speed(struct timeval *start, struct timeval *stop,
                        unsigned nr_pages, char *msg)
 {
-       s64 elapsed_centisecs64;
-       int centisecs;
-       int k;
-       int kps;
+       u64 elapsed_centisecs64;
+       unsigned int centisecs;
+       unsigned int k;
+       unsigned int kps;
 
        elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
+       /*
+        * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time,
+        * it is obvious enough for what went wrong.
+        */
        do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
        centisecs = elapsed_centisecs64;
        if (centisecs == 0)
                centisecs = 1;  /* avoid div-by-zero */
        k = nr_pages * (PAGE_SIZE / 1024);
        kps = (k * 100) / centisecs;
-       printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+       printk(KERN_INFO "PM: %s %u kbytes in %u.%02u seconds (%u.%02u MB/s)\n",
                        msg, k,
                        centisecs / 100, centisecs % 100,
                        kps / 1000, (kps % 1000) / 10);
@@ -595,7 +599,8 @@ static void power_down(void)
        case HIBERNATION_PLATFORM:
                hibernation_platform_enter();
        case HIBERNATION_SHUTDOWN:
-               kernel_power_off();
+               if (pm_power_off)
+                       kernel_power_off();
                break;
 #ifdef CONFIG_SUSPEND
        case HIBERNATION_SUSPEND:
@@ -623,7 +628,8 @@ static void power_down(void)
         * corruption after resume.
         */
        printk(KERN_CRIT "PM: Please power down manually\n");
-       while(1);
+       while (1)
+               cpu_relax();
 }
 
 /**
index b50990a5bea0220df9034f0bcc71d92e452edc78..33e4648ae0e7cd908671ef1a8ab60bbb562c097c 100644 (file)
@@ -779,3 +779,8 @@ int __init __weak arch_early_irq_init(void)
 {
        return 0;
 }
+
+unsigned int __weak arch_dynirq_lower_bound(unsigned int from)
+{
+       return from;
+}
index 87bd529879c23bb12705fa0144cff354064f91dc..3bb01a323b2a3e0ae9291271f4dc0322f01bfd80 100644 (file)
@@ -838,7 +838,7 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
 
        bit = find_last_bit(&mask, BITS_PER_LONG);
 
-       mask = (1 << bit) - 1;
+       mask = (1UL << bit) - 1;
 
        expires_limit = expires_limit & ~(mask);
 
index 1fd4b9479210183762293944be777abb5435f8e3..4a54a25afa2fe67165cb6f65cd0b63c42eb724eb 100644 (file)
@@ -4330,16 +4330,11 @@ static void ftrace_init_module(struct module *mod,
        ftrace_process_locs(mod, start, end);
 }
 
-static int ftrace_module_notify_enter(struct notifier_block *self,
-                                     unsigned long val, void *data)
+void ftrace_module_init(struct module *mod)
 {
-       struct module *mod = data;
-
-       if (val == MODULE_STATE_COMING)
-               ftrace_init_module(mod, mod->ftrace_callsites,
-                                  mod->ftrace_callsites +
-                                  mod->num_ftrace_callsites);
-       return 0;
+       ftrace_init_module(mod, mod->ftrace_callsites,
+                          mod->ftrace_callsites +
+                          mod->num_ftrace_callsites);
 }
 
 static int ftrace_module_notify_exit(struct notifier_block *self,
@@ -4353,11 +4348,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self,
        return 0;
 }
 #else
-static int ftrace_module_notify_enter(struct notifier_block *self,
-                                     unsigned long val, void *data)
-{
-       return 0;
-}
 static int ftrace_module_notify_exit(struct notifier_block *self,
                                     unsigned long val, void *data)
 {
@@ -4365,11 +4355,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self,
 }
 #endif /* CONFIG_MODULES */
 
-struct notifier_block ftrace_module_enter_nb = {
-       .notifier_call = ftrace_module_notify_enter,
-       .priority = INT_MAX,    /* Run before anything that can use kprobes */
-};
-
 struct notifier_block ftrace_module_exit_nb = {
        .notifier_call = ftrace_module_notify_exit,
        .priority = INT_MIN,    /* Run after anything that can remove kprobes */
@@ -4403,10 +4388,6 @@ void __init ftrace_init(void)
                                  __start_mcount_loc,
                                  __stop_mcount_loc);
 
-       ret = register_module_notifier(&ftrace_module_enter_nb);
-       if (ret)
-               pr_warning("Failed to register trace ftrace module enter notifier\n");
-
        ret = register_module_notifier(&ftrace_module_exit_nb);
        if (ret)
                pr_warning("Failed to register trace ftrace module exit notifier\n");
index 925f537f07d17db7caae363dd39a20bd2296d2ee..4747b476a0300bc3c08ad82f97d6a7a10fb638c4 100644 (file)
@@ -77,7 +77,7 @@ event_triggers_call(struct ftrace_event_file *file, void *rec)
                        data->ops->func(data);
                        continue;
                }
-               filter = rcu_dereference(data->filter);
+               filter = rcu_dereference_sched(data->filter);
                if (filter && !filter_match_preds(filter, rec))
                        continue;
                if (data->cmd_ops->post_trigger) {
index 4771fb3f4da4deafdab8b26c76df9c0bec618300..334f7722a999232aa46b706d8cda61b57c854708 100644 (file)
@@ -331,6 +331,20 @@ config TEXTSEARCH_FSM
 config BTREE
        boolean
 
+config INTERVAL_TREE
+       boolean
+       help
+         Simple, embeddable, interval-tree. Can find the start of an
+         overlapping range in log(n) time and then iterate over all
+         overlapping nodes. The algorithm is implemented as an
+         augmented rbtree.
+
+         See:
+
+               Documentation/rbtree.txt
+
+         for more information.
+
 config ASSOCIATIVE_ARRAY
        bool
        help
index 819ac51202c01006e105f91355d492db6bdd6eb6..7482d55c8ecbdf8768c0fdd1fbe1c69ec381c69d 100644 (file)
@@ -180,7 +180,7 @@ config STRIP_ASM_SYMS
 
 config READABLE_ASM
         bool "Generate readable assembler code"
-        depends on DEBUG_KERNEL
+        depends on DEBUG_KERNEL && !LTO
         help
           Disable some compiler optimizations that tend to generate human unreadable
           assembler output. This may make the kernel slightly slower, but it helps
@@ -1496,6 +1496,7 @@ config RBTREE_TEST
 config INTERVAL_TREE_TEST
        tristate "Interval tree test"
        depends on m && DEBUG_KERNEL
+       select INTERVAL_TREE
        help
          A benchmark measuring the performance of the interval tree library
 
index 0cd7b68e1382dee93301898da70a6ca51c3d764e..2c6c1a42e1d2f748ad534958f99c64ae971dd31d 100644 (file)
@@ -50,6 +50,7 @@ CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
+obj-$(CONFIG_INTERVAL_TREE) += interval_tree.o
 obj-$(CONFIG_ASSOCIATIVE_ARRAY) += assoc_array.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
@@ -156,8 +157,6 @@ lib-$(CONFIG_LIBFDT) += $(libfdt_files)
 obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o
 obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o
 
-interval_tree_test-objs := interval_tree_test_main.o interval_tree.o
-
 obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
 
 obj-$(CONFIG_ASN1) += asn1_decoder.o
index e6eb406f2d65dd3c4e22520239ec10afdd42dc30..f367f9ad544c3901a0ee5bcdfe451ac8b9b2aea3 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/init.h>
 #include <linux/interval_tree.h>
 #include <linux/interval_tree_generic.h>
+#include <linux/module.h>
 
 #define START(node) ((node)->start)
 #define LAST(node)  ((node)->last)
@@ -8,3 +9,8 @@
 INTERVAL_TREE_DEFINE(struct interval_tree_node, rb,
                     unsigned long, __subtree_last,
                     START, LAST,, interval_tree)
+
+EXPORT_SYMBOL_GPL(interval_tree_insert);
+EXPORT_SYMBOL_GPL(interval_tree_remove);
+EXPORT_SYMBOL_GPL(interval_tree_iter_first);
+EXPORT_SYMBOL_GPL(interval_tree_iter_next);
index ebe5880c29d6cbe2306054f19bda87ffb3daa59a..30cb6cb008f5b972207ef5c38b7844ebd81a9cf9 100644 (file)
@@ -134,6 +134,9 @@ config HAVE_MEMBLOCK
 config HAVE_MEMBLOCK_NODE_MAP
        boolean
 
+config HAVE_MEMBLOCK_PHYS_MAP
+       boolean
+
 config ARCH_DISCARD_MEMBLOCK
        boolean
 
index 5020b280a771a4929bee7dbf0c5aee3fab1dea8b..6c7fffedb70116d6ee8b58607b0cf41ef69999b3 100644 (file)
@@ -1656,96 +1656,42 @@ out:
        return written ? written : error;
 }
 
-/*
- * Performs necessary checks before doing a write
- * @iov:       io vector request
- * @nr_segs:   number of segments in the iovec
- * @count:     number of bytes to write
- * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE
- *
- * Adjust number of segments and amount of bytes to write (nr_segs should be
- * properly initialized first). Returns appropriate error code that caller
- * should return or zero in case that write should be allowed.
- */
-int generic_segment_checks(const struct iovec *iov,
-                       unsigned long *nr_segs, size_t *count, int access_flags)
-{
-       unsigned long   seg;
-       size_t cnt = 0;
-       for (seg = 0; seg < *nr_segs; seg++) {
-               const struct iovec *iv = &iov[seg];
-
-               /*
-                * If any segment has a negative length, or the cumulative
-                * length ever wraps negative then return -EINVAL.
-                */
-               cnt += iv->iov_len;
-               if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
-                       return -EINVAL;
-               if (access_ok(access_flags, iv->iov_base, iv->iov_len))
-                       continue;
-               if (seg == 0)
-                       return -EFAULT;
-               *nr_segs = seg;
-               cnt -= iv->iov_len;     /* This segment is no good */
-               break;
-       }
-       *count = cnt;
-       return 0;
-}
-EXPORT_SYMBOL(generic_segment_checks);
-
 /**
- * generic_file_aio_read - generic filesystem read routine
+ * generic_file_read_iter - generic filesystem read routine
  * @iocb:      kernel I/O control block
- * @iov:       io vector request
- * @nr_segs:   number of segments in the iovec
- * @pos:       current file position
+ * @iter:      destination for the data read
  *
- * This is the "read()" routine for all filesystems
+ * This is the "read_iter()" routine for all filesystems
  * that can use the page cache directly.
  */
 ssize_t
-generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t pos)
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
-       struct file *filp = iocb->ki_filp;
-       ssize_t retval;
-       size_t count;
+       struct file *file = iocb->ki_filp;
+       ssize_t retval = 0;
        loff_t *ppos = &iocb->ki_pos;
-       struct iov_iter i;
-
-       count = 0;
-       retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
-       if (retval)
-               return retval;
-       iov_iter_init(&i, iov, nr_segs, count, 0);
+       loff_t pos = *ppos;
 
        /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
-       if (filp->f_flags & O_DIRECT) {
+       if (file->f_flags & O_DIRECT) {
+               struct address_space *mapping = file->f_mapping;
+               struct inode *inode = mapping->host;
+               size_t count = iov_iter_count(iter);
                loff_t size;
-               struct address_space *mapping;
-               struct inode *inode;
 
-               mapping = filp->f_mapping;
-               inode = mapping->host;
                if (!count)
                        goto out; /* skip atime */
                size = i_size_read(inode);
                retval = filemap_write_and_wait_range(mapping, pos,
-                                       pos + iov_length(iov, nr_segs) - 1);
+                                       pos + count - 1);
                if (!retval) {
-                       retval = mapping->a_ops->direct_IO(READ, iocb,
-                                                          iov, pos, nr_segs);
+                       struct iov_iter data = *iter;
+                       retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos);
                }
+
                if (retval > 0) {
                        *ppos = pos + retval;
-                       count -= retval;
-                       /*
-                        * If we did a short DIO read we need to skip the
-                        * section of the iov that we've already read data into.
-                        */
-                       iov_iter_advance(&i, retval);
+                       iov_iter_advance(iter, retval);
                }
 
                /*
@@ -1756,17 +1702,17 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                 * and return.  Otherwise fallthrough to buffered io for
                 * the rest of the read.
                 */
-               if (retval < 0 || !count || *ppos >= size) {
-                       file_accessed(filp);
+               if (retval < 0 || !iov_iter_count(iter) || *ppos >= size) {
+                       file_accessed(file);
                        goto out;
                }
        }
 
-       retval = do_generic_file_read(filp, ppos, &i, retval);
+       retval = do_generic_file_read(file, ppos, iter, retval);
 out:
        return retval;
 }
-EXPORT_SYMBOL(generic_file_aio_read);
+EXPORT_SYMBOL(generic_file_read_iter);
 
 #ifdef CONFIG_MMU
 /**
@@ -2378,9 +2324,7 @@ int pagecache_write_end(struct file *file, struct address_space *mapping,
 EXPORT_SYMBOL(pagecache_write_end);
 
 ssize_t
-generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long *nr_segs, loff_t pos,
-               size_t count, size_t ocount)
+generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos)
 {
        struct file     *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
@@ -2388,11 +2332,9 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
        ssize_t         written;
        size_t          write_len;
        pgoff_t         end;
+       struct iov_iter data;
 
-       if (count != ocount)
-               *nr_segs = iov_shorten((struct iovec *)iov, *nr_segs, count);
-
-       write_len = iov_length(iov, *nr_segs);
+       write_len = iov_iter_count(from);
        end = (pos + write_len - 1) >> PAGE_CACHE_SHIFT;
 
        written = filemap_write_and_wait_range(mapping, pos, pos + write_len - 1);
@@ -2419,7 +2361,8 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
                }
        }
 
-       written = mapping->a_ops->direct_IO(WRITE, iocb, iov, pos, *nr_segs);
+       data = *from;
+       written = mapping->a_ops->direct_IO(WRITE, iocb, &data, pos);
 
        /*
         * Finally, try again to invalidate clean pages which might have been
@@ -2436,6 +2379,7 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
 
        if (written > 0) {
                pos += written;
+               iov_iter_advance(from, written);
                if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
                        i_size_write(inode, pos);
                        mark_inode_dirty(inode);
@@ -2577,10 +2521,9 @@ again:
 EXPORT_SYMBOL(generic_perform_write);
 
 /**
- * __generic_file_aio_write - write data to a file
+ * __generic_file_write_iter - write data to a file
  * @iocb:      IO state structure (file, offset, etc.)
- * @iov:       vector with data to write
- * @nr_segs:   number of segments in the vector
+ * @from:      iov_iter with data to write
  *
  * This function does all the work needed for actually writing data to a
  * file. It does all basic checks, removes SUID from the file, updates
@@ -2594,26 +2537,16 @@ EXPORT_SYMBOL(generic_perform_write);
  * A caller has to handle it. This is mainly due to the fact that we want to
  * avoid syncing under i_mutex.
  */
-ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                                unsigned long nr_segs)
+ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct address_space * mapping = file->f_mapping;
-       size_t ocount;          /* original count */
-       size_t count;           /* after file limit checks */
        struct inode    *inode = mapping->host;
        loff_t          pos = iocb->ki_pos;
        ssize_t         written = 0;
        ssize_t         err;
        ssize_t         status;
-       struct iov_iter from;
-
-       ocount = 0;
-       err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
-       if (err)
-               return err;
-
-       count = ocount;
+       size_t          count = iov_iter_count(from);
 
        /* We can write back this queue in page reclaim */
        current->backing_dev_info = mapping->backing_dev_info;
@@ -2624,6 +2557,8 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (count == 0)
                goto out;
 
+       iov_iter_truncate(from, count);
+
        err = file_remove_suid(file);
        if (err)
                goto out;
@@ -2632,17 +2567,13 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (err)
                goto out;
 
-       iov_iter_init(&from, iov, nr_segs, count, 0);
-
        /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
        if (unlikely(file->f_flags & O_DIRECT)) {
                loff_t endbyte;
 
-               written = generic_file_direct_write(iocb, iov, &from.nr_segs, pos,
-                                                       count, ocount);
+               written = generic_file_direct_write(iocb, from, pos);
                if (written < 0 || written == count)
                        goto out;
-               iov_iter_advance(&from, written);
 
                /*
                 * direct-io write to a hole: fall through to buffered I/O
@@ -2651,7 +2582,7 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                pos += written;
                count -= written;
 
-               status = generic_perform_write(file, &from, pos);
+               status = generic_perform_write(file, from, pos);
                /*
                 * If generic_perform_write() returned a synchronous error
                 * then we want to return the number of bytes which were
@@ -2683,7 +2614,7 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                         */
                }
        } else {
-               written = generic_perform_write(file, &from, pos);
+               written = generic_perform_write(file, from, pos);
                if (likely(written >= 0))
                        iocb->ki_pos = pos + written;
        }
@@ -2691,30 +2622,25 @@ out:
        current->backing_dev_info = NULL;
        return written ? written : err;
 }
-EXPORT_SYMBOL(__generic_file_aio_write);
+EXPORT_SYMBOL(__generic_file_write_iter);
 
 /**
- * generic_file_aio_write - write data to a file
+ * generic_file_write_iter - write data to a file
  * @iocb:      IO state structure
- * @iov:       vector with data to write
- * @nr_segs:   number of segments in the vector
- * @pos:       position in file where to write
+ * @from:      iov_iter with data to write
  *
- * This is a wrapper around __generic_file_aio_write() to be used by most
+ * This is a wrapper around __generic_file_write_iter() to be used by most
  * filesystems. It takes care of syncing the file in case of O_SYNC file
  * and acquires i_mutex as needed.
  */
-ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t pos)
+ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        ssize_t ret;
 
-       BUG_ON(iocb->ki_pos != pos);
-
        mutex_lock(&inode->i_mutex);
-       ret = __generic_file_aio_write(iocb, iov, nr_segs);
+       ret = __generic_file_write_iter(iocb, from);
        mutex_unlock(&inode->i_mutex);
 
        if (ret > 0) {
@@ -2726,7 +2652,7 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        }
        return ret;
 }
-EXPORT_SYMBOL(generic_file_aio_write);
+EXPORT_SYMBOL(generic_file_write_iter);
 
 /**
  * try_to_release_page() - release old fs-specific metadata on a page
index 10e46cd721de5876d0016aab5969d0b2c6ebdeb3..7b5dbd1517b5594b05d5590cae29c3eb3a1dada2 100644 (file)
@@ -1,8 +1,10 @@
 #include <linux/export.h>
 #include <linux/uio.h>
 #include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
 
-size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
+static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
        size_t skip, copy, left, wanted;
@@ -72,13 +74,97 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
        }
        kunmap(page);
 done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *to;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_readable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               to = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_from_user_inatomic(to, buf, copy);
+               copy -= left;
+               skip += copy;
+               to += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_from_user_inatomic(to, buf, copy);
+                       copy -= left;
+                       skip = copy;
+                       to += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = to - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       to = kaddr + offset;
+       left = __copy_from_user(to, buf, copy);
+       copy -= left;
+       skip += copy;
+       to += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_from_user(to, buf, copy);
+               copy -= left;
+               skip = copy;
+               to += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
        i->count -= wanted - bytes;
        i->nr_segs -= iov - i->iov;
        i->iov = iov;
        i->iov_offset = skip;
        return wanted - bytes;
 }
-EXPORT_SYMBOL(copy_page_to_iter);
 
 static size_t __iovec_copy_from_user_inatomic(char *vaddr,
                        const struct iovec *iov, size_t base, size_t bytes)
@@ -107,7 +193,7 @@ static size_t __iovec_copy_from_user_inatomic(char *vaddr,
  * were successfully copied.  If a fault is encountered then return the number of
  * bytes which were copied.
  */
-size_t iov_iter_copy_from_user_atomic(struct page *page,
+static size_t copy_from_user_atomic_iovec(struct page *page,
                struct iov_iter *i, unsigned long offset, size_t bytes)
 {
        char *kaddr;
@@ -127,36 +213,8 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
 
        return copied;
 }
-EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
-
-/*
- * This has the same sideeffects and return value as
- * iov_iter_copy_from_user_atomic().
- * The difference is that it attempts to resolve faults.
- * Page must not be locked.
- */
-size_t iov_iter_copy_from_user(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes)
-{
-       char *kaddr;
-       size_t copied;
-
-       kaddr = kmap(page);
-       if (likely(i->nr_segs == 1)) {
-               int left;
-               char __user *buf = i->iov->iov_base + i->iov_offset;
-               left = __copy_from_user(kaddr + offset, buf, bytes);
-               copied = bytes - left;
-       } else {
-               copied = __iovec_copy_from_user_inatomic(kaddr + offset,
-                                               i->iov, i->iov_offset, bytes);
-       }
-       kunmap(page);
-       return copied;
-}
-EXPORT_SYMBOL(iov_iter_copy_from_user);
 
-void iov_iter_advance(struct iov_iter *i, size_t bytes)
+static void advance_iovec(struct iov_iter *i, size_t bytes)
 {
        BUG_ON(i->count < bytes);
 
@@ -191,7 +249,6 @@ void iov_iter_advance(struct iov_iter *i, size_t bytes)
                i->nr_segs = nr_segs;
        }
 }
-EXPORT_SYMBOL(iov_iter_advance);
 
 /*
  * Fault in the first iovec of the given iov_iter, to a maximum length
@@ -204,21 +261,483 @@ EXPORT_SYMBOL(iov_iter_advance);
  */
 int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
 {
-       char __user *buf = i->iov->iov_base + i->iov_offset;
-       bytes = min(bytes, i->iov->iov_len - i->iov_offset);
-       return fault_in_pages_readable(buf, bytes);
+       if (!(i->type & ITER_BVEC)) {
+               char __user *buf = i->iov->iov_base + i->iov_offset;
+               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
+               return fault_in_pages_readable(buf, bytes);
+       }
+       return 0;
 }
 EXPORT_SYMBOL(iov_iter_fault_in_readable);
 
+static unsigned long alignment_iovec(const struct iov_iter *i)
+{
+       const struct iovec *iov = i->iov;
+       unsigned long res;
+       size_t size = i->count;
+       size_t n;
+
+       if (!size)
+               return 0;
+
+       res = (unsigned long)iov->iov_base + i->iov_offset;
+       n = iov->iov_len - i->iov_offset;
+       if (n >= size)
+               return res | size;
+       size -= n;
+       res |= n;
+       while (size > (++iov)->iov_len) {
+               res |= (unsigned long)iov->iov_base | iov->iov_len;
+               size -= iov->iov_len;
+       }
+       res |= (unsigned long)iov->iov_base | size;
+       return res;
+}
+
+void iov_iter_init(struct iov_iter *i, int direction,
+                       const struct iovec *iov, unsigned long nr_segs,
+                       size_t count)
+{
+       /* It will get better.  Eventually... */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               direction |= ITER_KVEC;
+       i->type = direction;
+       i->iov = iov;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_init);
+
+static ssize_t get_pages_iovec(struct iov_iter *i,
+                  struct page **pages, size_t maxsize,
+                  size_t *start)
+{
+       size_t offset = i->iov_offset;
+       const struct iovec *iov = i->iov;
+       size_t len;
+       unsigned long addr;
+       int n;
+       int res;
+
+       len = iov->iov_len - offset;
+       if (len > i->count)
+               len = i->count;
+       if (len > maxsize)
+               len = maxsize;
+       addr = (unsigned long)iov->iov_base + offset;
+       len += *start = addr & (PAGE_SIZE - 1);
+       addr &= ~(PAGE_SIZE - 1);
+       n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
+       res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
+       if (unlikely(res < 0))
+               return res;
+       return (res == n ? len : res * PAGE_SIZE) - *start;
+}
+
+static ssize_t get_pages_alloc_iovec(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  size_t *start)
+{
+       size_t offset = i->iov_offset;
+       const struct iovec *iov = i->iov;
+       size_t len;
+       unsigned long addr;
+       void *p;
+       int n;
+       int res;
+
+       len = iov->iov_len - offset;
+       if (len > i->count)
+               len = i->count;
+       if (len > maxsize)
+               len = maxsize;
+       addr = (unsigned long)iov->iov_base + offset;
+       len += *start = addr & (PAGE_SIZE - 1);
+       addr &= ~(PAGE_SIZE - 1);
+       n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
+       
+       p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
+       if (!p)
+               p = vmalloc(n * sizeof(struct page *));
+       if (!p)
+               return -ENOMEM;
+
+       res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
+       if (unlikely(res < 0)) {
+               kvfree(p);
+               return res;
+       }
+       *pages = p;
+       return (res == n ? len : res * PAGE_SIZE) - *start;
+}
+
+static int iov_iter_npages_iovec(const struct iov_iter *i, int maxpages)
+{
+       size_t offset = i->iov_offset;
+       size_t size = i->count;
+       const struct iovec *iov = i->iov;
+       int npages = 0;
+       int n;
+
+       for (n = 0; size && n < i->nr_segs; n++, iov++) {
+               unsigned long addr = (unsigned long)iov->iov_base + offset;
+               size_t len = iov->iov_len - offset;
+               offset = 0;
+               if (unlikely(!len))     /* empty segment */
+                       continue;
+               if (len > size)
+                       len = size;
+               npages += (addr + len + PAGE_SIZE - 1) / PAGE_SIZE
+                         - addr / PAGE_SIZE;
+               if (npages >= maxpages) /* don't bother going further */
+                       return maxpages;
+               size -= len;
+               offset = 0;
+       }
+       return min(npages, maxpages);
+}
+
+static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
+{
+       char *from = kmap_atomic(page);
+       memcpy(to, from + offset, len);
+       kunmap_atomic(from);
+}
+
+static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
+{
+       char *to = kmap_atomic(page);
+       memcpy(to + offset, from, len);
+       kunmap_atomic(to);
+}
+
+static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, wanted;
+       const struct bio_vec *bvec;
+       void *kaddr, *from;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       bvec = i->bvec;
+       skip = i->iov_offset;
+       copy = min_t(size_t, bytes, bvec->bv_len - skip);
+
+       kaddr = kmap_atomic(page);
+       from = kaddr + offset;
+       memcpy_to_page(bvec->bv_page, skip + bvec->bv_offset, from, copy);
+       skip += copy;
+       from += copy;
+       bytes -= copy;
+       while (bytes) {
+               bvec++;
+               copy = min(bytes, (size_t)bvec->bv_len);
+               memcpy_to_page(bvec->bv_page, bvec->bv_offset, from, copy);
+               skip = copy;
+               from += copy;
+               bytes -= copy;
+       }
+       kunmap_atomic(kaddr);
+       if (skip == bvec->bv_len) {
+               bvec++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= bvec - i->bvec;
+       i->bvec = bvec;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, wanted;
+       const struct bio_vec *bvec;
+       void *kaddr, *to;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       bvec = i->bvec;
+       skip = i->iov_offset;
+
+       kaddr = kmap_atomic(page);
+
+       to = kaddr + offset;
+
+       copy = min(bytes, bvec->bv_len - skip);
+
+       memcpy_from_page(to, bvec->bv_page, bvec->bv_offset + skip, copy);
+
+       to += copy;
+       skip += copy;
+       bytes -= copy;
+
+       while (bytes) {
+               bvec++;
+               copy = min(bytes, (size_t)bvec->bv_len);
+               memcpy_from_page(to, bvec->bv_page, bvec->bv_offset, copy);
+               skip = copy;
+               to += copy;
+               bytes -= copy;
+       }
+       kunmap_atomic(kaddr);
+       if (skip == bvec->bv_len) {
+               bvec++;
+               skip = 0;
+       }
+       i->count -= wanted;
+       i->nr_segs -= bvec - i->bvec;
+       i->bvec = bvec;
+       i->iov_offset = skip;
+       return wanted;
+}
+
+static size_t copy_from_user_bvec(struct page *page,
+               struct iov_iter *i, unsigned long offset, size_t bytes)
+{
+       char *kaddr;
+       size_t left;
+       const struct bio_vec *bvec;
+       size_t base = i->iov_offset;
+
+       kaddr = kmap_atomic(page);
+       for (left = bytes, bvec = i->bvec; left; bvec++, base = 0) {
+               size_t copy = min(left, bvec->bv_len - base);
+               if (!bvec->bv_len)
+                       continue;
+               memcpy_from_page(kaddr + offset, bvec->bv_page,
+                                bvec->bv_offset + base, copy);
+               offset += copy;
+               left -= copy;
+       }
+       kunmap_atomic(kaddr);
+       return bytes;
+}
+
+static void advance_bvec(struct iov_iter *i, size_t bytes)
+{
+       BUG_ON(i->count < bytes);
+
+       if (likely(i->nr_segs == 1)) {
+               i->iov_offset += bytes;
+               i->count -= bytes;
+       } else {
+               const struct bio_vec *bvec = i->bvec;
+               size_t base = i->iov_offset;
+               unsigned long nr_segs = i->nr_segs;
+
+               /*
+                * The !iov->iov_len check ensures we skip over unlikely
+                * zero-length segments (without overruning the iovec).
+                */
+               while (bytes || unlikely(i->count && !bvec->bv_len)) {
+                       int copy;
+
+                       copy = min(bytes, bvec->bv_len - base);
+                       BUG_ON(!i->count || i->count < copy);
+                       i->count -= copy;
+                       bytes -= copy;
+                       base += copy;
+                       if (bvec->bv_len == base) {
+                               bvec++;
+                               nr_segs--;
+                               base = 0;
+                       }
+               }
+               i->bvec = bvec;
+               i->iov_offset = base;
+               i->nr_segs = nr_segs;
+       }
+}
+
+static unsigned long alignment_bvec(const struct iov_iter *i)
+{
+       const struct bio_vec *bvec = i->bvec;
+       unsigned long res;
+       size_t size = i->count;
+       size_t n;
+
+       if (!size)
+               return 0;
+
+       res = bvec->bv_offset + i->iov_offset;
+       n = bvec->bv_len - i->iov_offset;
+       if (n >= size)
+               return res | size;
+       size -= n;
+       res |= n;
+       while (size > (++bvec)->bv_len) {
+               res |= bvec->bv_offset | bvec->bv_len;
+               size -= bvec->bv_len;
+       }
+       res |= bvec->bv_offset | size;
+       return res;
+}
+
+static ssize_t get_pages_bvec(struct iov_iter *i,
+                  struct page **pages, size_t maxsize,
+                  size_t *start)
+{
+       const struct bio_vec *bvec = i->bvec;
+       size_t len = bvec->bv_len - i->iov_offset;
+       if (len > i->count)
+               len = i->count;
+       if (len > maxsize)
+               len = maxsize;
+       *start = bvec->bv_offset + i->iov_offset;
+
+       get_page(*pages = bvec->bv_page);
+
+       return len;
+}
+
+static ssize_t get_pages_alloc_bvec(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  size_t *start)
+{
+       const struct bio_vec *bvec = i->bvec;
+       size_t len = bvec->bv_len - i->iov_offset;
+       if (len > i->count)
+               len = i->count;
+       if (len > maxsize)
+               len = maxsize;
+       *start = bvec->bv_offset + i->iov_offset;
+
+       *pages = kmalloc(sizeof(struct page *), GFP_KERNEL);
+       if (!*pages)
+               return -ENOMEM;
+
+       get_page(**pages = bvec->bv_page);
+
+       return len;
+}
+
+static int iov_iter_npages_bvec(const struct iov_iter *i, int maxpages)
+{
+       size_t offset = i->iov_offset;
+       size_t size = i->count;
+       const struct bio_vec *bvec = i->bvec;
+       int npages = 0;
+       int n;
+
+       for (n = 0; size && n < i->nr_segs; n++, bvec++) {
+               size_t len = bvec->bv_len - offset;
+               offset = 0;
+               if (unlikely(!len))     /* empty segment */
+                       continue;
+               if (len > size)
+                       len = size;
+               npages++;
+               if (npages >= maxpages) /* don't bother going further */
+                       return maxpages;
+               size -= len;
+               offset = 0;
+       }
+       return min(npages, maxpages);
+}
+
+size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & ITER_BVEC)
+               return copy_page_to_iter_bvec(page, offset, bytes, i);
+       else
+               return copy_page_to_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_to_iter);
+
+size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & ITER_BVEC)
+               return copy_page_from_iter_bvec(page, offset, bytes, i);
+       else
+               return copy_page_from_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_from_iter);
+
+size_t iov_iter_copy_from_user_atomic(struct page *page,
+               struct iov_iter *i, unsigned long offset, size_t bytes)
+{
+       if (i->type & ITER_BVEC)
+               return copy_from_user_bvec(page, i, offset, bytes);
+       else
+               return copy_from_user_atomic_iovec(page, i, offset, bytes);
+}
+EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
+
+void iov_iter_advance(struct iov_iter *i, size_t size)
+{
+       if (i->type & ITER_BVEC)
+               advance_bvec(i, size);
+       else
+               advance_iovec(i, size);
+}
+EXPORT_SYMBOL(iov_iter_advance);
+
 /*
  * Return the count of just the current iov_iter segment.
  */
 size_t iov_iter_single_seg_count(const struct iov_iter *i)
 {
-       const struct iovec *iov = i->iov;
        if (i->nr_segs == 1)
                return i->count;
+       else if (i->type & ITER_BVEC)
+               return min(i->count, i->iov->iov_len - i->iov_offset);
        else
-               return min(i->count, iov->iov_len - i->iov_offset);
+               return min(i->count, i->bvec->bv_len - i->iov_offset);
 }
 EXPORT_SYMBOL(iov_iter_single_seg_count);
+
+unsigned long iov_iter_alignment(const struct iov_iter *i)
+{
+       if (i->type & ITER_BVEC)
+               return alignment_bvec(i);
+       else
+               return alignment_iovec(i);
+}
+EXPORT_SYMBOL(iov_iter_alignment);
+
+ssize_t iov_iter_get_pages(struct iov_iter *i,
+                  struct page **pages, size_t maxsize,
+                  size_t *start)
+{
+       if (i->type & ITER_BVEC)
+               return get_pages_bvec(i, pages, maxsize, start);
+       else
+               return get_pages_iovec(i, pages, maxsize, start);
+}
+EXPORT_SYMBOL(iov_iter_get_pages);
+
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  size_t *start)
+{
+       if (i->type & ITER_BVEC)
+               return get_pages_alloc_bvec(i, pages, maxsize, start);
+       else
+               return get_pages_alloc_iovec(i, pages, maxsize, start);
+}
+EXPORT_SYMBOL(iov_iter_get_pages_alloc);
+
+int iov_iter_npages(const struct iov_iter *i, int maxpages)
+{
+       if (i->type & ITER_BVEC)
+               return iov_iter_npages_bvec(i, maxpages);
+       else
+               return iov_iter_npages_iovec(i, maxpages);
+}
+EXPORT_SYMBOL(iov_iter_npages);
index e9d6ca9a01a9a3e0b1f56029a332b51c9202455e..a810ba923cdd5304e655fd93e69a6f796e80e417 100644 (file)
@@ -27,6 +27,9 @@
 
 static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
 static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
+#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
+static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock;
+#endif
 
 struct memblock memblock __initdata_memblock = {
        .memory.regions         = memblock_memory_init_regions,
@@ -37,6 +40,12 @@ struct memblock memblock __initdata_memblock = {
        .reserved.cnt           = 1,    /* empty dummy entry */
        .reserved.max           = INIT_MEMBLOCK_REGIONS,
 
+#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
+       .physmem.regions        = memblock_physmem_init_regions,
+       .physmem.cnt            = 1,    /* empty dummy entry */
+       .physmem.max            = INIT_PHYSMEM_REGIONS,
+#endif
+
        .bottom_up              = false,
        .current_limit          = MEMBLOCK_ALLOC_ANYWHERE,
 };
@@ -472,7 +481,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type,
 }
 
 /**
- * memblock_add_region - add new memblock region
+ * memblock_add_range - add new memblock region
  * @type: memblock type to add new region into
  * @base: base address of the new region
  * @size: size of the new region
@@ -487,7 +496,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type,
  * RETURNS:
  * 0 on success, -errno on failure.
  */
-static int __init_memblock memblock_add_region(struct memblock_type *type,
+int __init_memblock memblock_add_range(struct memblock_type *type,
                                phys_addr_t base, phys_addr_t size,
                                int nid, unsigned long flags)
 {
@@ -569,12 +578,12 @@ repeat:
 int __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size,
                                       int nid)
 {
-       return memblock_add_region(&memblock.memory, base, size, nid, 0);
+       return memblock_add_range(&memblock.memory, base, size, nid, 0);
 }
 
 int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
 {
-       return memblock_add_region(&memblock.memory, base, size,
+       return memblock_add_range(&memblock.memory, base, size,
                                   MAX_NUMNODES, 0);
 }
 
@@ -654,8 +663,8 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
        return 0;
 }
 
-static int __init_memblock __memblock_remove(struct memblock_type *type,
-                                            phys_addr_t base, phys_addr_t size)
+int __init_memblock memblock_remove_range(struct memblock_type *type,
+                                         phys_addr_t base, phys_addr_t size)
 {
        int start_rgn, end_rgn;
        int i, ret;
@@ -671,9 +680,10 @@ static int __init_memblock __memblock_remove(struct memblock_type *type,
 
 int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)
 {
-       return __memblock_remove(&memblock.memory, base, size);
+       return memblock_remove_range(&memblock.memory, base, size);
 }
 
+
 int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
 {
        memblock_dbg("   memblock_free: [%#016llx-%#016llx] %pF\n",
@@ -681,7 +691,7 @@ int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
                     (unsigned long long)base + size - 1,
                     (void *)_RET_IP_);
 
-       return __memblock_remove(&memblock.reserved, base, size);
+       return memblock_remove_range(&memblock.reserved, base, size);
 }
 
 static int __init_memblock memblock_reserve_region(phys_addr_t base,
@@ -696,7 +706,7 @@ static int __init_memblock memblock_reserve_region(phys_addr_t base,
                     (unsigned long long)base + size - 1,
                     flags, (void *)_RET_IP_);
 
-       return memblock_add_region(_rgn, base, size, nid, flags);
+       return memblock_add_range(_rgn, base, size, nid, flags);
 }
 
 int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
@@ -758,17 +768,19 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
 }
 
 /**
- * __next_free_mem_range - next function for for_each_free_mem_range()
+ * __next__mem_range - next function for for_each_free_mem_range() etc.
  * @idx: pointer to u64 loop variable
  * @nid: node selector, %NUMA_NO_NODE for all nodes
+ * @type_a: pointer to memblock_type from where the range is taken
+ * @type_b: pointer to memblock_type which excludes memory from being taken
  * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL
  * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL
  * @out_nid: ptr to int for nid of the range, can be %NULL
  *
- * Find the first free area from *@idx which matches @nid, fill the out
+ * Find the first area from *@idx which matches @nid, fill the out
  * parameters, and update *@idx for the next iteration.  The lower 32bit of
- * *@idx contains index into memory region and the upper 32bit indexes the
- * areas before each reserved region.  For example, if reserved regions
+ * *@idx contains index into type_a and the upper 32bit indexes the
+ * areas before each region in type_b. For example, if type_b regions
  * look like the following,
  *
  *     0:[0-16), 1:[32-48), 2:[128-130)
@@ -780,53 +792,77 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
  * As both region arrays are sorted, the function advances the two indices
  * in lockstep and returns each intersection.
  */
-void __init_memblock __next_free_mem_range(u64 *idx, int nid,
-                                          phys_addr_t *out_start,
-                                          phys_addr_t *out_end, int *out_nid)
+void __init_memblock __next_mem_range(u64 *idx, int nid,
+                                     struct memblock_type *type_a,
+                                     struct memblock_type *type_b,
+                                     phys_addr_t *out_start,
+                                     phys_addr_t *out_end, int *out_nid)
 {
-       struct memblock_type *mem = &memblock.memory;
-       struct memblock_type *rsv = &memblock.reserved;
-       int mi = *idx & 0xffffffff;
-       int ri = *idx >> 32;
+       int idx_a = *idx & 0xffffffff;
+       int idx_b = *idx >> 32;
 
-       if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
+       if (WARN_ONCE(nid == MAX_NUMNODES,
+       "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
                nid = NUMA_NO_NODE;
 
-       for ( ; mi < mem->cnt; mi++) {
-               struct memblock_region *m = &mem->regions[mi];
+       for (; idx_a < type_a->cnt; idx_a++) {
+               struct memblock_region *m = &type_a->regions[idx_a];
+
                phys_addr_t m_start = m->base;
                phys_addr_t m_end = m->base + m->size;
+               int         m_nid = memblock_get_region_node(m);
 
                /* only memory regions are associated with nodes, check it */
-               if (nid != NUMA_NO_NODE && nid != memblock_get_region_node(m))
+               if (nid != NUMA_NO_NODE && nid != m_nid)
                        continue;
 
-               /* scan areas before each reservation for intersection */
-               for ( ; ri < rsv->cnt + 1; ri++) {
-                       struct memblock_region *r = &rsv->regions[ri];
-                       phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0;
-                       phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX;
+               if (!type_b) {
+                       if (out_start)
+                               *out_start = m_start;
+                       if (out_end)
+                               *out_end = m_end;
+                       if (out_nid)
+                               *out_nid = m_nid;
+                       idx_a++;
+                       *idx = (u32)idx_a | (u64)idx_b << 32;
+                       return;
+               }
 
-                       /* if ri advanced past mi, break out to advance mi */
+               /* scan areas before each reservation */
+               for (; idx_b < type_b->cnt + 1; idx_b++) {
+                       struct memblock_region *r;
+                       phys_addr_t r_start;
+                       phys_addr_t r_end;
+
+                       r = &type_b->regions[idx_b];
+                       r_start = idx_b ? r[-1].base + r[-1].size : 0;
+                       r_end = idx_b < type_b->cnt ?
+                               r->base : ULLONG_MAX;
+
+                       /*
+                        * if idx_b advanced past idx_a,
+                        * break out to advance idx_a
+                        */
                        if (r_start >= m_end)
                                break;
                        /* if the two regions intersect, we're done */
                        if (m_start < r_end) {
                                if (out_start)
-                                       *out_start = max(m_start, r_start);
+                                       *out_start =
+                                               max(m_start, r_start);
                                if (out_end)
                                        *out_end = min(m_end, r_end);
                                if (out_nid)
-                                       *out_nid = memblock_get_region_node(m);
+                                       *out_nid = m_nid;
                                /*
-                                * The region which ends first is advanced
-                                * for the next iteration.
+                                * The region which ends first is
+                                * advanced for the next iteration.
                                 */
                                if (m_end <= r_end)
-                                       mi++;
+                                       idx_a++;
                                else
-                                       ri++;
-                               *idx = (u32)mi | (u64)ri << 32;
+                                       idx_b++;
+                               *idx = (u32)idx_a | (u64)idx_b << 32;
                                return;
                        }
                }
@@ -837,57 +873,80 @@ void __init_memblock __next_free_mem_range(u64 *idx, int nid,
 }
 
 /**
- * __next_free_mem_range_rev - next function for for_each_free_mem_range_reverse()
+ * __next_mem_range_rev - generic next function for for_each_*_range_rev()
+ *
+ * Finds the next range from type_a which is not marked as unsuitable
+ * in type_b.
+ *
  * @idx: pointer to u64 loop variable
  * @nid: nid: node selector, %NUMA_NO_NODE for all nodes
+ * @type_a: pointer to memblock_type from where the range is taken
+ * @type_b: pointer to memblock_type which excludes memory from being taken
  * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL
  * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL
  * @out_nid: ptr to int for nid of the range, can be %NULL
  *
- * Reverse of __next_free_mem_range().
- *
- * Linux kernel cannot migrate pages used by itself. Memory hotplug users won't
- * be able to hot-remove hotpluggable memory used by the kernel. So this
- * function skip hotpluggable regions if needed when allocating memory for the
- * kernel.
+ * Reverse of __next_mem_range().
  */
-void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid,
-                                          phys_addr_t *out_start,
-                                          phys_addr_t *out_end, int *out_nid)
+void __init_memblock __next_mem_range_rev(u64 *idx, int nid,
+                                         struct memblock_type *type_a,
+                                         struct memblock_type *type_b,
+                                         phys_addr_t *out_start,
+                                         phys_addr_t *out_end, int *out_nid)
 {
-       struct memblock_type *mem = &memblock.memory;
-       struct memblock_type *rsv = &memblock.reserved;
-       int mi = *idx & 0xffffffff;
-       int ri = *idx >> 32;
+       int idx_a = *idx & 0xffffffff;
+       int idx_b = *idx >> 32;
 
        if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
                nid = NUMA_NO_NODE;
 
        if (*idx == (u64)ULLONG_MAX) {
-               mi = mem->cnt - 1;
-               ri = rsv->cnt;
+               idx_a = type_a->cnt - 1;
+               idx_b = type_b->cnt;
        }
 
-       for ( ; mi >= 0; mi--) {
-               struct memblock_region *m = &mem->regions[mi];
+       for (; idx_a >= 0; idx_a--) {
+               struct memblock_region *m = &type_a->regions[idx_a];
+
                phys_addr_t m_start = m->base;
                phys_addr_t m_end = m->base + m->size;
+               int m_nid = memblock_get_region_node(m);
 
                /* only memory regions are associated with nodes, check it */
-               if (nid != NUMA_NO_NODE && nid != memblock_get_region_node(m))
+               if (nid != NUMA_NO_NODE && nid != m_nid)
                        continue;
 
                /* skip hotpluggable memory regions if needed */
                if (movable_node_is_enabled() && memblock_is_hotpluggable(m))
                        continue;
 
-               /* scan areas before each reservation for intersection */
-               for ( ; ri >= 0; ri--) {
-                       struct memblock_region *r = &rsv->regions[ri];
-                       phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0;
-                       phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX;
+               if (!type_b) {
+                       if (out_start)
+                               *out_start = m_start;
+                       if (out_end)
+                               *out_end = m_end;
+                       if (out_nid)
+                               *out_nid = m_nid;
+                       idx_a++;
+                       *idx = (u32)idx_a | (u64)idx_b << 32;
+                       return;
+               }
+
+               /* scan areas before each reservation */
+               for (; idx_b >= 0; idx_b--) {
+                       struct memblock_region *r;
+                       phys_addr_t r_start;
+                       phys_addr_t r_end;
+
+                       r = &type_b->regions[idx_b];
+                       r_start = idx_b ? r[-1].base + r[-1].size : 0;
+                       r_end = idx_b < type_b->cnt ?
+                               r->base : ULLONG_MAX;
+                       /*
+                        * if idx_b advanced past idx_a,
+                        * break out to advance idx_a
+                        */
 
-                       /* if ri advanced past mi, break out to advance mi */
                        if (r_end <= m_start)
                                break;
                        /* if the two regions intersect, we're done */
@@ -897,18 +956,17 @@ void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid,
                                if (out_end)
                                        *out_end = min(m_end, r_end);
                                if (out_nid)
-                                       *out_nid = memblock_get_region_node(m);
-
+                                       *out_nid = m_nid;
                                if (m_start >= r_start)
-                                       mi--;
+                                       idx_a--;
                                else
-                                       ri--;
-                               *idx = (u32)mi | (u64)ri << 32;
+                                       idx_b--;
+                               *idx = (u32)idx_a | (u64)idx_b << 32;
                                return;
                        }
                }
        }
-
+       /* signal end of iteration */
        *idx = ULLONG_MAX;
 }
 
@@ -1201,7 +1259,7 @@ void __init __memblock_free_early(phys_addr_t base, phys_addr_t size)
                     __func__, (u64)base, (u64)base + size - 1,
                     (void *)_RET_IP_);
        kmemleak_free_part(__va(base), size);
-       __memblock_remove(&memblock.reserved, base, size);
+       memblock_remove_range(&memblock.reserved, base, size);
 }
 
 /*
@@ -1287,8 +1345,10 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
        }
 
        /* truncate both memory and reserved regions */
-       __memblock_remove(&memblock.memory, max_addr, (phys_addr_t)ULLONG_MAX);
-       __memblock_remove(&memblock.reserved, max_addr, (phys_addr_t)ULLONG_MAX);
+       memblock_remove_range(&memblock.memory, max_addr,
+                             (phys_addr_t)ULLONG_MAX);
+       memblock_remove_range(&memblock.reserved, max_addr,
+                             (phys_addr_t)ULLONG_MAX);
 }
 
 static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
@@ -1502,6 +1562,9 @@ static int __init memblock_init_debugfs(void)
                return -ENXIO;
        debugfs_create_file("memory", S_IRUGO, root, &memblock.memory, &memblock_debug_fops);
        debugfs_create_file("reserved", S_IRUGO, root, &memblock.reserved, &memblock_debug_fops);
+#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
+       debugfs_create_file("physmem", S_IRUGO, root, &memblock.physmem, &memblock_debug_fops);
+#endif
 
        return 0;
 }
index 7c59ef681381bb7afeef2cf5207d269e9a95c1f8..33bb38c4aad716b326c299d63a6cb72b74759bbc 100644 (file)
@@ -259,9 +259,17 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
                struct kiocb kiocb;
                struct file *swap_file = sis->swap_file;
                struct address_space *mapping = swap_file->f_mapping;
-               struct iovec iov = {
-                       .iov_base = kmap(page),
-                       .iov_len  = PAGE_SIZE,
+               struct bio_vec bv = {
+                       .bv_page = page,
+                       .bv_len  = PAGE_SIZE,
+                       .bv_offset = 0
+               };
+               struct iov_iter from = {
+                       .type = ITER_BVEC | WRITE,
+                       .count = PAGE_SIZE,
+                       .iov_offset = 0,
+                       .nr_segs = 1,
+                       .bvec = &bv
                };
 
                init_sync_kiocb(&kiocb, swap_file);
@@ -270,10 +278,9 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
 
                set_page_writeback(page);
                unlock_page(page);
-               ret = mapping->a_ops->direct_IO(KERNEL_WRITE,
-                                               &kiocb, &iov,
-                                               kiocb.ki_pos, 1);
-               kunmap(page);
+               ret = mapping->a_ops->direct_IO(ITER_BVEC | WRITE,
+                                               &kiocb, &from,
+                                               kiocb.ki_pos);
                if (ret == PAGE_SIZE) {
                        count_vm_event(PSWPOUT);
                        ret = 0;
index 8505c9262b35853e22580c6c9b74c4d12bc86acc..5077afcd9e116b16b17c7b0ed51930d570f88701 100644 (file)
@@ -46,11 +46,7 @@ static int process_vm_rw_pages(struct page **pages,
                        copy = len;
 
                if (vm_write) {
-                       if (copy > iov_iter_count(iter))
-                               copy = iov_iter_count(iter);
-                       copied = iov_iter_copy_from_user(page, iter,
-                                       offset, copy);
-                       iov_iter_advance(iter, copied);
+                       copied = copy_page_from_iter(page, offset, copy, iter);
                        set_page_dirty_lock(page);
                } else {
                        copied = copy_page_to_iter(page, offset, copy, iter);
@@ -278,7 +274,7 @@ static ssize_t process_vm_rw(pid_t pid,
        if (rc <= 0)
                goto free_iovecs;
 
-       iov_iter_init(&iter, iov_l, liovcnt, rc, 0);
+       iov_iter_init(&iter, vm_write ? WRITE : READ, iov_l, liovcnt, rc);
 
        rc = rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV,
                                   iovstack_r, &iov_r);
@@ -341,7 +337,7 @@ compat_process_vm_rw(compat_pid_t pid,
                                                  &iov_l);
        if (rc <= 0)
                goto free_iovecs;
-       iov_iter_init(&iter, iov_l, liovcnt, rc, 0);
+       iov_iter_init(&iter, vm_write ? WRITE : READ, iov_l, liovcnt, rc);
        rc = compat_rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt,
                                          UIO_FASTIOV, iovstack_r,
                                          &iov_r);
index 9f70e02111c6adcd090d8372ae0405b0f22b9abc..de834ab8b6b90a0a406da4c96278ef946702e7ad 100644 (file)
@@ -1402,8 +1402,7 @@ shmem_write_end(struct file *file, struct address_space *mapping,
        return copied;
 }
 
-static ssize_t shmem_file_aio_read(struct kiocb *iocb,
-               const struct iovec *iov, unsigned long nr_segs, loff_t pos)
+static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
@@ -1412,15 +1411,8 @@ static ssize_t shmem_file_aio_read(struct kiocb *iocb,
        unsigned long offset;
        enum sgp_type sgp = SGP_READ;
        int error = 0;
-       ssize_t retval;
-       size_t count;
+       ssize_t retval = 0;
        loff_t *ppos = &iocb->ki_pos;
-       struct iov_iter iter;
-
-       retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
-       if (retval)
-               return retval;
-       iov_iter_init(&iter, iov, nr_segs, count, 0);
 
        /*
         * Might this read be for a stacking filesystem?  Then when reading
@@ -1496,14 +1488,14 @@ static ssize_t shmem_file_aio_read(struct kiocb *iocb,
                 * Ok, we have the page, and it's up-to-date, so
                 * now we can copy it to user space...
                 */
-               ret = copy_page_to_iter(page, offset, nr, &iter);
+               ret = copy_page_to_iter(page, offset, nr, to);
                retval += ret;
                offset += ret;
                index += offset >> PAGE_CACHE_SHIFT;
                offset &= ~PAGE_CACHE_MASK;
 
                page_cache_release(page);
-               if (!iov_iter_count(&iter))
+               if (!iov_iter_count(to))
                        break;
                if (ret < nr) {
                        error = -EFAULT;
@@ -2625,13 +2617,13 @@ static const struct file_operations shmem_file_operations = {
        .mmap           = shmem_mmap,
 #ifdef CONFIG_TMPFS
        .llseek         = shmem_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = shmem_file_aio_read,
-       .aio_write      = generic_file_aio_write,
+       .read           = new_sync_read,
+       .write          = new_sync_write,
+       .read_iter      = shmem_file_read_iter,
+       .write_iter     = generic_file_write_iter,
        .fsync          = noop_fsync,
        .splice_read    = shmem_file_splice_read,
-       .splice_write   = generic_file_splice_write,
+       .splice_write   = iter_file_splice_write,
        .fallocate      = shmem_fallocate,
 #endif
 };
index d4224b397c0e4e4492fa135c3c5ee9b224872c07..1037a3bab50529f84c9d81c383df07dbfbbda081 100644 (file)
@@ -81,10 +81,12 @@ struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr)
        for (i = 0; i < VMACACHE_SIZE; i++) {
                struct vm_area_struct *vma = current->vmacache[i];
 
-               if (vma && vma->vm_start <= addr && vma->vm_end > addr) {
-                       BUG_ON(vma->vm_mm != mm);
+               if (!vma)
+                       continue;
+               if (WARN_ON_ONCE(vma->vm_mm != mm))
+                       break;
+               if (vma->vm_start <= addr && vma->vm_end > addr)
                        return vma;
-               }
        }
 
        return NULL;
index 3f56c8deb3c05f0904917b87113e188dbeff9ef0..11062a64a0101b78ec64baf4fc4c23457b591f73 100644 (file)
@@ -458,7 +458,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
         * stalls if we need to run get_block().  We could test
         * PagePrivate for that.
         *
-        * If this process is currently in __generic_file_aio_write() against
+        * If this process is currently in __generic_file_write_iter() against
         * this page's queue, we can perform writeback even if that
         * will block.
         *
index 733ec283ed1b9e85f9181f67116052f88bb49951..8f025afa29fdac1e65288891dc5977499cac9345 100644 (file)
@@ -706,38 +706,36 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev,
 
 static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
+       struct vlan_pcpu_stats *p;
+       u32 rx_errors = 0, tx_dropped = 0;
+       int i;
 
-       if (vlan_dev_priv(dev)->vlan_pcpu_stats) {
-               struct vlan_pcpu_stats *p;
-               u32 rx_errors = 0, tx_dropped = 0;
-               int i;
-
-               for_each_possible_cpu(i) {
-                       u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes;
-                       unsigned int start;
-
-                       p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
-                       do {
-                               start = u64_stats_fetch_begin_irq(&p->syncp);
-                               rxpackets       = p->rx_packets;
-                               rxbytes         = p->rx_bytes;
-                               rxmulticast     = p->rx_multicast;
-                               txpackets       = p->tx_packets;
-                               txbytes         = p->tx_bytes;
-                       } while (u64_stats_fetch_retry_irq(&p->syncp, start));
-
-                       stats->rx_packets       += rxpackets;
-                       stats->rx_bytes         += rxbytes;
-                       stats->multicast        += rxmulticast;
-                       stats->tx_packets       += txpackets;
-                       stats->tx_bytes         += txbytes;
-                       /* rx_errors & tx_dropped are u32 */
-                       rx_errors       += p->rx_errors;
-                       tx_dropped      += p->tx_dropped;
-               }
-               stats->rx_errors  = rx_errors;
-               stats->tx_dropped = tx_dropped;
+       for_each_possible_cpu(i) {
+               u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes;
+               unsigned int start;
+
+               p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
+               do {
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
+                       rxpackets       = p->rx_packets;
+                       rxbytes         = p->rx_bytes;
+                       rxmulticast     = p->rx_multicast;
+                       txpackets       = p->tx_packets;
+                       txbytes         = p->tx_bytes;
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
+
+               stats->rx_packets       += rxpackets;
+               stats->rx_bytes         += rxbytes;
+               stats->multicast        += rxmulticast;
+               stats->tx_packets       += txpackets;
+               stats->tx_bytes         += txbytes;
+               /* rx_errors & tx_dropped are u32 */
+               rx_errors       += p->rx_errors;
+               tx_dropped      += p->tx_dropped;
        }
+       stats->rx_errors  = rx_errors;
+       stats->tx_dropped = tx_dropped;
+
        return stats;
 }
 
index d958e2dca52fa5bb4d166e0073fa90d18729a73f..095943c02d6e4ae9643cd1099e7e648ef8de6488 100644 (file)
@@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work)
 {
        struct hci_conn *conn = container_of(work, struct hci_conn,
                                             le_conn_timeout.work);
+       struct hci_dev *hdev = conn->hdev;
 
        BT_DBG("");
 
+       /* We could end up here due to having done directed advertising,
+        * so clean up the state if necessary. This should however only
+        * happen with broken hardware or if low duty cycle was used
+        * (which doesn't have a timeout of its own).
+        */
+       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
+               u8 enable = 0x00;
+               hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
+                            &enable);
+               hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
+               return;
+       }
+
        hci_le_create_connection_cancel(conn);
 }
 
@@ -401,6 +415,10 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        case ACL_LINK:
                conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
                break;
+       case LE_LINK:
+               /* conn->src should reflect the local identity address */
+               hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
+               break;
        case SCO_LINK:
                if (lmp_esco_capable(hdev))
                        conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
@@ -545,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
         * favor of connection establishment, we should restart it.
         */
        hci_update_background_scan(hdev);
+
+       /* Re-enable advertising in case this was a failed connection
+        * attempt as a peripheral.
+        */
+       mgmt_reenable_advertising(hdev);
 }
 
 static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
@@ -605,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
        conn->state = BT_CONNECT;
 }
 
+static void hci_req_directed_advertising(struct hci_request *req,
+                                        struct hci_conn *conn)
+{
+       struct hci_dev *hdev = req->hdev;
+       struct hci_cp_le_set_adv_param cp;
+       u8 own_addr_type;
+       u8 enable;
+
+       enable = 0x00;
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+
+       /* Clear the HCI_ADVERTISING bit temporarily so that the
+        * hci_update_random_address knows that it's safe to go ahead
+        * and write a new random address. The flag will be set back on
+        * as soon as the SET_ADV_ENABLE HCI command completes.
+        */
+       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+
+       /* Set require_privacy to false so that the remote device has a
+        * chance of identifying us.
+        */
+       if (hci_update_random_address(req, false, &own_addr_type) < 0)
+               return;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.type = LE_ADV_DIRECT_IND;
+       cp.own_address_type = own_addr_type;
+       cp.direct_addr_type = conn->dst_type;
+       bacpy(&cp.direct_addr, &conn->dst);
+       cp.channel_map = hdev->le_adv_channel_map;
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
+
+       enable = 0x01;
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+
+       conn->state = BT_CONNECT;
+}
+
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
                                u8 dst_type, u8 sec_level, u8 auth_type)
 {
@@ -614,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
        struct hci_request req;
        int err;
 
-       if (test_bit(HCI_ADVERTISING, &hdev->flags))
-               return ERR_PTR(-ENOTSUPP);
-
        /* Some devices send ATT messages as soon as the physical link is
         * established. To be able to handle these ATT messages, the user-
         * space first establishes the connection and then starts the pairing
@@ -664,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
                return ERR_PTR(-ENOMEM);
 
        conn->dst_type = dst_type;
-
-       conn->out = true;
-       conn->link_mode |= HCI_LM_MASTER;
        conn->sec_level = BT_SECURITY_LOW;
        conn->pending_sec_level = sec_level;
        conn->auth_type = auth_type;
 
+       hci_req_init(&req, hdev);
+
+       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
+               hci_req_directed_advertising(&req, conn);
+               goto create_conn;
+       }
+
+       conn->out = true;
+       conn->link_mode |= HCI_LM_MASTER;
+
        params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
        if (params) {
                conn->le_conn_min_interval = params->conn_min_interval;
@@ -680,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
                conn->le_conn_max_interval = hdev->le_conn_max_interval;
        }
 
-       hci_req_init(&req, hdev);
-
        /* If controller is scanning, we stop it since some controllers are
         * not able to scan and connect at the same time. Also set the
         * HCI_LE_SCAN_INTERRUPTED flag so that the command complete
@@ -695,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 
        hci_req_add_le_create_conn(&req, conn);
 
+create_conn:
        err = hci_req_run(&req, create_le_conn_complete);
        if (err) {
                hci_conn_del(conn);
@@ -819,14 +884,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                struct hci_cp_auth_requested cp;
 
-               /* encrypt must be pending if auth is also pending */
-               set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
-
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
                             sizeof(cp), &cp);
+
+               /* If we're already encrypted set the REAUTH_PEND flag,
+                * otherwise set the ENCRYPT_PEND.
+                */
                if (conn->key_type != 0xff)
                        set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
+               else
+                       set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
        }
 
        return 0;
index 1c6ffaa8902f5e9fe32a86f2a19cf9073d6f0dae..d31f144860d127cdf223f2145185feb963e011c4 100644 (file)
@@ -955,14 +955,9 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
        if (count < 3)
                return -EINVAL;
 
-       buf = kzalloc(count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       if (copy_from_user(buf, data, count)) {
-               err = -EFAULT;
-               goto done;
-       }
+       buf = memdup_user(data, count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
 
        if (memcmp(buf, "add", 3) == 0) {
                n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu",
@@ -1828,6 +1823,9 @@ static int __hci_init(struct hci_dev *hdev)
                                    &lowpan_debugfs_fops);
                debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
                                    &le_auto_conn_fops);
+               debugfs_create_u16("discov_interleaved_timeout", 0644,
+                                  hdev->debugfs,
+                                  &hdev->discov_interleaved_timeout);
        }
 
        return 0;
@@ -2033,12 +2031,11 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 
        hci_remove_remote_oob_data(hdev, &data->bdaddr);
 
-       if (ssp)
-               *ssp = data->ssp_mode;
+       *ssp = data->ssp_mode;
 
        ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
        if (ie) {
-               if (ie->data.ssp_mode && ssp)
+               if (ie->data.ssp_mode)
                        *ssp = true;
 
                if (ie->name_state == NAME_NEEDED &&
@@ -3791,6 +3788,7 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->le_conn_max_interval = 0x0038;
 
        hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT;
+       hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT;
 
        mutex_init(&hdev->lock);
        mutex_init(&hdev->req_lock);
index 49774912cb01f23ef6f85cb26f8613f538edec94..ca19fd4bbb8f198ed5d3a3b959c35aceb3a1e54e 100644 (file)
@@ -991,10 +991,25 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
+       if (status)
+               return;
+
        hci_dev_lock(hdev);
 
-       if (!status)
-               mgmt_advertising(hdev, *sent);
+       /* If we're doing connection initation as peripheral. Set a
+        * timeout in case something goes wrong.
+        */
+       if (*sent) {
+               struct hci_conn *conn;
+
+               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (conn)
+                       queue_delayed_work(hdev->workqueue,
+                                          &conn->le_conn_timeout,
+                                          HCI_LE_CONN_TIMEOUT);
+       }
+
+       mgmt_advertising(hdev, *sent);
 
        hci_dev_unlock(hdev);
 }
@@ -1018,6 +1033,33 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
+static bool has_pending_adv_report(struct hci_dev *hdev)
+{
+       struct discovery_state *d = &hdev->discovery;
+
+       return bacmp(&d->last_adv_addr, BDADDR_ANY);
+}
+
+static void clear_pending_adv_report(struct hci_dev *hdev)
+{
+       struct discovery_state *d = &hdev->discovery;
+
+       bacpy(&d->last_adv_addr, BDADDR_ANY);
+       d->last_adv_data_len = 0;
+}
+
+static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                    u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
+{
+       struct discovery_state *d = &hdev->discovery;
+
+       bacpy(&d->last_adv_addr, bdaddr);
+       d->last_adv_addr_type = bdaddr_type;
+       d->last_adv_rssi = rssi;
+       memcpy(d->last_adv_data, data, len);
+       d->last_adv_data_len = len;
+}
+
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
                                      struct sk_buff *skb)
 {
@@ -1036,9 +1078,25 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        switch (cp->enable) {
        case LE_SCAN_ENABLE:
                set_bit(HCI_LE_SCAN, &hdev->dev_flags);
+               if (hdev->le_scan_type == LE_SCAN_ACTIVE)
+                       clear_pending_adv_report(hdev);
                break;
 
        case LE_SCAN_DISABLE:
+               /* We do this here instead of when setting DISCOVERY_STOPPED
+                * since the latter would potentially require waiting for
+                * inquiry to stop too.
+                */
+               if (has_pending_adv_report(hdev)) {
+                       struct discovery_state *d = &hdev->discovery;
+
+                       mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
+                                         d->last_adv_addr_type, NULL,
+                                         d->last_adv_rssi, 0, 1,
+                                         d->last_adv_data,
+                                         d->last_adv_data_len, NULL, 0);
+               }
+
                /* Cancel this timer so that we don't try to disable scanning
                 * when it's already disabled.
                 */
@@ -1827,7 +1885,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
                name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                  info->dev_class, 0, !name_known, ssp, NULL,
-                                 0);
+                                 0, NULL, 0);
        }
 
        hci_dev_unlock(hdev);
@@ -3102,7 +3160,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
                                                              false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                          info->dev_class, info->rssi,
-                                         !name_known, ssp, NULL, 0);
+                                         !name_known, ssp, NULL, 0, NULL, 0);
                }
        } else {
                struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -3120,7 +3178,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
                                                              false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                          info->dev_class, info->rssi,
-                                         !name_known, ssp, NULL, 0);
+                                         !name_known, ssp, NULL, 0, NULL, 0);
                }
        }
 
@@ -3309,7 +3367,7 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
                eir_len = eir_get_length(info->data, sizeof(info->data));
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                  info->dev_class, info->rssi, !name_known,
-                                 ssp, info->data, eir_len);
+                                 ssp, info->data, eir_len, NULL, 0);
        }
 
        hci_dev_unlock(hdev);
@@ -3330,6 +3388,12 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
        if (!conn)
                goto unlock;
 
+       /* For BR/EDR the necessary steps are taken through the
+        * auth_complete event.
+        */
+       if (conn->type != LE_LINK)
+               goto unlock;
+
        if (!ev->status)
                conn->sec_level = conn->pending_sec_level;
 
@@ -3361,24 +3425,20 @@ unlock:
 
 static u8 hci_get_auth_req(struct hci_conn *conn)
 {
-       /* If remote requests dedicated bonding follow that lead */
-       if (conn->remote_auth == HCI_AT_DEDICATED_BONDING ||
-           conn->remote_auth == HCI_AT_DEDICATED_BONDING_MITM) {
-               /* If both remote and local IO capabilities allow MITM
-                * protection then require it, otherwise don't */
-               if (conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT ||
-                   conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)
-                       return HCI_AT_DEDICATED_BONDING;
-               else
-                       return HCI_AT_DEDICATED_BONDING_MITM;
-       }
-
        /* If remote requests no-bonding follow that lead */
        if (conn->remote_auth == HCI_AT_NO_BONDING ||
            conn->remote_auth == HCI_AT_NO_BONDING_MITM)
                return conn->remote_auth | (conn->auth_type & 0x01);
 
-       return conn->auth_type;
+       /* If both remote and local have enough IO capabilities, require
+        * MITM protection
+        */
+       if (conn->remote_cap != HCI_IO_NO_INPUT_OUTPUT &&
+           conn->io_capability != HCI_IO_NO_INPUT_OUTPUT)
+               return conn->remote_auth | 0x01;
+
+       /* No MITM protection possible so ignore remote requirement */
+       return (conn->remote_auth & ~0x01) | (conn->auth_type & 0x01);
 }
 
 static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3408,8 +3468,21 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
                 * to DisplayYesNo as it is not supported by BT spec. */
                cp.capability = (conn->io_capability == 0x04) ?
                                HCI_IO_DISPLAY_YESNO : conn->io_capability;
-               conn->auth_type = hci_get_auth_req(conn);
-               cp.authentication = conn->auth_type;
+
+               /* If we are initiators, there is no remote information yet */
+               if (conn->remote_auth == 0xff) {
+                       cp.authentication = conn->auth_type;
+
+                       /* Request MITM protection if our IO caps allow it
+                        * except for the no-bonding case
+                        */
+                       if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT &&
+                           cp.authentication != HCI_AT_NO_BONDING)
+                               cp.authentication |= 0x01;
+               } else {
+                       conn->auth_type = hci_get_auth_req(conn);
+                       cp.authentication = conn->auth_type;
+               }
 
                if (hci_find_remote_oob_data(hdev, &conn->dst) &&
                    (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
@@ -3477,12 +3550,9 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
        rem_mitm = (conn->remote_auth & 0x01);
 
        /* If we require MITM but the remote device can't provide that
-        * (it has NoInputNoOutput) then reject the confirmation
-        * request. The only exception is when we're dedicated bonding
-        * initiators (connect_cfm_cb set) since then we always have the MITM
-        * bit set. */
-       if (!conn->connect_cfm_cb && loc_mitm &&
-           conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
+        * (it has NoInputNoOutput) then reject the confirmation request
+        */
+       if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
                BT_DBG("Rejecting request: remote device can't provide MITM");
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
                             sizeof(ev->bdaddr), &ev->bdaddr);
@@ -3840,17 +3910,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
                conn->dst_type = ev->bdaddr_type;
 
-               /* The advertising parameters for own address type
-                * define which source address and source address
-                * type this connections has.
-                */
-               if (bacmp(&conn->src, BDADDR_ANY)) {
-                       conn->src_type = ADDR_LE_DEV_PUBLIC;
-               } else {
-                       bacpy(&conn->src, &hdev->static_addr);
-                       conn->src_type = ADDR_LE_DEV_RANDOM;
-               }
-
                if (ev->role == LE_CONN_ROLE_MASTER) {
                        conn->out = true;
                        conn->link_mode |= HCI_LM_MASTER;
@@ -3875,27 +3934,24 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                                                          &conn->init_addr,
                                                          &conn->init_addr_type);
                        }
-               } else {
-                       /* Set the responder (our side) address type based on
-                        * the advertising address type.
-                        */
-                       conn->resp_addr_type = hdev->adv_addr_type;
-                       if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
-                               bacpy(&conn->resp_addr, &hdev->random_addr);
-                       else
-                               bacpy(&conn->resp_addr, &hdev->bdaddr);
-
-                       conn->init_addr_type = ev->bdaddr_type;
-                       bacpy(&conn->init_addr, &ev->bdaddr);
                }
        } else {
                cancel_delayed_work(&conn->le_conn_timeout);
        }
 
-       /* Ensure that the hci_conn contains the identity address type
-        * regardless of which address the connection was made with.
-        */
-       hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
+       if (!conn->out) {
+               /* Set the responder (our side) address type based on
+                * the advertising address type.
+                */
+               conn->resp_addr_type = hdev->adv_addr_type;
+               if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
+                       bacpy(&conn->resp_addr, &hdev->random_addr);
+               else
+                       bacpy(&conn->resp_addr, &hdev->bdaddr);
+
+               conn->init_addr_type = ev->bdaddr_type;
+               bacpy(&conn->init_addr, &ev->bdaddr);
+       }
 
        /* Lookup the identity address from the stored connection
         * address and address type.
@@ -3975,25 +4031,97 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
        }
 }
 
+static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
+                              u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
+{
+       struct discovery_state *d = &hdev->discovery;
+       bool match;
+
+       /* Passive scanning shouldn't trigger any device found events */
+       if (hdev->le_scan_type == LE_SCAN_PASSIVE) {
+               if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND)
+                       check_pending_le_conn(hdev, bdaddr, bdaddr_type);
+               return;
+       }
+
+       /* If there's nothing pending either store the data from this
+        * event or send an immediate device found event if the data
+        * should not be stored for later.
+        */
+       if (!has_pending_adv_report(hdev)) {
+               /* If the report will trigger a SCAN_REQ store it for
+                * later merging.
+                */
+               if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
+                       store_pending_adv_report(hdev, bdaddr, bdaddr_type,
+                                                rssi, data, len);
+                       return;
+               }
+
+               mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
+                                 rssi, 0, 1, data, len, NULL, 0);
+               return;
+       }
+
+       /* Check if the pending report is for the same device as the new one */
+       match = (!bacmp(bdaddr, &d->last_adv_addr) &&
+                bdaddr_type == d->last_adv_addr_type);
+
+       /* If the pending data doesn't match this report or this isn't a
+        * scan response (e.g. we got a duplicate ADV_IND) then force
+        * sending of the pending data.
+        */
+       if (type != LE_ADV_SCAN_RSP || !match) {
+               /* Send out whatever is in the cache, but skip duplicates */
+               if (!match)
+                       mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
+                                         d->last_adv_addr_type, NULL,
+                                         d->last_adv_rssi, 0, 1,
+                                         d->last_adv_data,
+                                         d->last_adv_data_len, NULL, 0);
+
+               /* If the new report will trigger a SCAN_REQ store it for
+                * later merging.
+                */
+               if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
+                       store_pending_adv_report(hdev, bdaddr, bdaddr_type,
+                                                rssi, data, len);
+                       return;
+               }
+
+               /* The advertising reports cannot be merged, so clear
+                * the pending report and send out a device found event.
+                */
+               clear_pending_adv_report(hdev);
+               mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
+                                 rssi, 0, 1, data, len, NULL, 0);
+               return;
+       }
+
+       /* If we get here we've got a pending ADV_IND or ADV_SCAN_IND and
+        * the new event is a SCAN_RSP. We can therefore proceed with
+        * sending a merged device found event.
+        */
+       mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
+                         d->last_adv_addr_type, NULL, rssi, 0, 1, data, len,
+                         d->last_adv_data, d->last_adv_data_len);
+       clear_pending_adv_report(hdev);
+}
+
 static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        u8 num_reports = skb->data[0];
        void *ptr = &skb->data[1];
-       s8 rssi;
 
        hci_dev_lock(hdev);
 
        while (num_reports--) {
                struct hci_ev_le_advertising_info *ev = ptr;
-
-               if (ev->evt_type == LE_ADV_IND ||
-                   ev->evt_type == LE_ADV_DIRECT_IND)
-                       check_pending_le_conn(hdev, &ev->bdaddr,
-                                             ev->bdaddr_type);
+               s8 rssi;
 
                rssi = ev->data[ev->length];
-               mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
-                                 NULL, rssi, 0, 1, ev->data, ev->length);
+               process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
+                                  ev->bdaddr_type, rssi, ev->data, ev->length);
 
                ptr += sizeof(*ev) + ev->length + 1;
        }
index b9a418e578e0000ec4ad68734b3e34575cd759b5..f608bffdb8b940915ed160b18603c0733aee63a0 100644 (file)
@@ -524,16 +524,7 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
        case HCISETRAW:
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
-
-               if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
-                       return -EPERM;
-
-               if (arg)
-                       set_bit(HCI_RAW, &hdev->flags);
-               else
-                       clear_bit(HCI_RAW, &hdev->flags);
-
-               return 0;
+               return -EOPNOTSUPP;
 
        case HCIGETCONNINFO:
                return hci_get_conn_info(hdev, (void __user *) arg);
index b3fbc73516c415ee1654eb6f2aa38d5e390fb00b..941ad7530eda48f21dcf7faef9167cbce6574a8e 100644 (file)
@@ -58,6 +58,7 @@ int bt_to_errno(__u16 code)
                return EIO;
 
        case 0x04:
+       case 0x3c:
                return EHOSTDOWN;
 
        case 0x05:
index d2d4e0d5aed017366668bf263538baf332255d20..54abbce3a39e8bc0cdbd9018ca8e616e5c864546 100644 (file)
@@ -2850,10 +2850,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        sec_level = BT_SECURITY_MEDIUM;
-       if (cp->io_cap == 0x03)
-               auth_type = HCI_AT_DEDICATED_BONDING;
-       else
-               auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+       auth_type = HCI_AT_DEDICATED_BONDING;
 
        if (cp->addr.type == BDADDR_BREDR) {
                conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
@@ -3351,6 +3348,8 @@ static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
 
 static void start_discovery_complete(struct hci_dev *hdev, u8 status)
 {
+       unsigned long timeout = 0;
+
        BT_DBG("status %d", status);
 
        if (status) {
@@ -3366,13 +3365,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status)
 
        switch (hdev->discovery.type) {
        case DISCOV_TYPE_LE:
-               queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
-                                  DISCOV_LE_TIMEOUT);
+               timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
                break;
 
        case DISCOV_TYPE_INTERLEAVED:
-               queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
-                                  DISCOV_INTERLEAVED_TIMEOUT);
+               timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
                break;
 
        case DISCOV_TYPE_BREDR:
@@ -3381,6 +3378,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status)
        default:
                BT_ERR("Invalid discovery type %d", hdev->discovery.type);
        }
+
+       if (!timeout)
+               return;
+
+       queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout);
 }
 
 static int start_discovery(struct sock *sk, struct hci_dev *hdev,
@@ -5668,8 +5670,9 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
 }
 
 void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                      u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
-                      ssp, u8 *eir, u16 eir_len)
+                      u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
+                      u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
+                      u8 scan_rsp_len)
 {
        char buf[512];
        struct mgmt_ev_device_found *ev = (void *) buf;
@@ -5679,8 +5682,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
        if (!hci_discovery_active(hdev))
                return;
 
-       /* Leave 5 bytes for a potential CoD field */
-       if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
+       /* Make sure that the buffer is big enough. The 5 extra bytes
+        * are for the potential CoD field.
+        */
+       if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
                return;
 
        memset(buf, 0, sizeof(buf));
@@ -5707,8 +5712,11 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
                                          dev_class, 3);
 
-       ev->eir_len = cpu_to_le16(eir_len);
-       ev_size = sizeof(*ev) + eir_len;
+       if (scan_rsp_len > 0)
+               memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
+
+       ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
+       ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
 
        mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
 }
index e74b6d530cb6a3ab3dc650ee1900df06d3b3441a..e8844d975b321ac4e3f6a0cca76035918ec93a1b 100644 (file)
@@ -445,6 +445,20 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
        return 0;
 }
 
+static int br_dev_newlink(struct net *src_net, struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[])
+{
+       struct net_bridge *br = netdev_priv(dev);
+
+       if (tb[IFLA_ADDRESS]) {
+               spin_lock_bh(&br->lock);
+               br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS]));
+               spin_unlock_bh(&br->lock);
+       }
+
+       return register_netdevice(dev);
+}
+
 static size_t br_get_link_af_size(const struct net_device *dev)
 {
        struct net_port_vlans *pv;
@@ -473,6 +487,7 @@ struct rtnl_link_ops br_link_ops __read_mostly = {
        .priv_size      = sizeof(struct net_bridge),
        .setup          = br_dev_setup,
        .validate       = br_validate,
+       .newlink        = br_dev_newlink,
        .dellink        = br_dev_delete,
 };
 
index ac31891967da1ed811247d131dffbabfd7d28d11..050a2110d43f6b78f331b599569eaaf2d8803c24 100644 (file)
@@ -804,7 +804,7 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
        u8 limhops = 0;
        int err = 0;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (nlmsg_len(nlh) < sizeof(*r))
@@ -893,7 +893,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
        u8 limhops = 0;
        int err = 0;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (nlmsg_len(nlh) < sizeof(*r))
index e632b5a52f5b89cb2e275b64494905cc7ebfc8e7..8b8a5a24b223ef268c28cf5e5ac5379314bba237 100644 (file)
@@ -1548,8 +1548,10 @@ static void apply_primary_affinity(struct ceph_osdmap *osdmap, u32 pps,
                return;
 
        for (i = 0; i < len; i++) {
-               if (osds[i] != CRUSH_ITEM_NONE &&
-                   osdmap->osd_primary_affinity[i] !=
+               int osd = osds[i];
+
+               if (osd != CRUSH_ITEM_NONE &&
+                   osdmap->osd_primary_affinity[osd] !=
                                        CEPH_OSD_DEFAULT_PRIMARY_AFFINITY) {
                        break;
                }
@@ -1563,10 +1565,9 @@ static void apply_primary_affinity(struct ceph_osdmap *osdmap, u32 pps,
         * osd's pgs get rejected as primary.
         */
        for (i = 0; i < len; i++) {
-               int osd;
+               int osd = osds[i];
                u32 aff;
 
-               osd = osds[i];
                if (osd == CRUSH_ITEM_NONE)
                        continue;
 
index 815a2249cfa9371f1f9505c7016b509b83d50100..555013034f7a899e2d03268a6571e01d096e8cee 100644 (file)
@@ -53,7 +53,10 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
                        set_page_dirty_lock(pages[i]);
                put_page(pages[i]);
        }
-       kfree(pages);
+       if (is_vmalloc_addr(pages))
+               vfree(pages);
+       else
+               kfree(pages);
 }
 EXPORT_SYMBOL(ceph_put_page_vector);
 
@@ -164,36 +167,6 @@ void ceph_copy_from_page_vector(struct page **pages,
 }
 EXPORT_SYMBOL(ceph_copy_from_page_vector);
 
-/*
- * copy user data from a page vector into a user pointer
- */
-int ceph_copy_page_vector_to_user(struct page **pages,
-                                        void __user *data,
-                                        loff_t off, size_t len)
-{
-       int i = 0;
-       int po = off & ~PAGE_CACHE_MASK;
-       int left = len;
-       int l, bad;
-
-       while (left > 0) {
-               l = min_t(int, left, PAGE_CACHE_SIZE-po);
-               bad = copy_to_user(data, page_address(pages[i]) + po, l);
-               if (bad == l)
-                       return -EFAULT;
-               data += l - bad;
-               left -= l - bad;
-               if (po) {
-                       po += l - bad;
-                       if (po == PAGE_CACHE_SIZE)
-                               po = 0;
-               }
-               i++;
-       }
-       return len;
-}
-EXPORT_SYMBOL(ceph_copy_page_vector_to_user);
-
 /*
  * Zero an extent within a page vector.  Offset is relative to the
  * start of the first page.
index d2c8a06b3a9883b618c55a8cddf0929a4bcd049f..fe0b9cd69cb6e3ccf75d665d4981510b6d08041c 100644 (file)
@@ -1661,6 +1661,29 @@ bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(is_skb_forwardable);
 
+int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
+{
+       if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
+               if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
+                       atomic_long_inc(&dev->rx_dropped);
+                       kfree_skb(skb);
+                       return NET_RX_DROP;
+               }
+       }
+
+       if (unlikely(!is_skb_forwardable(dev, skb))) {
+               atomic_long_inc(&dev->rx_dropped);
+               kfree_skb(skb);
+               return NET_RX_DROP;
+       }
+
+       skb_scrub_packet(skb, true);
+       skb->protocol = eth_type_trans(skb, dev);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__dev_forward_skb);
+
 /**
  * dev_forward_skb - loopback an skb to another netif
  *
@@ -1681,24 +1704,7 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable);
  */
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
 {
-       if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-               if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
-                       atomic_long_inc(&dev->rx_dropped);
-                       kfree_skb(skb);
-                       return NET_RX_DROP;
-               }
-       }
-
-       if (unlikely(!is_skb_forwardable(dev, skb))) {
-               atomic_long_inc(&dev->rx_dropped);
-               kfree_skb(skb);
-               return NET_RX_DROP;
-       }
-
-       skb_scrub_packet(skb, true);
-       skb->protocol = eth_type_trans(skb, dev);
-
-       return netif_rx_internal(skb);
+       return __dev_forward_skb(dev, skb) ?: netif_rx_internal(skb);
 }
 EXPORT_SYMBOL_GPL(dev_forward_skb);
 
@@ -5600,10 +5606,6 @@ static void rollback_registered_many(struct list_head *head)
                */
                call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
 
-               if (!dev->rtnl_link_ops ||
-                   dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
-                       rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL);
-
                /*
                 *      Flush the unicast and multicast chains
                 */
@@ -5613,6 +5615,10 @@ static void rollback_registered_many(struct list_head *head)
                if (dev->netdev_ops->ndo_uninit)
                        dev->netdev_ops->ndo_uninit(dev);
 
+               if (!dev->rtnl_link_ops ||
+                   dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
+                       rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL);
+
                /* Notifier chain MUST detach us all upper devices. */
                WARN_ON(netdev_has_any_upper_dev(dev));
 
index 640ba0e5831ce0334a9cbf03983c16a022e85065..aa8978ac47d28b8588ff78e02e9607b1d616d6d1 100644 (file)
@@ -557,6 +557,25 @@ err_out:
        return ret;
 }
 
+static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
+                                       struct ethtool_rxnfc *rx_rings,
+                                       u32 size)
+{
+       int ret = 0, i;
+
+       if (copy_from_user(indir, useraddr, size * sizeof(indir[0])))
+               ret = -EFAULT;
+
+       /* Validate ring indices */
+       for (i = 0; i < size; i++) {
+               if (indir[i] >= rx_rings->data) {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+       return ret;
+}
+
 static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
                                                     void __user *useraddr)
 {
@@ -613,6 +632,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
        u32 *indir;
        const struct ethtool_ops *ops = dev->ethtool_ops;
        int ret;
+       u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
 
        if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir ||
            !ops->get_rxnfc)
@@ -643,28 +663,196 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
                for (i = 0; i < dev_size; i++)
                        indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
        } else {
-               if (copy_from_user(indir,
-                                 useraddr +
-                                 offsetof(struct ethtool_rxfh_indir,
-                                          ring_index[0]),
-                                 dev_size * sizeof(indir[0]))) {
+               ret = ethtool_copy_validate_indir(indir,
+                                                 useraddr + ringidx_offset,
+                                                 &rx_rings,
+                                                 dev_size);
+               if (ret)
+                       goto out;
+       }
+
+       ret = ops->set_rxfh_indir(dev, indir);
+
+out:
+       kfree(indir);
+       return ret;
+}
+
+static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
+                                              void __user *useraddr)
+{
+       int ret;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       u32 user_indir_size = 0, user_key_size = 0;
+       u32 dev_indir_size = 0, dev_key_size = 0;
+       u32 total_size;
+       u32 indir_offset, indir_bytes;
+       u32 key_offset;
+       u32 *indir = NULL;
+       u8 *hkey = NULL;
+       u8 *rss_config;
+
+       if (!(dev->ethtool_ops->get_rxfh_indir_size ||
+             dev->ethtool_ops->get_rxfh_key_size) ||
+             !dev->ethtool_ops->get_rxfh)
+               return -EOPNOTSUPP;
+
+       if (ops->get_rxfh_indir_size)
+               dev_indir_size = ops->get_rxfh_indir_size(dev);
+
+       indir_offset = offsetof(struct ethtool_rxfh, indir_size);
+
+       if (copy_from_user(&user_indir_size,
+                          useraddr + indir_offset,
+                          sizeof(user_indir_size)))
+               return -EFAULT;
+
+       if (copy_to_user(useraddr + indir_offset,
+                        &dev_indir_size, sizeof(dev_indir_size)))
+               return -EFAULT;
+
+       if (ops->get_rxfh_key_size)
+               dev_key_size = ops->get_rxfh_key_size(dev);
+
+       if ((dev_key_size + dev_indir_size) == 0)
+               return -EOPNOTSUPP;
+
+       key_offset = offsetof(struct ethtool_rxfh, key_size);
+
+       if (copy_from_user(&user_key_size,
+                          useraddr + key_offset,
+                          sizeof(user_key_size)))
+               return -EFAULT;
+
+       if (copy_to_user(useraddr + key_offset,
+                        &dev_key_size, sizeof(dev_key_size)))
+               return -EFAULT;
+
+       /* If the user buffer size is 0, this is just a query for the
+        * device table size and key size.  Otherwise, if the User size is
+        * not equal to device table size or key size it's an error.
+        */
+       if (!user_indir_size && !user_key_size)
+               return 0;
+
+       if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
+           (user_key_size && (user_key_size != dev_key_size)))
+               return -EINVAL;
+
+       indir_bytes = user_indir_size * sizeof(indir[0]);
+       total_size = indir_bytes + user_key_size;
+       rss_config = kzalloc(total_size, GFP_USER);
+       if (!rss_config)
+               return -ENOMEM;
+
+       if (user_indir_size)
+               indir = (u32 *)rss_config;
+
+       if (user_key_size)
+               hkey = rss_config + indir_bytes;
+
+       ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey);
+       if (!ret) {
+               if (copy_to_user(useraddr +
+                                offsetof(struct ethtool_rxfh, rss_config[0]),
+                                rss_config, total_size))
                        ret = -EFAULT;
+       }
+
+       kfree(rss_config);
+
+       return ret;
+}
+
+static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
+                                              void __user *useraddr)
+{
+       int ret;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       struct ethtool_rxnfc rx_rings;
+       u32 user_indir_size = 0, dev_indir_size = 0, i;
+       u32 user_key_size = 0, dev_key_size = 0;
+       u32 *indir = NULL, indir_bytes = 0;
+       u8 *hkey = NULL;
+       u8 *rss_config;
+       u32 indir_offset, key_offset;
+       u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
+
+       if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) ||
+           !ops->get_rxnfc || !ops->set_rxfh)
+               return -EOPNOTSUPP;
+
+       if (ops->get_rxfh_indir_size)
+               dev_indir_size = ops->get_rxfh_indir_size(dev);
+
+       indir_offset = offsetof(struct ethtool_rxfh, indir_size);
+       if (copy_from_user(&user_indir_size,
+                          useraddr + indir_offset,
+                          sizeof(user_indir_size)))
+               return -EFAULT;
+
+       if (ops->get_rxfh_key_size)
+               dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
+
+       if ((dev_key_size + dev_indir_size) == 0)
+               return -EOPNOTSUPP;
+
+       key_offset = offsetof(struct ethtool_rxfh, key_size);
+       if (copy_from_user(&user_key_size,
+                          useraddr + key_offset,
+                          sizeof(user_key_size)))
+               return -EFAULT;
+
+       /* If either indir or hash key is valid, proceed further.
+        */
+       if ((user_indir_size && ((user_indir_size != 0xDEADBEEF) &&
+                                user_indir_size != dev_indir_size)) ||
+           (user_key_size && (user_key_size != dev_key_size)))
+               return -EINVAL;
+
+       if (user_indir_size != 0xDEADBEEF)
+               indir_bytes = dev_indir_size * sizeof(indir[0]);
+
+       rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER);
+       if (!rss_config)
+               return -ENOMEM;
+
+       rx_rings.cmd = ETHTOOL_GRXRINGS;
+       ret = ops->get_rxnfc(dev, &rx_rings, NULL);
+       if (ret)
+               goto out;
+
+       /* user_indir_size == 0 means reset the indir table to default.
+        * user_indir_size == 0xDEADBEEF means indir setting is not requested.
+        */
+       if (user_indir_size && user_indir_size != 0xDEADBEEF) {
+               indir = (u32 *)rss_config;
+               ret = ethtool_copy_validate_indir(indir,
+                                                 useraddr + rss_cfg_offset,
+                                                 &rx_rings,
+                                                 user_indir_size);
+               if (ret)
                        goto out;
-               }
+       } else if (user_indir_size == 0) {
+               indir = (u32 *)rss_config;
+               for (i = 0; i < dev_indir_size; i++)
+                       indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
+       }
 
-               /* Validate ring indices */
-               for (i = 0; i < dev_size; i++) {
-                       if (indir[i] >= rx_rings.data) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
+       if (user_key_size) {
+               hkey = rss_config + indir_bytes;
+               if (copy_from_user(hkey,
+                                  useraddr + rss_cfg_offset + indir_bytes,
+                                  user_key_size)) {
+                       ret = -EFAULT;
+                       goto out;
                }
        }
 
-       ret = ops->set_rxfh_indir(dev, indir);
+       ret = ops->set_rxfh(dev, indir, hkey);
 
 out:
-       kfree(indir);
+       kfree(rss_config);
        return ret;
 }
 
@@ -1491,6 +1679,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GRXCLSRULE:
        case ETHTOOL_GRXCLSRLALL:
        case ETHTOOL_GRXFHINDIR:
+       case ETHTOOL_GRSSH:
        case ETHTOOL_GFEATURES:
        case ETHTOOL_GCHANNELS:
        case ETHTOOL_GET_TS_INFO:
@@ -1628,6 +1817,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_SRXFHINDIR:
                rc = ethtool_set_rxfh_indir(dev, useraddr);
                break;
+       case ETHTOOL_GRSSH:
+               rc = ethtool_get_rxfh(dev, useraddr);
+               break;
+       case ETHTOOL_SRSSH:
+               rc = ethtool_set_rxfh(dev, useraddr);
+               break;
        case ETHTOOL_GFEATURES:
                rc = ethtool_get_features(dev, useraddr);
                break;
index cd58614660cf54e1431392c5045bbdc9478336e6..eb020a7d6f55f9cf92b4ec96b5d2da16d24ec2c8 100644 (file)
 #include <linux/seccomp.h>
 #include <linux/if_vlan.h>
 
+/* Registers */
+#define R0     regs[BPF_REG_0]
+#define R1     regs[BPF_REG_1]
+#define R2     regs[BPF_REG_2]
+#define R3     regs[BPF_REG_3]
+#define R4     regs[BPF_REG_4]
+#define R5     regs[BPF_REG_5]
+#define R6     regs[BPF_REG_6]
+#define R7     regs[BPF_REG_7]
+#define R8     regs[BPF_REG_8]
+#define R9     regs[BPF_REG_9]
+#define R10    regs[BPF_REG_10]
+
+/* Named registers */
+#define A      regs[insn->a_reg]
+#define X      regs[insn->x_reg]
+#define FP     regs[BPF_REG_FP]
+#define ARG1   regs[BPF_REG_ARG1]
+#define CTX    regs[BPF_REG_CTX]
+#define K      insn->imm
+
 /* No hurry in this branch
  *
  * Exported for the bpf jit load helper.
@@ -57,9 +78,9 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
                ptr = skb_network_header(skb) + k - SKF_NET_OFF;
        else if (k >= SKF_LL_OFF)
                ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
-
        if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
                return ptr;
+
        return NULL;
 }
 
@@ -68,6 +89,7 @@ static inline void *load_pointer(const struct sk_buff *skb, int k,
 {
        if (k >= 0)
                return skb_header_pointer(skb, k, size, buffer);
+
        return bpf_internal_load_pointer_neg_helper(skb, k, size);
 }
 
@@ -135,206 +157,204 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn)
 {
        u64 stack[MAX_BPF_STACK / sizeof(u64)];
        u64 regs[MAX_BPF_REG], tmp;
-       void *ptr;
-       int off;
-
-#define K  insn->imm
-#define A  regs[insn->a_reg]
-#define X  regs[insn->x_reg]
-#define R0 regs[0]
-
-#define CONT    ({insn++; goto select_insn; })
-#define CONT_JMP ({insn++; goto select_insn; })
-
        static const void *jumptable[256] = {
                [0 ... 255] = &&default_label,
                /* Now overwrite non-defaults ... */
-#define DL(A, B, C)    [A|B|C] = &&A##_##B##_##C
-               DL(BPF_ALU, BPF_ADD, BPF_X),
-               DL(BPF_ALU, BPF_ADD, BPF_K),
-               DL(BPF_ALU, BPF_SUB, BPF_X),
-               DL(BPF_ALU, BPF_SUB, BPF_K),
-               DL(BPF_ALU, BPF_AND, BPF_X),
-               DL(BPF_ALU, BPF_AND, BPF_K),
-               DL(BPF_ALU, BPF_OR, BPF_X),
-               DL(BPF_ALU, BPF_OR, BPF_K),
-               DL(BPF_ALU, BPF_LSH, BPF_X),
-               DL(BPF_ALU, BPF_LSH, BPF_K),
-               DL(BPF_ALU, BPF_RSH, BPF_X),
-               DL(BPF_ALU, BPF_RSH, BPF_K),
-               DL(BPF_ALU, BPF_XOR, BPF_X),
-               DL(BPF_ALU, BPF_XOR, BPF_K),
-               DL(BPF_ALU, BPF_MUL, BPF_X),
-               DL(BPF_ALU, BPF_MUL, BPF_K),
-               DL(BPF_ALU, BPF_MOV, BPF_X),
-               DL(BPF_ALU, BPF_MOV, BPF_K),
-               DL(BPF_ALU, BPF_DIV, BPF_X),
-               DL(BPF_ALU, BPF_DIV, BPF_K),
-               DL(BPF_ALU, BPF_MOD, BPF_X),
-               DL(BPF_ALU, BPF_MOD, BPF_K),
-               DL(BPF_ALU, BPF_NEG, 0),
-               DL(BPF_ALU, BPF_END, BPF_TO_BE),
-               DL(BPF_ALU, BPF_END, BPF_TO_LE),
-               DL(BPF_ALU64, BPF_ADD, BPF_X),
-               DL(BPF_ALU64, BPF_ADD, BPF_K),
-               DL(BPF_ALU64, BPF_SUB, BPF_X),
-               DL(BPF_ALU64, BPF_SUB, BPF_K),
-               DL(BPF_ALU64, BPF_AND, BPF_X),
-               DL(BPF_ALU64, BPF_AND, BPF_K),
-               DL(BPF_ALU64, BPF_OR, BPF_X),
-               DL(BPF_ALU64, BPF_OR, BPF_K),
-               DL(BPF_ALU64, BPF_LSH, BPF_X),
-               DL(BPF_ALU64, BPF_LSH, BPF_K),
-               DL(BPF_ALU64, BPF_RSH, BPF_X),
-               DL(BPF_ALU64, BPF_RSH, BPF_K),
-               DL(BPF_ALU64, BPF_XOR, BPF_X),
-               DL(BPF_ALU64, BPF_XOR, BPF_K),
-               DL(BPF_ALU64, BPF_MUL, BPF_X),
-               DL(BPF_ALU64, BPF_MUL, BPF_K),
-               DL(BPF_ALU64, BPF_MOV, BPF_X),
-               DL(BPF_ALU64, BPF_MOV, BPF_K),
-               DL(BPF_ALU64, BPF_ARSH, BPF_X),
-               DL(BPF_ALU64, BPF_ARSH, BPF_K),
-               DL(BPF_ALU64, BPF_DIV, BPF_X),
-               DL(BPF_ALU64, BPF_DIV, BPF_K),
-               DL(BPF_ALU64, BPF_MOD, BPF_X),
-               DL(BPF_ALU64, BPF_MOD, BPF_K),
-               DL(BPF_ALU64, BPF_NEG, 0),
-               DL(BPF_JMP, BPF_CALL, 0),
-               DL(BPF_JMP, BPF_JA, 0),
-               DL(BPF_JMP, BPF_JEQ, BPF_X),
-               DL(BPF_JMP, BPF_JEQ, BPF_K),
-               DL(BPF_JMP, BPF_JNE, BPF_X),
-               DL(BPF_JMP, BPF_JNE, BPF_K),
-               DL(BPF_JMP, BPF_JGT, BPF_X),
-               DL(BPF_JMP, BPF_JGT, BPF_K),
-               DL(BPF_JMP, BPF_JGE, BPF_X),
-               DL(BPF_JMP, BPF_JGE, BPF_K),
-               DL(BPF_JMP, BPF_JSGT, BPF_X),
-               DL(BPF_JMP, BPF_JSGT, BPF_K),
-               DL(BPF_JMP, BPF_JSGE, BPF_X),
-               DL(BPF_JMP, BPF_JSGE, BPF_K),
-               DL(BPF_JMP, BPF_JSET, BPF_X),
-               DL(BPF_JMP, BPF_JSET, BPF_K),
-               DL(BPF_JMP, BPF_EXIT, 0),
-               DL(BPF_STX, BPF_MEM, BPF_B),
-               DL(BPF_STX, BPF_MEM, BPF_H),
-               DL(BPF_STX, BPF_MEM, BPF_W),
-               DL(BPF_STX, BPF_MEM, BPF_DW),
-               DL(BPF_STX, BPF_XADD, BPF_W),
-               DL(BPF_STX, BPF_XADD, BPF_DW),
-               DL(BPF_ST, BPF_MEM, BPF_B),
-               DL(BPF_ST, BPF_MEM, BPF_H),
-               DL(BPF_ST, BPF_MEM, BPF_W),
-               DL(BPF_ST, BPF_MEM, BPF_DW),
-               DL(BPF_LDX, BPF_MEM, BPF_B),
-               DL(BPF_LDX, BPF_MEM, BPF_H),
-               DL(BPF_LDX, BPF_MEM, BPF_W),
-               DL(BPF_LDX, BPF_MEM, BPF_DW),
-               DL(BPF_LD, BPF_ABS, BPF_W),
-               DL(BPF_LD, BPF_ABS, BPF_H),
-               DL(BPF_LD, BPF_ABS, BPF_B),
-               DL(BPF_LD, BPF_IND, BPF_W),
-               DL(BPF_LD, BPF_IND, BPF_H),
-               DL(BPF_LD, BPF_IND, BPF_B),
+#define DL(A, B, C)    [BPF_##A|BPF_##B|BPF_##C] = &&A##_##B##_##C
+               DL(ALU, ADD, X),
+               DL(ALU, ADD, K),
+               DL(ALU, SUB, X),
+               DL(ALU, SUB, K),
+               DL(ALU, AND, X),
+               DL(ALU, AND, K),
+               DL(ALU, OR, X),
+               DL(ALU, OR, K),
+               DL(ALU, LSH, X),
+               DL(ALU, LSH, K),
+               DL(ALU, RSH, X),
+               DL(ALU, RSH, K),
+               DL(ALU, XOR, X),
+               DL(ALU, XOR, K),
+               DL(ALU, MUL, X),
+               DL(ALU, MUL, K),
+               DL(ALU, MOV, X),
+               DL(ALU, MOV, K),
+               DL(ALU, DIV, X),
+               DL(ALU, DIV, K),
+               DL(ALU, MOD, X),
+               DL(ALU, MOD, K),
+               DL(ALU, NEG, 0),
+               DL(ALU, END, TO_BE),
+               DL(ALU, END, TO_LE),
+               DL(ALU64, ADD, X),
+               DL(ALU64, ADD, K),
+               DL(ALU64, SUB, X),
+               DL(ALU64, SUB, K),
+               DL(ALU64, AND, X),
+               DL(ALU64, AND, K),
+               DL(ALU64, OR, X),
+               DL(ALU64, OR, K),
+               DL(ALU64, LSH, X),
+               DL(ALU64, LSH, K),
+               DL(ALU64, RSH, X),
+               DL(ALU64, RSH, K),
+               DL(ALU64, XOR, X),
+               DL(ALU64, XOR, K),
+               DL(ALU64, MUL, X),
+               DL(ALU64, MUL, K),
+               DL(ALU64, MOV, X),
+               DL(ALU64, MOV, K),
+               DL(ALU64, ARSH, X),
+               DL(ALU64, ARSH, K),
+               DL(ALU64, DIV, X),
+               DL(ALU64, DIV, K),
+               DL(ALU64, MOD, X),
+               DL(ALU64, MOD, K),
+               DL(ALU64, NEG, 0),
+               DL(JMP, CALL, 0),
+               DL(JMP, JA, 0),
+               DL(JMP, JEQ, X),
+               DL(JMP, JEQ, K),
+               DL(JMP, JNE, X),
+               DL(JMP, JNE, K),
+               DL(JMP, JGT, X),
+               DL(JMP, JGT, K),
+               DL(JMP, JGE, X),
+               DL(JMP, JGE, K),
+               DL(JMP, JSGT, X),
+               DL(JMP, JSGT, K),
+               DL(JMP, JSGE, X),
+               DL(JMP, JSGE, K),
+               DL(JMP, JSET, X),
+               DL(JMP, JSET, K),
+               DL(JMP, EXIT, 0),
+               DL(STX, MEM, B),
+               DL(STX, MEM, H),
+               DL(STX, MEM, W),
+               DL(STX, MEM, DW),
+               DL(STX, XADD, W),
+               DL(STX, XADD, DW),
+               DL(ST, MEM, B),
+               DL(ST, MEM, H),
+               DL(ST, MEM, W),
+               DL(ST, MEM, DW),
+               DL(LDX, MEM, B),
+               DL(LDX, MEM, H),
+               DL(LDX, MEM, W),
+               DL(LDX, MEM, DW),
+               DL(LD, ABS, W),
+               DL(LD, ABS, H),
+               DL(LD, ABS, B),
+               DL(LD, IND, W),
+               DL(LD, IND, H),
+               DL(LD, IND, B),
 #undef DL
        };
+       void *ptr;
+       int off;
+
+#define CONT    ({ insn++; goto select_insn; })
+#define CONT_JMP ({ insn++; goto select_insn; })
 
-       regs[FP_REG]  = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)];
-       regs[ARG1_REG] = (u64) (unsigned long) ctx;
+       FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)];
+       ARG1 = (u64) (unsigned long) ctx;
+
+       /* Register for user BPF programs need to be reset first. */
+       regs[BPF_REG_A] = 0;
+       regs[BPF_REG_X] = 0;
 
 select_insn:
        goto *jumptable[insn->code];
 
        /* ALU */
 #define ALU(OPCODE, OP)                        \
-       BPF_ALU64_##OPCODE##_BPF_X:     \
+       ALU64_##OPCODE##_X:             \
                A = A OP X;             \
                CONT;                   \
-       BPF_ALU_##OPCODE##_BPF_X:       \
+       ALU_##OPCODE##_X:               \
                A = (u32) A OP (u32) X; \
                CONT;                   \
-       BPF_ALU64_##OPCODE##_BPF_K:     \
+       ALU64_##OPCODE##_K:             \
                A = A OP K;             \
                CONT;                   \
-       BPF_ALU_##OPCODE##_BPF_K:       \
+       ALU_##OPCODE##_K:               \
                A = (u32) A OP (u32) K; \
                CONT;
 
-       ALU(BPF_ADD,  +)
-       ALU(BPF_SUB,  -)
-       ALU(BPF_AND,  &)
-       ALU(BPF_OR,   |)
-       ALU(BPF_LSH, <<)
-       ALU(BPF_RSH, >>)
-       ALU(BPF_XOR,  ^)
-       ALU(BPF_MUL,  *)
+       ALU(ADD,  +)
+       ALU(SUB,  -)
+       ALU(AND,  &)
+       ALU(OR,   |)
+       ALU(LSH, <<)
+       ALU(RSH, >>)
+       ALU(XOR,  ^)
+       ALU(MUL,  *)
 #undef ALU
-       BPF_ALU_BPF_NEG_0:
+       ALU_NEG_0:
                A = (u32) -A;
                CONT;
-       BPF_ALU64_BPF_NEG_0:
+       ALU64_NEG_0:
                A = -A;
                CONT;
-       BPF_ALU_BPF_MOV_BPF_X:
+       ALU_MOV_X:
                A = (u32) X;
                CONT;
-       BPF_ALU_BPF_MOV_BPF_K:
+       ALU_MOV_K:
                A = (u32) K;
                CONT;
-       BPF_ALU64_BPF_MOV_BPF_X:
+       ALU64_MOV_X:
                A = X;
                CONT;
-       BPF_ALU64_BPF_MOV_BPF_K:
+       ALU64_MOV_K:
                A = K;
                CONT;
-       BPF_ALU64_BPF_ARSH_BPF_X:
+       ALU64_ARSH_X:
                (*(s64 *) &A) >>= X;
                CONT;
-       BPF_ALU64_BPF_ARSH_BPF_K:
+       ALU64_ARSH_K:
                (*(s64 *) &A) >>= K;
                CONT;
-       BPF_ALU64_BPF_MOD_BPF_X:
+       ALU64_MOD_X:
                if (unlikely(X == 0))
                        return 0;
                tmp = A;
                A = do_div(tmp, X);
                CONT;
-       BPF_ALU_BPF_MOD_BPF_X:
+       ALU_MOD_X:
                if (unlikely(X == 0))
                        return 0;
                tmp = (u32) A;
                A = do_div(tmp, (u32) X);
                CONT;
-       BPF_ALU64_BPF_MOD_BPF_K:
+       ALU64_MOD_K:
                tmp = A;
                A = do_div(tmp, K);
                CONT;
-       BPF_ALU_BPF_MOD_BPF_K:
+       ALU_MOD_K:
                tmp = (u32) A;
                A = do_div(tmp, (u32) K);
                CONT;
-       BPF_ALU64_BPF_DIV_BPF_X:
+       ALU64_DIV_X:
                if (unlikely(X == 0))
                        return 0;
                do_div(A, X);
                CONT;
-       BPF_ALU_BPF_DIV_BPF_X:
+       ALU_DIV_X:
                if (unlikely(X == 0))
                        return 0;
                tmp = (u32) A;
                do_div(tmp, (u32) X);
                A = (u32) tmp;
                CONT;
-       BPF_ALU64_BPF_DIV_BPF_K:
+       ALU64_DIV_K:
                do_div(A, K);
                CONT;
-       BPF_ALU_BPF_DIV_BPF_K:
+       ALU_DIV_K:
                tmp = (u32) A;
                do_div(tmp, (u32) K);
                A = (u32) tmp;
                CONT;
-       BPF_ALU_BPF_END_BPF_TO_BE:
+       ALU_END_TO_BE:
                switch (K) {
                case 16:
                        A = (__force u16) cpu_to_be16(A);
@@ -347,7 +367,7 @@ select_insn:
                        break;
                }
                CONT;
-       BPF_ALU_BPF_END_BPF_TO_LE:
+       ALU_END_TO_LE:
                switch (K) {
                case 16:
                        A = (__force u16) cpu_to_le16(A);
@@ -362,136 +382,135 @@ select_insn:
                CONT;
 
        /* CALL */
-       BPF_JMP_BPF_CALL_0:
+       JMP_CALL_0:
                /* Function call scratches R1-R5 registers, preserves R6-R9,
                 * and stores return value into R0.
                 */
-               R0 = (__bpf_call_base + insn->imm)(regs[1], regs[2], regs[3],
-                                                  regs[4], regs[5]);
+               R0 = (__bpf_call_base + insn->imm)(R1, R2, R3, R4, R5);
                CONT;
 
        /* JMP */
-       BPF_JMP_BPF_JA_0:
+       JMP_JA_0:
                insn += insn->off;
                CONT;
-       BPF_JMP_BPF_JEQ_BPF_X:
+       JMP_JEQ_X:
                if (A == X) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JEQ_BPF_K:
+       JMP_JEQ_K:
                if (A == K) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JNE_BPF_X:
+       JMP_JNE_X:
                if (A != X) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JNE_BPF_K:
+       JMP_JNE_K:
                if (A != K) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JGT_BPF_X:
+       JMP_JGT_X:
                if (A > X) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JGT_BPF_K:
+       JMP_JGT_K:
                if (A > K) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JGE_BPF_X:
+       JMP_JGE_X:
                if (A >= X) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JGE_BPF_K:
+       JMP_JGE_K:
                if (A >= K) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JSGT_BPF_X:
-               if (((s64)A) > ((s64)X)) {
+       JMP_JSGT_X:
+               if (((s64) A) > ((s64) X)) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JSGT_BPF_K:
-               if (((s64)A) > ((s64)K)) {
+       JMP_JSGT_K:
+               if (((s64) A) > ((s64) K)) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JSGE_BPF_X:
-               if (((s64)A) >= ((s64)X)) {
+       JMP_JSGE_X:
+               if (((s64) A) >= ((s64) X)) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JSGE_BPF_K:
-               if (((s64)A) >= ((s64)K)) {
+       JMP_JSGE_K:
+               if (((s64) A) >= ((s64) K)) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JSET_BPF_X:
+       JMP_JSET_X:
                if (A & X) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_JSET_BPF_K:
+       JMP_JSET_K:
                if (A & K) {
                        insn += insn->off;
                        CONT_JMP;
                }
                CONT;
-       BPF_JMP_BPF_EXIT_0:
+       JMP_EXIT_0:
                return R0;
 
        /* STX and ST and LDX*/
 #define LDST(SIZEOP, SIZE)                                     \
-       BPF_STX_BPF_MEM_##SIZEOP:                               \
+       STX_MEM_##SIZEOP:                                       \
                *(SIZE *)(unsigned long) (A + insn->off) = X;   \
                CONT;                                           \
-       BPF_ST_BPF_MEM_##SIZEOP:                                \
+       ST_MEM_##SIZEOP:                                        \
                *(SIZE *)(unsigned long) (A + insn->off) = K;   \
                CONT;                                           \
-       BPF_LDX_BPF_MEM_##SIZEOP:                               \
+       LDX_MEM_##SIZEOP:                                       \
                A = *(SIZE *)(unsigned long) (X + insn->off);   \
                CONT;
 
-       LDST(BPF_B,   u8)
-       LDST(BPF_H,  u16)
-       LDST(BPF_W,  u32)
-       LDST(BPF_DW, u64)
+       LDST(B,   u8)
+       LDST(H,  u16)
+       LDST(W,  u32)
+       LDST(DW, u64)
 #undef LDST
-       BPF_STX_BPF_XADD_BPF_W: /* lock xadd *(u32 *)(A + insn->off) += X */
+       STX_XADD_W: /* lock xadd *(u32 *)(A + insn->off) += X */
                atomic_add((u32) X, (atomic_t *)(unsigned long)
                           (A + insn->off));
                CONT;
-       BPF_STX_BPF_XADD_BPF_DW: /* lock xadd *(u64 *)(A + insn->off) += X */
+       STX_XADD_DW: /* lock xadd *(u64 *)(A + insn->off) += X */
                atomic64_add((u64) X, (atomic64_t *)(unsigned long)
                             (A + insn->off));
                CONT;
-       BPF_LD_BPF_ABS_BPF_W: /* R0 = ntohl(*(u32 *) (skb->data + K)) */
+       LD_ABS_W: /* R0 = ntohl(*(u32 *) (skb->data + K)) */
                off = K;
 load_word:
                /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are only
                 * appearing in the programs where ctx == skb. All programs
-                * keep 'ctx' in regs[CTX_REG] == R6, sk_convert_filter()
+                * keep 'ctx' in regs[BPF_REG_CTX] == R6, sk_convert_filter()
                 * saves it in R6, internal BPF verifier will check that
                 * R6 == ctx.
                 *
@@ -515,7 +534,7 @@ load_word:
                        CONT;
                }
                return 0;
-       BPF_LD_BPF_ABS_BPF_H: /* R0 = ntohs(*(u16 *) (skb->data + K)) */
+       LD_ABS_H: /* R0 = ntohs(*(u16 *) (skb->data + K)) */
                off = K;
 load_half:
                ptr = load_pointer((struct sk_buff *) ctx, off, 2, &tmp);
@@ -524,7 +543,7 @@ load_half:
                        CONT;
                }
                return 0;
-       BPF_LD_BPF_ABS_BPF_B: /* R0 = *(u8 *) (ctx + K) */
+       LD_ABS_B: /* R0 = *(u8 *) (ctx + K) */
                off = K;
 load_byte:
                ptr = load_pointer((struct sk_buff *) ctx, off, 1, &tmp);
@@ -533,13 +552,13 @@ load_byte:
                        CONT;
                }
                return 0;
-       BPF_LD_BPF_IND_BPF_W: /* R0 = ntohl(*(u32 *) (skb->data + X + K)) */
+       LD_IND_W: /* R0 = ntohl(*(u32 *) (skb->data + X + K)) */
                off = K + X;
                goto load_word;
-       BPF_LD_BPF_IND_BPF_H: /* R0 = ntohs(*(u16 *) (skb->data + X + K)) */
+       LD_IND_H: /* R0 = ntohs(*(u16 *) (skb->data + X + K)) */
                off = K + X;
                goto load_half;
-       BPF_LD_BPF_IND_BPF_B: /* R0 = *(u8 *) (skb->data + X + K) */
+       LD_IND_B: /* R0 = *(u8 *) (skb->data + X + K) */
                off = K + X;
                goto load_byte;
 
@@ -547,13 +566,6 @@ load_byte:
                /* If we ever reach this, we have a bug somewhere. */
                WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code);
                return 0;
-#undef CONT_JMP
-#undef CONT
-
-#undef R0
-#undef X
-#undef A
-#undef K
 }
 
 u32 sk_run_filter_int_seccomp(const struct seccomp_data *ctx,
@@ -585,16 +597,14 @@ static unsigned int pkt_type_offset(void)
        return -1;
 }
 
-static u64 __skb_get_pay_offset(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
 {
-       struct sk_buff *skb = (struct sk_buff *)(long) ctx;
-
-       return __skb_get_poff(skb);
+       return __skb_get_poff((struct sk_buff *)(unsigned long) ctx);
 }
 
-static u64 __skb_get_nlattr(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
 {
-       struct sk_buff *skb = (struct sk_buff *)(long) ctx;
+       struct sk_buff *skb = (struct sk_buff *)(unsigned long) ctx;
        struct nlattr *nla;
 
        if (skb_is_nonlinear(skb))
@@ -603,19 +613,19 @@ static u64 __skb_get_nlattr(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
        if (skb->len < sizeof(struct nlattr))
                return 0;
 
-       if (A > skb->len - sizeof(struct nlattr))
+       if (a > skb->len - sizeof(struct nlattr))
                return 0;
 
-       nla = nla_find((struct nlattr *) &skb->data[A], skb->len - A, X);
+       nla = nla_find((struct nlattr *) &skb->data[a], skb->len - a, x);
        if (nla)
                return (void *) nla - (void *) skb->data;
 
        return 0;
 }
 
-static u64 __skb_get_nlattr_nest(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+static u64 __skb_get_nlattr_nest(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
 {
-       struct sk_buff *skb = (struct sk_buff *)(long) ctx;
+       struct sk_buff *skb = (struct sk_buff *)(unsigned long) ctx;
        struct nlattr *nla;
 
        if (skb_is_nonlinear(skb))
@@ -624,31 +634,30 @@ static u64 __skb_get_nlattr_nest(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
        if (skb->len < sizeof(struct nlattr))
                return 0;
 
-       if (A > skb->len - sizeof(struct nlattr))
+       if (a > skb->len - sizeof(struct nlattr))
                return 0;
 
-       nla = (struct nlattr *) &skb->data[A];
-       if (nla->nla_len > skb->len - A)
+       nla = (struct nlattr *) &skb->data[a];
+       if (nla->nla_len > skb->len - a)
                return 0;
 
-       nla = nla_find_nested(nla, X);
+       nla = nla_find_nested(nla, x);
        if (nla)
                return (void *) nla - (void *) skb->data;
 
        return 0;
 }
 
-static u64 __get_raw_cpu_id(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+static u64 __get_raw_cpu_id(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
 {
        return raw_smp_processor_id();
 }
 
-/* Register mappings for user programs. */
-#define A_REG          0
-#define X_REG          7
-#define TMP_REG                8
-#define ARG2_REG       2
-#define ARG3_REG       3
+/* note that this only generates 32-bit random numbers */
+static u64 __get_random_u32(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
+{
+       return prandom_u32();
+}
 
 static bool convert_bpf_extensions(struct sock_filter *fp,
                                   struct sock_filter_int **insnp)
@@ -660,28 +669,28 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
 
                insn->code = BPF_LDX | BPF_MEM | BPF_H;
-               insn->a_reg = A_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = offsetof(struct sk_buff, protocol);
                insn++;
 
                /* A = ntohs(A) [emitting a nop or swap16] */
                insn->code = BPF_ALU | BPF_END | BPF_FROM_BE;
-               insn->a_reg = A_REG;
+               insn->a_reg = BPF_REG_A;
                insn->imm = 16;
                break;
 
        case SKF_AD_OFF + SKF_AD_PKTTYPE:
                insn->code = BPF_LDX | BPF_MEM | BPF_B;
-               insn->a_reg = A_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = pkt_type_offset();
                if (insn->off < 0)
                        return false;
                insn++;
 
                insn->code = BPF_ALU | BPF_AND | BPF_K;
-               insn->a_reg = A_REG;
+               insn->a_reg = BPF_REG_A;
                insn->imm = PKT_TYPE_MAX;
                break;
 
@@ -691,13 +700,13 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                        insn->code = BPF_LDX | BPF_MEM | BPF_DW;
                else
                        insn->code = BPF_LDX | BPF_MEM | BPF_W;
-               insn->a_reg = TMP_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_TMP;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = offsetof(struct sk_buff, dev);
                insn++;
 
                insn->code = BPF_JMP | BPF_JNE | BPF_K;
-               insn->a_reg = TMP_REG;
+               insn->a_reg = BPF_REG_TMP;
                insn->imm = 0;
                insn->off = 1;
                insn++;
@@ -708,8 +717,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
                BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
 
-               insn->a_reg = A_REG;
-               insn->x_reg = TMP_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_TMP;
 
                if (fp->k == SKF_AD_OFF + SKF_AD_IFINDEX) {
                        insn->code = BPF_LDX | BPF_MEM | BPF_W;
@@ -724,8 +733,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
 
                insn->code = BPF_LDX | BPF_MEM | BPF_W;
-               insn->a_reg = A_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = offsetof(struct sk_buff, mark);
                break;
 
@@ -733,8 +742,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
 
                insn->code = BPF_LDX | BPF_MEM | BPF_W;
-               insn->a_reg = A_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = offsetof(struct sk_buff, hash);
                break;
 
@@ -742,8 +751,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
 
                insn->code = BPF_LDX | BPF_MEM | BPF_H;
-               insn->a_reg = A_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = offsetof(struct sk_buff, queue_mapping);
                break;
 
@@ -752,8 +761,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
 
                insn->code = BPF_LDX | BPF_MEM | BPF_H;
-               insn->a_reg = A_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_CTX;
                insn->off = offsetof(struct sk_buff, vlan_tci);
                insn++;
 
@@ -761,16 +770,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
 
                if (fp->k == SKF_AD_OFF + SKF_AD_VLAN_TAG) {
                        insn->code = BPF_ALU | BPF_AND | BPF_K;
-                       insn->a_reg = A_REG;
+                       insn->a_reg = BPF_REG_A;
                        insn->imm = ~VLAN_TAG_PRESENT;
                } else {
                        insn->code = BPF_ALU | BPF_RSH | BPF_K;
-                       insn->a_reg = A_REG;
+                       insn->a_reg = BPF_REG_A;
                        insn->imm = 12;
                        insn++;
 
                        insn->code = BPF_ALU | BPF_AND | BPF_K;
-                       insn->a_reg = A_REG;
+                       insn->a_reg = BPF_REG_A;
                        insn->imm = 1;
                }
                break;
@@ -779,22 +788,23 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
        case SKF_AD_OFF + SKF_AD_NLATTR:
        case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
        case SKF_AD_OFF + SKF_AD_CPU:
+       case SKF_AD_OFF + SKF_AD_RANDOM:
                /* arg1 = ctx */
                insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-               insn->a_reg = ARG1_REG;
-               insn->x_reg = CTX_REG;
+               insn->a_reg = BPF_REG_ARG1;
+               insn->x_reg = BPF_REG_CTX;
                insn++;
 
                /* arg2 = A */
                insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-               insn->a_reg = ARG2_REG;
-               insn->x_reg = A_REG;
+               insn->a_reg = BPF_REG_ARG2;
+               insn->x_reg = BPF_REG_A;
                insn++;
 
                /* arg3 = X */
                insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-               insn->a_reg = ARG3_REG;
-               insn->x_reg = X_REG;
+               insn->a_reg = BPF_REG_ARG3;
+               insn->x_reg = BPF_REG_X;
                insn++;
 
                /* Emit call(ctx, arg2=A, arg3=X) */
@@ -812,13 +822,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                case SKF_AD_OFF + SKF_AD_CPU:
                        insn->imm = __get_raw_cpu_id - __bpf_call_base;
                        break;
+               case SKF_AD_OFF + SKF_AD_RANDOM:
+                       insn->imm = __get_random_u32 - __bpf_call_base;
+                       break;
                }
                break;
 
        case SKF_AD_OFF + SKF_AD_ALU_XOR_X:
                insn->code = BPF_ALU | BPF_XOR | BPF_X;
-               insn->a_reg = A_REG;
-               insn->x_reg = X_REG;
+               insn->a_reg = BPF_REG_A;
+               insn->x_reg = BPF_REG_X;
                break;
 
        default:
@@ -868,7 +881,7 @@ int sk_convert_filter(struct sock_filter *prog, int len,
        u8 bpf_src;
 
        BUILD_BUG_ON(BPF_MEMWORDS * sizeof(u32) > MAX_BPF_STACK);
-       BUILD_BUG_ON(FP_REG + 1 != MAX_BPF_REG);
+       BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG);
 
        if (len <= 0 || len >= BPF_MAXINSNS)
                return -EINVAL;
@@ -885,8 +898,8 @@ do_pass:
 
        if (new_insn) {
                new_insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-               new_insn->a_reg = CTX_REG;
-               new_insn->x_reg = ARG1_REG;
+               new_insn->a_reg = BPF_REG_CTX;
+               new_insn->x_reg = BPF_REG_ARG1;
        }
        new_insn++;
 
@@ -936,8 +949,8 @@ do_pass:
                                break;
 
                        insn->code = fp->code;
-                       insn->a_reg = A_REG;
-                       insn->x_reg = X_REG;
+                       insn->a_reg = BPF_REG_A;
+                       insn->x_reg = BPF_REG_X;
                        insn->imm = fp->k;
                        break;
 
@@ -971,16 +984,16 @@ do_pass:
                                 * in compare insn.
                                 */
                                insn->code = BPF_ALU | BPF_MOV | BPF_K;
-                               insn->a_reg = TMP_REG;
+                               insn->a_reg = BPF_REG_TMP;
                                insn->imm = fp->k;
                                insn++;
 
-                               insn->a_reg = A_REG;
-                               insn->x_reg = TMP_REG;
+                               insn->a_reg = BPF_REG_A;
+                               insn->x_reg = BPF_REG_TMP;
                                bpf_src = BPF_X;
                        } else {
-                               insn->a_reg = A_REG;
-                               insn->x_reg = X_REG;
+                               insn->a_reg = BPF_REG_A;
+                               insn->x_reg = BPF_REG_X;
                                insn->imm = fp->k;
                                bpf_src = BPF_SRC(fp->code);
                        }
@@ -1015,33 +1028,33 @@ do_pass:
                /* ldxb 4 * ([14] & 0xf) is remaped into 6 insns. */
                case BPF_LDX | BPF_MSH | BPF_B:
                        insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-                       insn->a_reg = TMP_REG;
-                       insn->x_reg = A_REG;
+                       insn->a_reg = BPF_REG_TMP;
+                       insn->x_reg = BPF_REG_A;
                        insn++;
 
                        insn->code = BPF_LD | BPF_ABS | BPF_B;
-                       insn->a_reg = A_REG;
+                       insn->a_reg = BPF_REG_A;
                        insn->imm = fp->k;
                        insn++;
 
                        insn->code = BPF_ALU | BPF_AND | BPF_K;
-                       insn->a_reg = A_REG;
+                       insn->a_reg = BPF_REG_A;
                        insn->imm = 0xf;
                        insn++;
 
                        insn->code = BPF_ALU | BPF_LSH | BPF_K;
-                       insn->a_reg = A_REG;
+                       insn->a_reg = BPF_REG_A;
                        insn->imm = 2;
                        insn++;
 
                        insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-                       insn->a_reg = X_REG;
-                       insn->x_reg = A_REG;
+                       insn->a_reg = BPF_REG_X;
+                       insn->x_reg = BPF_REG_A;
                        insn++;
 
                        insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-                       insn->a_reg = A_REG;
-                       insn->x_reg = TMP_REG;
+                       insn->a_reg = BPF_REG_A;
+                       insn->x_reg = BPF_REG_TMP;
                        break;
 
                /* RET_K, RET_A are remaped into 2 insns. */
@@ -1051,7 +1064,7 @@ do_pass:
                                     (BPF_RVAL(fp->code) == BPF_K ?
                                      BPF_K : BPF_X);
                        insn->a_reg = 0;
-                       insn->x_reg = A_REG;
+                       insn->x_reg = BPF_REG_A;
                        insn->imm = fp->k;
                        insn++;
 
@@ -1062,8 +1075,9 @@ do_pass:
                case BPF_ST:
                case BPF_STX:
                        insn->code = BPF_STX | BPF_MEM | BPF_W;
-                       insn->a_reg = FP_REG;
-                       insn->x_reg = fp->code == BPF_ST ? A_REG : X_REG;
+                       insn->a_reg = BPF_REG_FP;
+                       insn->x_reg = fp->code == BPF_ST ?
+                                     BPF_REG_A : BPF_REG_X;
                        insn->off = -(BPF_MEMWORDS - fp->k) * 4;
                        break;
 
@@ -1072,8 +1086,8 @@ do_pass:
                case BPF_LDX | BPF_MEM:
                        insn->code = BPF_LDX | BPF_MEM | BPF_W;
                        insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ?
-                                     A_REG : X_REG;
-                       insn->x_reg = FP_REG;
+                                     BPF_REG_A : BPF_REG_X;
+                       insn->x_reg = BPF_REG_FP;
                        insn->off = -(BPF_MEMWORDS - fp->k) * 4;
                        break;
 
@@ -1082,22 +1096,22 @@ do_pass:
                case BPF_LDX | BPF_IMM:
                        insn->code = BPF_ALU | BPF_MOV | BPF_K;
                        insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ?
-                                     A_REG : X_REG;
+                                     BPF_REG_A : BPF_REG_X;
                        insn->imm = fp->k;
                        break;
 
                /* X = A */
                case BPF_MISC | BPF_TAX:
                        insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-                       insn->a_reg = X_REG;
-                       insn->x_reg = A_REG;
+                       insn->a_reg = BPF_REG_X;
+                       insn->x_reg = BPF_REG_A;
                        break;
 
                /* A = X */
                case BPF_MISC | BPF_TXA:
                        insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
-                       insn->a_reg = A_REG;
-                       insn->x_reg = X_REG;
+                       insn->a_reg = BPF_REG_A;
+                       insn->x_reg = BPF_REG_X;
                        break;
 
                /* A = skb->len or X = skb->len */
@@ -1105,16 +1119,16 @@ do_pass:
                case BPF_LDX | BPF_W | BPF_LEN:
                        insn->code = BPF_LDX | BPF_MEM | BPF_W;
                        insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ?
-                                     A_REG : X_REG;
-                       insn->x_reg = CTX_REG;
+                                     BPF_REG_A : BPF_REG_X;
+                       insn->x_reg = BPF_REG_CTX;
                        insn->off = offsetof(struct sk_buff, len);
                        break;
 
                /* access seccomp_data fields */
                case BPF_LDX | BPF_ABS | BPF_W:
                        insn->code = BPF_LDX | BPF_MEM | BPF_W;
-                       insn->a_reg = A_REG;
-                       insn->x_reg = CTX_REG;
+                       insn->a_reg = BPF_REG_A;
+                       insn->x_reg = BPF_REG_CTX;
                        insn->off = fp->k;
                        break;
 
@@ -1362,6 +1376,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
                        ANCILLARY(VLAN_TAG);
                        ANCILLARY(VLAN_TAG_PRESENT);
                        ANCILLARY(PAY_OFFSET);
+                       ANCILLARY(RANDOM);
                        }
 
                        /* ancillary operation unknown or unsupported */
@@ -1459,7 +1474,7 @@ static struct sk_filter *__sk_migrate_realloc(struct sk_filter *fp,
 
        fp_new = sock_kmalloc(sk, len, GFP_KERNEL);
        if (fp_new) {
-               memcpy(fp_new, fp, sizeof(struct sk_filter));
+               *fp_new = *fp;
                /* As we're kepping orig_prog in fp_new along,
                 * we need to make sure we're not evicting it
                 * from the old fp.
@@ -1746,6 +1761,7 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
                [BPF_S_ANC_VLAN_TAG]    = BPF_LD|BPF_B|BPF_ABS,
                [BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS,
                [BPF_S_ANC_PAY_OFFSET]  = BPF_LD|BPF_B|BPF_ABS,
+               [BPF_S_ANC_RANDOM]      = BPF_LD|BPF_B|BPF_ABS,
                [BPF_S_LD_W_LEN]        = BPF_LD|BPF_W|BPF_LEN,
                [BPF_S_LD_W_IND]        = BPF_LD|BPF_W|BPF_IND,
                [BPF_S_LD_H_IND]        = BPF_LD|BPF_H|BPF_IND,
index 81d3a9a084536541867afe9350602c0c73253006..05e949d482049b839c59714381cde1e8a186926a 100644 (file)
@@ -273,7 +273,7 @@ static void cleanup_net(struct work_struct *work)
 {
        const struct pernet_operations *ops;
        struct net *net, *tmp;
-       LIST_HEAD(net_kill_list);
+       struct list_head net_kill_list;
        LIST_HEAD(net_exit_list);
 
        /* Atomically snapshot the list of namespaces to cleanup */
index d4ff41739b0f23fcb572905dd34288cb1d8ebd49..9837bebf93cea9e9a2f909947326b83b3a3356f9 100644 (file)
@@ -774,7 +774,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev,
                return 0;
 }
 
-static size_t rtnl_port_size(const struct net_device *dev)
+static size_t rtnl_port_size(const struct net_device *dev,
+                            u32 ext_filter_mask)
 {
        size_t port_size = nla_total_size(4)            /* PORT_VF */
                + nla_total_size(PORT_PROFILE_MAX)      /* PORT_PROFILE */
@@ -790,7 +791,8 @@ static size_t rtnl_port_size(const struct net_device *dev)
        size_t port_self_size = nla_total_size(sizeof(struct nlattr))
                + port_size;
 
-       if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
+       if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent ||
+           !(ext_filter_mask & RTEXT_FILTER_VF))
                return 0;
        if (dev_num_vf(dev->dev.parent))
                return port_self_size + vf_ports_size +
@@ -826,7 +828,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
               + nla_total_size(ext_filter_mask
                                & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */
               + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
-              + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
+              + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
               + rtnl_link_get_size(dev) /* IFLA_LINKINFO */
               + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
               + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
@@ -888,11 +890,13 @@ static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
-static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)
+static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev,
+                         u32 ext_filter_mask)
 {
        int err;
 
-       if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
+       if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent ||
+           !(ext_filter_mask & RTEXT_FILTER_VF))
                return 0;
 
        err = rtnl_port_self_fill(skb, dev);
@@ -1079,7 +1083,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                nla_nest_end(skb, vfinfo);
        }
 
-       if (rtnl_port_fill(skb, dev))
+       if (rtnl_port_fill(skb, dev, ext_filter_mask))
                goto nla_put_failure;
 
        if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) {
@@ -1198,6 +1202,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        struct hlist_head *head;
        struct nlattr *tb[IFLA_MAX+1];
        u32 ext_filter_mask = 0;
+       int err;
 
        s_h = cb->args[0];
        s_idx = cb->args[1];
@@ -1218,11 +1223,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
                hlist_for_each_entry_rcu(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
-                       if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
-                                            NETLINK_CB(cb->skb).portid,
-                                            cb->nlh->nlmsg_seq, 0,
-                                            NLM_F_MULTI,
-                                            ext_filter_mask) <= 0)
+                       err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
+                                              NETLINK_CB(cb->skb).portid,
+                                              cb->nlh->nlmsg_seq, 0,
+                                              NLM_F_MULTI,
+                                              ext_filter_mask);
+                       /* If we ran out of room on the first message,
+                        * we're in trouble
+                        */
+                       WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
+
+                       if (err <= 0)
                                goto out;
 
                        nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -1395,7 +1406,8 @@ static int do_set_master(struct net_device *dev, int ifindex)
        return 0;
 }
 
-static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
+static int do_setlink(const struct sk_buff *skb,
+                     struct net_device *dev, struct ifinfomsg *ifm,
                      struct nlattr **tb, char *ifname, int modified)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
@@ -1407,7 +1419,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                        err = PTR_ERR(net);
                        goto errout;
                }
-               if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
+               if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
                        err = -EPERM;
                        goto errout;
                }
@@ -1661,7 +1673,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (err < 0)
                goto errout;
 
-       err = do_setlink(dev, ifm, tb, ifname, 0);
+       err = do_setlink(skb, dev, ifm, tb, ifname, 0);
 errout:
        return err;
 }
@@ -1778,7 +1790,8 @@ err:
 }
 EXPORT_SYMBOL(rtnl_create_link);
 
-static int rtnl_group_changelink(struct net *net, int group,
+static int rtnl_group_changelink(const struct sk_buff *skb,
+               struct net *net, int group,
                struct ifinfomsg *ifm,
                struct nlattr **tb)
 {
@@ -1787,7 +1800,7 @@ static int rtnl_group_changelink(struct net *net, int group,
 
        for_each_netdev(net, dev) {
                if (dev->group == group) {
-                       err = do_setlink(dev, ifm, tb, NULL, 0);
+                       err = do_setlink(skb, dev, ifm, tb, NULL, 0);
                        if (err < 0)
                                return err;
                }
@@ -1929,12 +1942,12 @@ replay:
                                modified = 1;
                        }
 
-                       return do_setlink(dev, ifm, tb, ifname, modified);
+                       return do_setlink(skb, dev, ifm, tb, ifname, modified);
                }
 
                if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
                        if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
-                               return rtnl_group_changelink(net,
+                               return rtnl_group_changelink(skb, net,
                                                nla_get_u32(tb[IFLA_GROUP]),
                                                ifm, tb);
                        return -ENODEV;
@@ -2321,7 +2334,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
        int err = -EINVAL;
        __u8 *addr;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
@@ -2773,7 +2786,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        sz_idx = type>>2;
        kind = type&3;
 
-       if (kind != 2 && !ns_capable(net->user_ns, CAP_NET_ADMIN))
+       if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
index b4fff008136fafcca363e3a41ef441c2a1be878b..664ee4295b6f6ec38fb4f89d11c52eaa383a15d1 100644 (file)
 static DEFINE_MUTEX(proto_list_mutex);
 static LIST_HEAD(proto_list);
 
+/**
+ * sk_ns_capable - General socket capability test
+ * @sk: Socket to use a capability on or through
+ * @user_ns: The user namespace of the capability to use
+ * @cap: The capability to use
+ *
+ * Test to see if the opener of the socket had when the socket was
+ * created and the current process has the capability @cap in the user
+ * namespace @user_ns.
+ */
+bool sk_ns_capable(const struct sock *sk,
+                  struct user_namespace *user_ns, int cap)
+{
+       return file_ns_capable(sk->sk_socket->file, user_ns, cap) &&
+               ns_capable(user_ns, cap);
+}
+EXPORT_SYMBOL(sk_ns_capable);
+
+/**
+ * sk_capable - Socket global capability test
+ * @sk: Socket to use a capability on or through
+ * @cap: The global capbility to use
+ *
+ * Test to see if the opener of the socket had when the socket was
+ * created and the current process has the capability @cap in all user
+ * namespaces.
+ */
+bool sk_capable(const struct sock *sk, int cap)
+{
+       return sk_ns_capable(sk, &init_user_ns, cap);
+}
+EXPORT_SYMBOL(sk_capable);
+
+/**
+ * sk_net_capable - Network namespace socket capability test
+ * @sk: Socket to use a capability on or through
+ * @cap: The capability to use
+ *
+ * Test to see if the opener of the socket had when the socke was created
+ * and the current process has the capability @cap over the network namespace
+ * the socket is a member of.
+ */
+bool sk_net_capable(const struct sock *sk, int cap)
+{
+       return sk_ns_capable(sk, sock_net(sk)->user_ns, cap);
+}
+EXPORT_SYMBOL(sk_net_capable);
+
+
 #ifdef CONFIG_MEMCG_KMEM
 int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
index d7af1885932269eb9f4196fe1211a6d09e298b97..a4216a4c95720f105b0cd7841cd59e84d3dda7a6 100644 (file)
@@ -49,7 +49,7 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
 }
 EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
 
-int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
+int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
                             struct sk_buff *skb, int attrtype)
 {
        struct sock_fprog_kern *fprog;
@@ -58,7 +58,7 @@ int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
        unsigned int flen;
        int err = 0;
 
-       if (!ns_capable(user_ns, CAP_NET_ADMIN)) {
+       if (!may_report_filterinfo) {
                nla_reserve(skb, attrtype, 0);
                return 0;
        }
index 553644402670b3461bde7fb26705ddde8729be75..f8b98d89c28527f049b4c3132aa7f0b412cfa0ef 100644 (file)
@@ -1669,7 +1669,7 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct nlmsghdr *reply_nlh = NULL;
        const struct reply_func *fn;
 
-       if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN))
+       if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
index a603823a3e279c850d1641e5f4d59be983400488..3b726f31c64c0b88efcfacd4d64df7177260ad5c 100644 (file)
@@ -574,7 +574,7 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct dn_ifaddr __rcu **ifap;
        int err = -EINVAL;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (!net_eq(net, &init_net))
@@ -618,7 +618,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct dn_ifaddr *ifa;
        int err;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (!net_eq(net, &init_net))
index 57dc159245ecfff38e318626cf0ea1ffa9db1cae..d332aefb0846f86a11d924e3e1e7ad23e279dda2 100644 (file)
@@ -505,7 +505,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct nlattr *attrs[RTA_MAX+1];
        int err;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (!net_eq(net, &init_net))
@@ -530,7 +530,7 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct nlattr *attrs[RTA_MAX+1];
        int err;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if (!net_eq(net, &init_net))
index e83015cecfa7507d551bd19e4b4121ad0f25eeaf..e4d9560a910b0eb96ed3a4ad59d63771f865de3c 100644 (file)
@@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
        if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
                return;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);
 
        /* Eventually we might send routing messages too */
index ef2d54372b134330d0fa7c51c2049379ce69e85e..6f1428c4870b11e9bab087c54d414079514caf8a 100644 (file)
@@ -36,7 +36,7 @@ struct lowpan_frag_info {
        u8 d_offset;
 };
 
-struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb)
+static struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb)
 {
        return (struct lowpan_frag_info *)skb->cb;
 }
@@ -120,6 +120,8 @@ fq_find(struct net *net, const struct lowpan_frag_info *frag_info,
        struct inet_frag_queue *q;
        struct lowpan_create_arg arg;
        unsigned int hash;
+       struct netns_ieee802154_lowpan *ieee802154_lowpan =
+               net_ieee802154_lowpan(net);
 
        arg.tag = frag_info->d_tag;
        arg.d_size = frag_info->d_size;
@@ -129,7 +131,7 @@ fq_find(struct net *net, const struct lowpan_frag_info *frag_info,
        read_lock(&lowpan_frags.lock);
        hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst);
 
-       q = inet_frag_find(&net->ieee802154_lowpan.frags,
+       q = inet_frag_find(&ieee802154_lowpan->frags,
                           &lowpan_frags, &arg, hash);
        if (IS_ERR_OR_NULL(q)) {
                inet_frag_maybe_warn_overflow(q, pr_fmt());
@@ -357,6 +359,8 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
        struct net *net = dev_net(skb->dev);
        struct lowpan_frag_info *frag_info = lowpan_cb(skb);
        struct ieee802154_addr source, dest;
+       struct netns_ieee802154_lowpan *ieee802154_lowpan =
+               net_ieee802154_lowpan(net);
        int err;
 
        source = mac_cb(skb)->source;
@@ -366,10 +370,10 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
        if (err < 0)
                goto err;
 
-       if (frag_info->d_size > net->ieee802154_lowpan.max_dsize)
+       if (frag_info->d_size > ieee802154_lowpan->max_dsize)
                goto err;
 
-       inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false);
+       inet_frag_evictor(&ieee802154_lowpan->frags, &lowpan_frags, false);
 
        fq = fq_find(net, frag_info, &source, &dest);
        if (fq != NULL) {
@@ -436,6 +440,8 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
+       struct netns_ieee802154_lowpan *ieee802154_lowpan =
+               net_ieee802154_lowpan(net);
 
        table = lowpan_frags_ns_ctl_table;
        if (!net_eq(net, &init_net)) {
@@ -444,10 +450,10 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
                if (table == NULL)
                        goto err_alloc;
 
-               table[0].data = &net->ieee802154_lowpan.frags.high_thresh;
-               table[1].data = &net->ieee802154_lowpan.frags.low_thresh;
-               table[2].data = &net->ieee802154_lowpan.frags.timeout;
-               table[3].data = &net->ieee802154_lowpan.max_dsize;
+               table[0].data = &ieee802154_lowpan->frags.high_thresh;
+               table[1].data = &ieee802154_lowpan->frags.low_thresh;
+               table[2].data = &ieee802154_lowpan->frags.timeout;
+               table[3].data = &ieee802154_lowpan->max_dsize;
 
                /* Don't export sysctls to unprivileged users */
                if (net->user_ns != &init_user_ns)
@@ -458,7 +464,7 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
        if (hdr == NULL)
                goto err_reg;
 
-       net->ieee802154_lowpan.sysctl.frags_hdr = hdr;
+       ieee802154_lowpan->sysctl.frags_hdr = hdr;
        return 0;
 
 err_reg:
@@ -471,9 +477,11 @@ err_alloc:
 static void __net_exit lowpan_frags_ns_sysctl_unregister(struct net *net)
 {
        struct ctl_table *table;
+       struct netns_ieee802154_lowpan *ieee802154_lowpan =
+               net_ieee802154_lowpan(net);
 
-       table = net->ieee802154_lowpan.sysctl.frags_hdr->ctl_table_arg;
-       unregister_net_sysctl_table(net->ieee802154_lowpan.sysctl.frags_hdr);
+       table = ieee802154_lowpan->sysctl.frags_hdr->ctl_table_arg;
+       unregister_net_sysctl_table(ieee802154_lowpan->sysctl.frags_hdr);
        if (!net_eq(net, &init_net))
                kfree(table);
 }
@@ -514,20 +522,26 @@ static inline void lowpan_frags_sysctl_unregister(void)
 
 static int __net_init lowpan_frags_init_net(struct net *net)
 {
-       net->ieee802154_lowpan.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
-       net->ieee802154_lowpan.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
-       net->ieee802154_lowpan.frags.timeout = IPV6_FRAG_TIMEOUT;
-       net->ieee802154_lowpan.max_dsize = 0xFFFF;
+       struct netns_ieee802154_lowpan *ieee802154_lowpan =
+               net_ieee802154_lowpan(net);
 
-       inet_frags_init_net(&net->ieee802154_lowpan.frags);
+       ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
+       ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH;
+       ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT;
+       ieee802154_lowpan->max_dsize = 0xFFFF;
+
+       inet_frags_init_net(&ieee802154_lowpan->frags);
 
        return lowpan_frags_ns_sysctl_register(net);
 }
 
 static void __net_exit lowpan_frags_exit_net(struct net *net)
 {
+       struct netns_ieee802154_lowpan *ieee802154_lowpan =
+               net_ieee802154_lowpan(net);
+
        lowpan_frags_ns_sysctl_unregister(net);
-       inet_frags_exit_net(&net->ieee802154_lowpan.frags, &lowpan_frags);
+       inet_frags_exit_net(&ieee802154_lowpan->frags, &lowpan_frags);
 }
 
 static struct pernet_operations lowpan_frags_ops = {
index 48f4244651125fb4ef7bcfda155137f287b07c77..c98cf141f4ed66aa57595423baf83b6fa92e19da 100644 (file)
@@ -120,7 +120,7 @@ int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;  /* usual time to live: 10 min
 static void inetpeer_gc_worker(struct work_struct *work)
 {
        struct inet_peer *p, *n, *c;
-       LIST_HEAD(list);
+       struct list_head list;
 
        spin_lock_bh(&gc_lock);
        list_replace_init(&gc_list, &list);
index 94213c89156511d86682b2c3e034f9e5b6ef5ccb..c5a557a06a31ae589a0938d2d1a12073ae3706df 100644 (file)
@@ -410,7 +410,7 @@ static int ipgre_open(struct net_device *dev)
                struct flowi4 fl4;
                struct rtable *rt;
 
-               rt = ip_route_output_gre(dev_net(dev), &fl4,
+               rt = ip_route_output_gre(t->net, &fl4,
                                         t->parms.iph.daddr,
                                         t->parms.iph.saddr,
                                         t->parms.o_key,
@@ -434,7 +434,7 @@ static int ipgre_close(struct net_device *dev)
 
        if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
                struct in_device *in_dev;
-               in_dev = inetdev_by_index(dev_net(dev), t->mlink);
+               in_dev = inetdev_by_index(t->net, t->mlink);
                if (in_dev)
                        ip_mc_dec_group(in_dev, t->parms.iph.daddr);
        }
@@ -478,7 +478,7 @@ static void __gre_tunnel_init(struct net_device *dev)
        dev->needed_headroom    = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
 
-       dev->features           |= NETIF_F_NETNS_LOCAL | GRE_FEATURES;
+       dev->features           |= GRE_FEATURES;
        dev->hw_features        |= GRE_FEATURES;
 
        if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
index f4ab72e19af923536656e734996f4b9201684b58..5e7aecea05cd2afbd3e3e13f417e26687517b468 100644 (file)
@@ -364,7 +364,7 @@ int ip_options_compile(struct net *net,
                        }
                        if (optptr[2] <= optlen) {
                                unsigned char *timeptr = NULL;
-                               if (optptr[2]+3 > optptr[1]) {
+                               if (optptr[2]+3 > optlen) {
                                        pp_ptr = optptr + 2;
                                        goto error;
                                }
@@ -376,7 +376,7 @@ int ip_options_compile(struct net *net,
                                        optptr[2] += 4;
                                        break;
                                case IPOPT_TS_TSANDADDR:
-                                       if (optptr[2]+7 > optptr[1]) {
+                                       if (optptr[2]+7 > optlen) {
                                                pp_ptr = optptr + 2;
                                                goto error;
                                        }
@@ -390,7 +390,7 @@ int ip_options_compile(struct net *net,
                                        optptr[2] += 8;
                                        break;
                                case IPOPT_TS_PRESPEC:
-                                       if (optptr[2]+7 > optptr[1]) {
+                                       if (optptr[2]+7 > optlen) {
                                                pp_ptr = optptr + 2;
                                                goto error;
                                        }
index fa5b7519765f10c61b8855c6646b79915384062f..b3f859731c60eccfdd77517989cff5ba84f6581a 100644 (file)
@@ -442,6 +442,8 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
                tunnel->i_seqno = ntohl(tpi->seq) + 1;
        }
 
+       skb_reset_network_header(skb);
+
        err = IP_ECN_decapsulate(iph, skb);
        if (unlikely(err)) {
                if (log_ecn_error)
index afcee51b90ede30a846bbd7a5c16b6996d955889..dbaa3d3901775fb2ca953a23ddf9fffd262e4248 100644 (file)
@@ -349,7 +349,6 @@ static int vti_tunnel_init(struct net_device *dev)
        memcpy(dev->dev_addr, &iph->saddr, 4);
        memcpy(dev->broadcast, &iph->daddr, 4);
 
-       dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN;
        dev->flags              = IFF_NOARP;
        dev->iflink             = 0;
index 4bd6d52eeffb6c7ddc3e98054a7070826a4c4dcd..eb1dde37e678f6bb1570bfb452c019b88eb1a76c 100644 (file)
@@ -2916,6 +2916,14 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
        case TCP_USER_TIMEOUT:
                val = jiffies_to_msecs(icsk->icsk_user_timeout);
                break;
+
+       case TCP_FASTOPEN:
+               if (icsk->icsk_accept_queue.fastopenq != NULL)
+                       val = icsk->icsk_accept_queue.fastopenq->max_qlen;
+               else
+                       val = 0;
+               break;
+
        case TCP_TIMESTAMP:
                val = tcp_time_stamp + tp->tsoffset;
                break;
index 821846fb0a7e211fc870b1afce5991bc3de28494..d5de69bc04f581ac589ae0f6fe7fcc3646b2cc3e 100644 (file)
@@ -140,13 +140,12 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
                ca->cnt = 1;
 }
 
-static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                             u32 in_flight)
+static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bictcp *ca = inet_csk_ca(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (tp->snd_cwnd <= tp->snd_ssthresh)
index 2b9464c93b8859fcbef0f900f70a4bed2dc6e617..7b09d8b49fa51271cc0fa99a3fcda9f017c0f469 100644 (file)
@@ -276,26 +276,6 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
        return err;
 }
 
-/* RFC2861 Check whether we are limited by application or congestion window
- * This is the inverse of cwnd check in tcp_tso_should_defer
- */
-bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
-{
-       const struct tcp_sock *tp = tcp_sk(sk);
-       u32 left;
-
-       if (in_flight >= tp->snd_cwnd)
-               return true;
-
-       left = tp->snd_cwnd - in_flight;
-       if (sk_can_gso(sk) &&
-           left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
-           left < tp->xmit_size_goal_segs)
-               return true;
-       return left <= tcp_max_tso_deferred_mss(tp);
-}
-EXPORT_SYMBOL_GPL(tcp_is_cwnd_limited);
-
 /* Slow start is used when congestion window is no greater than the slow start
  * threshold. We base on RFC2581 and also handle stretch ACKs properly.
  * We do not implement RFC3465 Appropriate Byte Counting (ABC) per se but
@@ -337,11 +317,11 @@ EXPORT_SYMBOL_GPL(tcp_cong_avoid_ai);
 /* This is Jacobson's slow start and congestion avoidance.
  * SIGCOMM '88, p. 328.
  */
-void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight)
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        /* In "safe" area, increase. */
index 8bf224516ba2a26a661d16f89aaee32301d09397..a9bd8a4828a9e5c2da275626c11c6c953a1b3dd6 100644 (file)
@@ -304,13 +304,12 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
                ca->cnt = 1;
 }
 
-static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                             u32 in_flight)
+static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bictcp *ca = inet_csk_ca(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (tp->snd_cwnd <= tp->snd_ssthresh) {
@@ -409,7 +408,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us)
                ratio -= ca->delayed_ack >> ACK_RATIO_SHIFT;
                ratio += cnt;
 
-               ca->delayed_ack = min(ratio, ACK_RATIO_LIMIT);
+               ca->delayed_ack = clamp(ratio, 1U, ACK_RATIO_LIMIT);
        }
 
        /* Some calls are for duplicates without timetamps */
index 8b9e7bad77c09a0c07706b955c29b81d4e71a542..1c4908280d921fbe9a9e21e4fd55d1a87f2db706 100644 (file)
@@ -109,12 +109,12 @@ static void hstcp_init(struct sock *sk)
        tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
 }
 
-static void hstcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight)
+static void hstcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct hstcp *ca = inet_csk_ca(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (tp->snd_cwnd <= tp->snd_ssthresh)
index 4a194acfd9237f1aaadfe9f9831358f5c9037cf7..031361311a8b92b1f7ab1172fb00e3bbb0503129 100644 (file)
@@ -227,12 +227,12 @@ static u32 htcp_recalc_ssthresh(struct sock *sk)
        return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
 }
 
-static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight)
+static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct htcp *ca = inet_csk_ca(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (tp->snd_cwnd <= tp->snd_ssthresh)
index a15a799bf76888f3633b27cf57e8e05f30339601..d8f8f05a49516ec2d9213f10af77b82fbf32bff7 100644 (file)
@@ -87,8 +87,7 @@ static inline u32 hybla_fraction(u32 odds)
  *     o Give cwnd a new value based on the model proposed
  *     o remember increments <1
  */
-static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                            u32 in_flight)
+static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct hybla *ca = inet_csk_ca(sk);
@@ -101,11 +100,11 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked,
                ca->minrtt_us = tp->srtt_us;
        }
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (!ca->hybla_en) {
-               tcp_reno_cong_avoid(sk, ack, acked, in_flight);
+               tcp_reno_cong_avoid(sk, ack, acked);
                return;
        }
 
index 863d105e30150391e9ac3ce8545c0411e4d083ab..5999b3972e6449d616facb628d27116ab8876ac2 100644 (file)
@@ -255,8 +255,7 @@ static void tcp_illinois_state(struct sock *sk, u8 new_state)
 /*
  * Increase window in response to successful acknowledgment.
  */
-static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                                   u32 in_flight)
+static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct illinois *ca = inet_csk_ca(sk);
@@ -265,7 +264,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked,
                update_params(sk);
 
        /* RFC2861 only increase cwnd if fully utilized */
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        /* In slow start */
index d6b46eb2f94c5e6fb7eb77592722115eed9c8d7c..350b2072f0ab82776f196dfbe9c5b87b80a79046 100644 (file)
@@ -2938,10 +2938,11 @@ static void tcp_synack_rtt_meas(struct sock *sk, const u32 synack_stamp)
                tcp_ack_update_rtt(sk, FLAG_SYN_ACKED, seq_rtt_us, -1L);
 }
 
-static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight)
+static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
-       icsk->icsk_ca_ops->cong_avoid(sk, ack, acked, in_flight);
+
+       icsk->icsk_ca_ops->cong_avoid(sk, ack, acked);
        tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
 }
 
@@ -3364,7 +3365,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        u32 ack_seq = TCP_SKB_CB(skb)->seq;
        u32 ack = TCP_SKB_CB(skb)->ack_seq;
        bool is_dupack = false;
-       u32 prior_in_flight;
        u32 prior_fackets;
        int prior_packets = tp->packets_out;
        const int prior_unsacked = tp->packets_out - tp->sacked_out;
@@ -3397,7 +3397,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
                flag |= FLAG_SND_UNA_ADVANCED;
 
        prior_fackets = tp->fackets_out;
-       prior_in_flight = tcp_packets_in_flight(tp);
 
        /* ts_recent update must be made after we are sure that the packet
         * is in window.
@@ -3452,7 +3451,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
        /* Advance cwnd if state allows */
        if (tcp_may_raise_cwnd(sk, flag))
-               tcp_cong_avoid(sk, ack, acked, prior_in_flight);
+               tcp_cong_avoid(sk, ack, acked);
 
        if (tcp_ack_is_dubious(sk, flag)) {
                is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
@@ -4703,28 +4702,6 @@ static int tcp_prune_queue(struct sock *sk)
        return -1;
 }
 
-/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto.
- * As additional protections, we do not touch cwnd in retransmission phases,
- * and if application hit its sndbuf limit recently.
- */
-void tcp_cwnd_application_limited(struct sock *sk)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&
-           sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
-               /* Limited by application or receiver window. */
-               u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk));
-               u32 win_used = max(tp->snd_cwnd_used, init_win);
-               if (win_used < tp->snd_cwnd) {
-                       tp->snd_ssthresh = tcp_current_ssthresh(sk);
-                       tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1;
-               }
-               tp->snd_cwnd_used = 0;
-       }
-       tp->snd_cwnd_stamp = tcp_time_stamp;
-}
-
 static bool tcp_should_expand_sndbuf(const struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
index 438f3b95143df0bffa01322c62b44c8fcd6d6b8b..ad166dcc278fe46f2e5863eb90cf8b12b878a404 100644 (file)
@@ -1744,28 +1744,6 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        return sk;
 }
 
-static __sum16 tcp_v4_checksum_init(struct sk_buff *skb)
-{
-       const struct iphdr *iph = ip_hdr(skb);
-
-       if (skb->ip_summed == CHECKSUM_COMPLETE) {
-               if (!tcp_v4_check(skb->len, iph->saddr,
-                                 iph->daddr, skb->csum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       return 0;
-               }
-       }
-
-       skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
-                                      skb->len, IPPROTO_TCP, 0);
-
-       if (skb->len <= 76) {
-               return __skb_checksum_complete(skb);
-       }
-       return 0;
-}
-
-
 /* The socket must have it's spinlock held when we get
  * here.
  *
@@ -1960,7 +1938,8 @@ int tcp_v4_rcv(struct sk_buff *skb)
         * Packet length and doff are validated by header prediction,
         * provided case of th->doff==0 is eliminated.
         * So, we defer the checks. */
-       if (!skb_csum_unnecessary(skb) && tcp_v4_checksum_init(skb))
+
+       if (skb_checksum_init(skb, IPPROTO_TCP, inet_compute_pseudo))
                goto csum_error;
 
        th = tcp_hdr(skb);
index c9aecae313276d134ef56d1385ac44266c200a51..1e70fa8fa793fdbca3ca782231f8b775ed96f205 100644 (file)
@@ -115,13 +115,12 @@ static void tcp_lp_init(struct sock *sk)
  * Will only call newReno CA when away from inference.
  * From TCP-LP's paper, this will be handled in additive increasement.
  */
-static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                             u32 in_flight)
+static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct lp *lp = inet_csk_ca(sk);
 
        if (!(lp->flag & LP_WITHIN_INF))
-               tcp_reno_cong_avoid(sk, ack, acked, in_flight);
+               tcp_reno_cong_avoid(sk, ack, acked);
 }
 
 /**
index 025e25093984bacaca7a5cdaa26074d436f29cf1..694711a140d46fe8877c493df407fe946fbade1d 100644 (file)
@@ -878,15 +878,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
        BUG_ON(!skb || !tcp_skb_pcount(skb));
 
        if (clone_it) {
-               const struct sk_buff *fclone = skb + 1;
-
                skb_mstamp_get(&skb->skb_mstamp);
 
-               if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
-                            fclone->fclone == SKB_FCLONE_CLONE))
-                       NET_INC_STATS(sock_net(sk),
-                                     LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
-
                if (unlikely(skb_cloned(skb)))
                        skb = pskb_copy(skb, gfp_mask);
                else
@@ -1387,12 +1380,35 @@ unsigned int tcp_current_mss(struct sock *sk)
        return mss_now;
 }
 
-/* Congestion window validation. (RFC2861) */
-static void tcp_cwnd_validate(struct sock *sk)
+/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto.
+ * As additional protections, we do not touch cwnd in retransmission phases,
+ * and if application hit its sndbuf limit recently.
+ */
+static void tcp_cwnd_application_limited(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+
+       if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&
+           sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
+               /* Limited by application or receiver window. */
+               u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk));
+               u32 win_used = max(tp->snd_cwnd_used, init_win);
+               if (win_used < tp->snd_cwnd) {
+                       tp->snd_ssthresh = tcp_current_ssthresh(sk);
+                       tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1;
+               }
+               tp->snd_cwnd_used = 0;
+       }
+       tp->snd_cwnd_stamp = tcp_time_stamp;
+}
+
+static void tcp_cwnd_validate(struct sock *sk, u32 unsent_segs)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (tp->packets_out >= tp->snd_cwnd) {
+       tp->lsnd_pending = tp->packets_out + unsent_segs;
+
+       if (tcp_is_cwnd_limited(sk)) {
                /* Network is feed fully. */
                tp->snd_cwnd_used = 0;
                tp->snd_cwnd_stamp = tcp_time_stamp;
@@ -1865,7 +1881,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
-       unsigned int tso_segs, sent_pkts;
+       unsigned int tso_segs, sent_pkts, unsent_segs = 0;
        int cwnd_quota;
        int result;
 
@@ -1909,7 +1925,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                                break;
                } else {
                        if (!push_one && tcp_tso_should_defer(sk, skb))
-                               break;
+                               goto compute_unsent_segs;
                }
 
                /* TCP Small Queues :
@@ -1934,8 +1950,14 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                         * there is no smp_mb__after_set_bit() yet
                         */
                        smp_mb__after_clear_bit();
-                       if (atomic_read(&sk->sk_wmem_alloc) > limit)
+                       if (atomic_read(&sk->sk_wmem_alloc) > limit) {
+                               u32 unsent_bytes;
+
+compute_unsent_segs:
+                               unsent_bytes = tp->write_seq - tp->snd_nxt;
+                               unsent_segs = DIV_ROUND_UP(unsent_bytes, mss_now);
                                break;
+                       }
                }
 
                limit = mss_now;
@@ -1975,7 +1997,7 @@ repair:
                /* Send one loss probe per tail loss episode. */
                if (push_one != 2)
                        tcp_schedule_loss_probe(sk);
-               tcp_cwnd_validate(sk);
+               tcp_cwnd_validate(sk, unsent_segs);
                return false;
        }
        return (push_one == 2) || (!tp->packets_out && tcp_send_head(sk));
@@ -2039,6 +2061,25 @@ bool tcp_schedule_loss_probe(struct sock *sk)
        return true;
 }
 
+/* Thanks to skb fast clones, we can detect if a prior transmit of
+ * a packet is still in a qdisc or driver queue.
+ * In this case, there is very little point doing a retransmit !
+ * Note: This is called from BH context only.
+ */
+static bool skb_still_in_host_queue(const struct sock *sk,
+                                   const struct sk_buff *skb)
+{
+       const struct sk_buff *fclone = skb + 1;
+
+       if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
+                    fclone->fclone == SKB_FCLONE_CLONE)) {
+               NET_INC_STATS_BH(sock_net(sk),
+                                LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
+               return true;
+       }
+       return false;
+}
+
 /* When probe timeout (PTO) fires, send a new segment if one exists, else
  * retransmit the last segment.
  */
@@ -2064,6 +2105,9 @@ void tcp_send_loss_probe(struct sock *sk)
        if (WARN_ON(!skb))
                goto rearm_timer;
 
+       if (skb_still_in_host_queue(sk, skb))
+               goto rearm_timer;
+
        pcount = tcp_skb_pcount(skb);
        if (WARN_ON(!pcount))
                goto rearm_timer;
@@ -2385,6 +2429,9 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
            min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf))
                return -EAGAIN;
 
+       if (skb_still_in_host_queue(sk, skb))
+               return -EBUSY;
+
        if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {
                if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
                        BUG();
@@ -2441,8 +2488,14 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
        }
 
-       if (likely(!err))
+       if (likely(!err)) {
                TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS;
+               /* Update global TCP statistics. */
+               TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS);
+               if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
+                       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
+               tp->total_retrans++;
+       }
        return err;
 }
 
@@ -2452,12 +2505,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        int err = __tcp_retransmit_skb(sk, skb);
 
        if (err == 0) {
-               /* Update global TCP statistics. */
-               TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS);
-               if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
-                       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
-               tp->total_retrans++;
-
 #if FASTRETRANS_DEBUG > 0
                if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
                        net_dbg_ratelimited("retrans_out leaked\n");
@@ -2478,7 +2525,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                 * see tcp_input.c tcp_sacktag_write_queue().
                 */
                TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt;
-       } else {
+       } else if (err != -EBUSY) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL);
        }
        return err;
index 0ac50836da4d42832f3aa35c9a4cebbf79f69981..8250949b88538db4e0f2d318050518855e74cf3d 100644 (file)
 #define TCP_SCALABLE_AI_CNT    50U
 #define TCP_SCALABLE_MD_SCALE  3
 
-static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                                   u32 in_flight)
+static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (tp->snd_cwnd <= tp->snd_ssthresh)
index 48539fff6357a4e778c537b99bb9a7fd49eb43b3..9a5e05f27f4f7cce16cb285698cb0fc73ef49a91 100644 (file)
@@ -163,14 +163,13 @@ static inline u32 tcp_vegas_ssthresh(struct tcp_sock *tp)
        return  min(tp->snd_ssthresh, tp->snd_cwnd-1);
 }
 
-static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                                u32 in_flight)
+static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct vegas *vegas = inet_csk_ca(sk);
 
        if (!vegas->doing_vegas_now) {
-               tcp_reno_cong_avoid(sk, ack, acked, in_flight);
+               tcp_reno_cong_avoid(sk, ack, acked);
                return;
        }
 
@@ -195,7 +194,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked,
                        /* We don't have enough RTT samples to do the Vegas
                         * calculation, so we'll behave like Reno.
                         */
-                       tcp_reno_cong_avoid(sk, ack, acked, in_flight);
+                       tcp_reno_cong_avoid(sk, ack, acked);
                } else {
                        u32 rtt, diff;
                        u64 target_cwnd;
index 1b8e28fcd7e1cab3edd586db1b716742a4402fd7..27b9825753d15d89717d7b76e1c38fae4758cfbc 100644 (file)
@@ -114,19 +114,18 @@ static void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event)
                tcp_veno_init(sk);
 }
 
-static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                               u32 in_flight)
+static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct veno *veno = inet_csk_ca(sk);
 
        if (!veno->doing_veno_now) {
-               tcp_reno_cong_avoid(sk, ack, acked, in_flight);
+               tcp_reno_cong_avoid(sk, ack, acked);
                return;
        }
 
        /* limited by applications */
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        /* We do the Veno calculations only if we got enough rtt samples */
@@ -134,7 +133,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked,
                /* We don't have enough rtt samples to do the Veno
                 * calculation, so we'll behave like Reno.
                 */
-               tcp_reno_cong_avoid(sk, ack, acked, in_flight);
+               tcp_reno_cong_avoid(sk, ack, acked);
        } else {
                u64 target_cwnd;
                u32 rtt;
index 5ede0e727945add71904a2d3c57d334e77e94baf..599b79b8eac07298a34cff43ae87e546bdb36847 100644 (file)
@@ -69,13 +69,12 @@ static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, s32 rtt_us)
        tcp_vegas_pkts_acked(sk, pkts_acked, rtt_us);
 }
 
-static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked,
-                               u32 in_flight)
+static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct yeah *yeah = inet_csk_ca(sk);
 
-       if (!tcp_is_cwnd_limited(sk, in_flight))
+       if (!tcp_is_cwnd_limited(sk))
                return;
 
        if (tp->snd_cwnd <= tp->snd_ssthresh)
index 4468e1adc094a1f6f12eb20cf7c79a9b9187826d..f2d05d7be743d09fd42cd0e302f4c088bc71048b 100644 (file)
@@ -1672,7 +1672,6 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
                                 int proto)
 {
-       const struct iphdr *iph;
        int err;
 
        UDP_SKB_CB(skb)->partial_cov = 0;
@@ -1684,22 +1683,8 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
                        return err;
        }
 
-       iph = ip_hdr(skb);
-       if (uh->check == 0) {
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-       } else if (skb->ip_summed == CHECKSUM_COMPLETE) {
-               if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
-                                     proto, skb->csum))
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       }
-       if (!skb_csum_unnecessary(skb))
-               skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
-                                              skb->len, proto, 0);
-       /* Probably, we should checksum udp header (it should be in cache
-        * in any case) and data in tiny packets (< rx copybreak).
-        */
-
-       return 0;
+       return skb_checksum_init_zero_check(skb, proto, uh->check,
+                                           inet_compute_pseudo);
 }
 
 /*
index 40e701f2e1e0324af6f0af781ac6715866ad88d3..186a8ecf92fa84bda9d0f6b050131da603c7694a 100644 (file)
@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
        if (err)
                return err;
 
-       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
-
-       skb->protocol = htons(ETH_P_IP);
+       IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
 
        return x->outer_mode->output2(x, skb);
 }
@@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 
 int xfrm4_output_finish(struct sk_buff *skb)
 {
+       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+       skb->protocol = htons(ETH_P_IP);
+
+#ifdef CONFIG_NETFILTER
+       IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+#endif
+
+       return xfrm_output(skb);
+}
+
+static int __xfrm4_output(struct sk_buff *skb)
+{
+       struct xfrm_state *x = skb_dst(skb)->xfrm;
+
 #ifdef CONFIG_NETFILTER
-       if (!skb_dst(skb)->xfrm) {
+       if (!x) {
                IPCB(skb)->flags |= IPSKB_REROUTED;
                return dst_output(skb);
        }
-
-       IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
 #endif
 
-       skb->protocol = htons(ETH_P_IP);
-       return xfrm_output(skb);
+       return x->outer_mode->afinfo->output_finish(skb);
 }
 
 int xfrm4_output(struct sock *sk, struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb_dst(skb);
-       struct xfrm_state *x = dst->xfrm;
-
        return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
-                           NULL, dst->dev,
-                           x->outer_mode->afinfo->output_finish,
+                           NULL, skb_dst(skb)->dev, __xfrm4_output,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
 
index 6c7fa0853fc74ef179b00de52d78aecee342e18b..1ac13c0300b70db08bc941c270ae54d13d81844c 100644 (file)
@@ -2504,8 +2504,8 @@ static int inet6_addr_add(struct net *net, int ifindex,
        return PTR_ERR(ifp);
 }
 
-static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx,
-                         unsigned int plen)
+static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
+                         const struct in6_addr *pfx, unsigned int plen)
 {
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev;
@@ -2528,7 +2528,12 @@ static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *p
                        in6_ifa_hold(ifp);
                        read_unlock_bh(&idev->lock);
 
+                       if (!(ifp->flags & IFA_F_TEMPORARY) &&
+                           (ifa_flags & IFA_F_MANAGETEMPADDR))
+                               manage_tempaddrs(idev, ifp, 0, 0, false,
+                                                jiffies);
                        ipv6_del_addr(ifp);
+                       addrconf_verify_rtnl();
                        return 0;
                }
        }
@@ -2568,7 +2573,7 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg)
                return -EFAULT;
 
        rtnl_lock();
-       err = inet6_addr_del(net, ireq.ifr6_ifindex, &ireq.ifr6_addr,
+       err = inet6_addr_del(net, ireq.ifr6_ifindex, 0, &ireq.ifr6_addr,
                             ireq.ifr6_prefixlen);
        rtnl_unlock();
        return err;
@@ -2813,18 +2818,6 @@ static void addrconf_gre_config(struct net_device *dev)
 }
 #endif
 
-static inline int
-ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
-{
-       struct in6_addr lladdr;
-
-       if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) {
-               addrconf_add_linklocal(idev, &lladdr);
-               return 0;
-       }
-       return -1;
-}
-
 static int addrconf_notify(struct notifier_block *this, unsigned long event,
                           void *ptr)
 {
@@ -3743,6 +3736,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct ifaddrmsg *ifm;
        struct nlattr *tb[IFA_MAX+1];
        struct in6_addr *pfx, *peer_pfx;
+       u32 ifa_flags;
        int err;
 
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
@@ -3754,7 +3748,13 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (pfx == NULL)
                return -EINVAL;
 
-       return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+       ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
+
+       /* We ignore other flags so far. */
+       ifa_flags &= IFA_F_MANAGETEMPADDR;
+
+       return inet6_addr_del(net, ifm->ifa_index, ifa_flags, pfx,
+                             ifm->ifa_prefixlen);
 }
 
 static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
index 7b326529e6a2cba57695697cfff436357c347b2c..3b0905b77127d9efb29e93f1fdcb432b5357fc97 100644 (file)
@@ -493,12 +493,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        if (IS_ERR(dst))
                goto out;
 
-       if (ipv6_addr_is_multicast(&fl6.daddr))
-               hlimit = np->mcast_hops;
-       else
-               hlimit = np->hop_limit;
-       if (hlimit < 0)
-               hlimit = ip6_dst_hoplimit(dst);
+       hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        msg.skb = skb;
        msg.offset = skb_network_offset(skb);
@@ -593,12 +588,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
        if (IS_ERR(dst))
                goto out;
 
-       if (ipv6_addr_is_multicast(&fl6.daddr))
-               hlimit = np->mcast_hops;
-       else
-               hlimit = np->hop_limit;
-       if (hlimit < 0)
-               hlimit = ip6_dst_hoplimit(dst);
+       hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        idev = __in6_dev_get(skb->dev);
 
index ee7a97f510cbd9f94fa24eafa43ddba201c75f3e..da26224a599323250303d0c07d42254b536b5d82 100644 (file)
@@ -75,25 +75,12 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
                        return err;
        }
 
-       if (uh->check == 0) {
-               /* RFC 2460 section 8.1 says that we SHOULD log
-                  this error. Well, it is reasonable.
-                */
-               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
-                              &ipv6_hdr(skb)->saddr, ntohs(uh->source),
-                              &ipv6_hdr(skb)->daddr, ntohs(uh->dest));
-               return 1;
-       }
-       if (skb->ip_summed == CHECKSUM_COMPLETE &&
-           !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
-                            skb->len, proto, skb->csum))
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       if (!skb_csum_unnecessary(skb))
-               skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                        &ipv6_hdr(skb)->daddr,
-                                                        skb->len, proto, 0));
-
-       return 0;
+       /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
+        * we accept a checksum of zero here. When we find the socket
+        * for the UDP packet we'll check if that socket allows zero checksum
+        * for IPv6 (set by socket option).
+        */
+       return skb_checksum_init_zero_check(skb, proto, uh->check,
+                                          ip6_compute_pseudo);
 }
 EXPORT_SYMBOL(udp6_csum_init);
index 34e0ded5c14b028ebbb1bb03c1b30e8f25f98811..87891f5f57b5786725321d2fc301941531064bf2 100644 (file)
@@ -1459,7 +1459,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
 
                                if (w->skip) {
                                        w->skip--;
-                                       continue;
+                                       goto skip;
                                }
 
                                err = w->func(w);
@@ -1469,6 +1469,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
                                w->count++;
                                continue;
                        }
+skip:
                        w->state = FWS_U;
                case FWS_U:
                        if (fn == w->root)
index 0961b5ef866d04803cf91243aec32bb9e2ea8cf7..4052694c6f2cb196b54ef7d5235d61d74e4ea69c 100644 (file)
@@ -26,7 +26,6 @@
 #include <net/sock.h>
 
 #include <net/ipv6.h>
-#include <net/addrconf.h>
 #include <net/rawv6.h>
 #include <net/transp_v6.h>
 
index 9d921462b57f293f9f49f6ec78936c84a3f756a0..75277b739b0424eab8ef83081b1e7756966f2877 100644 (file)
@@ -72,6 +72,7 @@ struct ip6gre_net {
 };
 
 static struct rtnl_link_ops ip6gre_link_ops __read_mostly;
+static struct rtnl_link_ops ip6gre_tap_ops __read_mostly;
 static int ip6gre_tunnel_init(struct net_device *dev);
 static void ip6gre_tunnel_setup(struct net_device *dev);
 static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t);
@@ -353,10 +354,10 @@ failed_free:
 
 static void ip6gre_tunnel_uninit(struct net_device *dev)
 {
-       struct net *net = dev_net(dev);
-       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
 
-       ip6gre_tunnel_unlink(ign, netdev_priv(dev));
+       ip6gre_tunnel_unlink(ign, t);
        dev_put(dev);
 }
 
@@ -611,8 +612,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
                         int encap_limit,
                         __u32 *pmtu)
 {
-       struct net *net = dev_net(dev);
        struct ip6_tnl *tunnel = netdev_priv(dev);
+       struct net *net = tunnel->net;
        struct net_device *tdev;    /* Device to other host */
        struct ipv6hdr  *ipv6h;     /* Our new IP header */
        unsigned int max_headroom = 0; /* The extra header space needed */
@@ -979,7 +980,7 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
                int strict = (ipv6_addr_type(&p->raddr) &
                              (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
 
-               struct rt6_info *rt = rt6_lookup(dev_net(dev),
+               struct rt6_info *rt = rt6_lookup(t->net,
                                                 &p->raddr, &p->laddr,
                                                 p->link, strict);
 
@@ -1063,13 +1064,12 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev,
        int err = 0;
        struct ip6_tnl_parm2 p;
        struct __ip6_tnl_parm p1;
-       struct ip6_tnl *t;
-       struct net *net = dev_net(dev);
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct net *net = t->net;
        struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
 
        switch (cmd) {
        case SIOCGETTUNNEL:
-               t = NULL;
                if (dev == ign->fb_tunnel_dev) {
                        if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
                                err = -EFAULT;
@@ -1077,9 +1077,9 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev,
                        }
                        ip6gre_tnl_parm_from_user(&p1, &p);
                        t = ip6gre_tunnel_locate(net, &p1, 0);
+                       if (t == NULL)
+                               t = netdev_priv(dev);
                }
-               if (t == NULL)
-                       t = netdev_priv(dev);
                memset(&p, 0, sizeof(p));
                ip6gre_tnl_parm_to_user(&p, &t->parms);
                if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
@@ -1242,7 +1242,6 @@ static void ip6gre_tunnel_setup(struct net_device *dev)
        dev->flags |= IFF_NOARP;
        dev->iflink = 0;
        dev->addr_len = sizeof(struct in6_addr);
-       dev->features |= NETIF_F_NETNS_LOCAL;
        dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
 }
 
@@ -1297,11 +1296,17 @@ static struct inet6_protocol ip6gre_protocol __read_mostly = {
        .flags       = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-static void ip6gre_destroy_tunnels(struct ip6gre_net *ign,
-       struct list_head *head)
+static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head)
 {
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+       struct net_device *dev, *aux;
        int prio;
 
+       for_each_netdev_safe(net, dev, aux)
+               if (dev->rtnl_link_ops == &ip6gre_link_ops ||
+                   dev->rtnl_link_ops == &ip6gre_tap_ops)
+                       unregister_netdevice_queue(dev, head);
+
        for (prio = 0; prio < 4; prio++) {
                int h;
                for (h = 0; h < HASH_SIZE; h++) {
@@ -1310,7 +1315,12 @@ static void ip6gre_destroy_tunnels(struct ip6gre_net *ign,
                        t = rtnl_dereference(ign->tunnels[prio][h]);
 
                        while (t != NULL) {
-                               unregister_netdevice_queue(t->dev, head);
+                               /* If dev is in the same netns, it has already
+                                * been added to the list by the previous loop.
+                                */
+                               if (!net_eq(dev_net(t->dev), net))
+                                       unregister_netdevice_queue(t->dev,
+                                                                  head);
                                t = rtnl_dereference(t->next);
                        }
                }
@@ -1329,6 +1339,11 @@ static int __net_init ip6gre_init_net(struct net *net)
                goto err_alloc_dev;
        }
        dev_net_set(ign->fb_tunnel_dev, net);
+       /* FB netdevice is special: we have one, and only one per netns.
+        * Allowing to move it to another netns is clearly unsafe.
+        */
+       ign->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
+
 
        ip6gre_fb_tunnel_init(ign->fb_tunnel_dev);
        ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops;
@@ -1349,12 +1364,10 @@ err_alloc_dev:
 
 static void __net_exit ip6gre_exit_net(struct net *net)
 {
-       struct ip6gre_net *ign;
        LIST_HEAD(list);
 
-       ign = net_generic(net, ip6gre_net_id);
        rtnl_lock();
-       ip6gre_destroy_tunnels(ign, &list);
+       ip6gre_destroy_tunnels(net, &list);
        unregister_netdevice_many(&list);
        rtnl_unlock();
 }
@@ -1531,15 +1544,14 @@ out:
 static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
                            struct nlattr *data[])
 {
-       struct ip6_tnl *t, *nt;
-       struct net *net = dev_net(dev);
+       struct ip6_tnl *t, *nt = netdev_priv(dev);
+       struct net *net = nt->net;
        struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
        struct __ip6_tnl_parm p;
 
        if (dev == ign->fb_tunnel_dev)
                return -EINVAL;
 
-       nt = netdev_priv(dev);
        ip6gre_netlink_parms(data, &p);
 
        t = ip6gre_tunnel_locate(net, &p, 0);
index 8659067da28e8a8557af6f4109fc52056ccdee1b..8250474ab7dc0e10b3340bca3e68aaf9377a81f2 100644 (file)
@@ -1633,7 +1633,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
 {
        struct mr6_table *mrt;
        struct flowi6 fl6 = {
-               .flowi6_iif     = skb->skb_iif,
+               .flowi6_iif     = skb->skb_iif ? : LOOPBACK_IFINDEX,
                .flowi6_oif     = skb->dev->ifindex,
                .flowi6_mark    = skb->mark,
        };
index e0983f3648a628410c6f6bfd9549ec339a325353..790e0c6b19e1caa41b31c5f279de719581bd6065 100644 (file)
@@ -33,6 +33,7 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,
        struct ipv6hdr *iph = ipv6_hdr(skb);
        bool ret = false;
        struct flowi6 fl6 = {
+               .flowi6_iif = LOOPBACK_IFINDEX,
                .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
                .flowi6_proto = iph->nexthdr,
                .daddr = iph->saddr,
index bda74291c3e0d09c94ff5961cf393cb7695ee518..a2a1d80dfe0c0e3cab9ed1eadd51bb3401797b11 100644 (file)
@@ -168,12 +168,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        pfh.wcheck = 0;
        pfh.family = AF_INET6;
 
-       if (ipv6_addr_is_multicast(&fl6.daddr))
-               hlimit = np->mcast_hops;
-       else
-               hlimit = np->hop_limit;
-       if (hlimit < 0)
-               hlimit = ip6_dst_hoplimit(dst);
+       hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        lock_sock(sk);
        err = ip6_append_data(sk, ping_getfrag, &pfh, len,
index 1f29996e368a23e67bfe09d9b2ff10bd9b61805d..dddfb5fa2b7a289f80fcf81d67ff332a678ed398 100644 (file)
@@ -873,14 +873,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                err = PTR_ERR(dst);
                goto out;
        }
-       if (hlimit < 0) {
-               if (ipv6_addr_is_multicast(&fl6.daddr))
-                       hlimit = np->mcast_hops;
-               else
-                       hlimit = np->hop_limit;
-               if (hlimit < 0)
-                       hlimit = ip6_dst_hoplimit(dst);
-       }
+       if (hlimit < 0)
+               hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        if (tclass < 0)
                tclass = np->tclass;
index 4011617cca688850c4d530f2e35d9890203dedaf..004fffb6c2218a12a9619eb08f359a8f2b391297 100644 (file)
@@ -1273,6 +1273,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
        struct flowi6 fl6;
 
        memset(&fl6, 0, sizeof(fl6));
+       fl6.flowi6_iif = LOOPBACK_IFINDEX;
        fl6.flowi6_oif = oif;
        fl6.flowi6_mark = mark;
        fl6.daddr = iph->daddr;
@@ -1294,6 +1295,7 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
        struct flowi6 fl6;
 
        memset(&fl6, 0, sizeof(fl6));
+       fl6.flowi6_iif = LOOPBACK_IFINDEX;
        fl6.flowi6_oif = oif;
        fl6.flowi6_mark = mark;
        fl6.daddr = msg->dest;
index e289830ed6e35a3be4feda700b5b6789dac20292..7fa67439f4d6a93a0191678671267e3b0d9a3768 100644 (file)
@@ -1294,25 +1294,6 @@ out:
        return NULL;
 }
 
-static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
-{
-       if (skb->ip_summed == CHECKSUM_COMPLETE) {
-               if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
-                                 &ipv6_hdr(skb)->daddr, skb->csum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       return 0;
-               }
-       }
-
-       skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
-                                             &ipv6_hdr(skb)->saddr,
-                                             &ipv6_hdr(skb)->daddr, 0));
-
-       if (skb->len <= 76)
-               return __skb_checksum_complete(skb);
-       return 0;
-}
-
 /* The socket must have it's spinlock held when we get
  * here.
  *
@@ -1486,7 +1467,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, th->doff*4))
                goto discard_it;
 
-       if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
+       if (skb_checksum_init(skb, IPPROTO_TCP, ip6_compute_pseudo))
                goto csum_error;
 
        th = tcp_hdr(skb);
index 1e586d92260e1e75957060b896a8748e9beaa61a..4fcd9bca950e5ceecff9ce2f0cbed8b1b6eb689a 100644 (file)
@@ -760,6 +760,17 @@ static void flush_stack(struct sock **stack, unsigned int count,
        if (unlikely(skb1))
                kfree_skb(skb1);
 }
+
+static void udp6_csum_zero_error(struct sk_buff *skb)
+{
+       /* RFC 2460 section 8.1 says that we SHOULD log
+        * this error. Well, it is reasonable.
+        */
+       LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
+                      &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
+                      &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
+}
+
 /*
  * Note: called only from the BH handler context,
  * so we don't need to lock the hashes.
@@ -779,7 +790,12 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
        dif = inet6_iif(skb);
        sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
        while (sk) {
-               stack[count++] = sk;
+               /* If zero checksum and sk_no_check is not on for
+                * the socket then skip it.
+                */
+               if (uh->check || sk->sk_no_check)
+                       stack[count++] = sk;
+
                sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr,
                                       uh->source, saddr, dif);
                if (unlikely(count == ARRAY_SIZE(stack))) {
@@ -867,6 +883,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        if (sk != NULL) {
                int ret;
 
+               if (!uh->check && !sk->sk_no_check) {
+                       udp6_csum_zero_error(skb);
+                       goto csum_error;
+               }
+
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
@@ -879,6 +900,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                return 0;
        }
 
+       if (!uh->check) {
+               udp6_csum_zero_error(skb);
+               goto csum_error;
+       }
+
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
                goto discard;
 
@@ -1006,7 +1032,10 @@ static int udp_v6_push_pending_frames(struct sock *sk)
 
        if (is_udplite)
                csum = udplite_csum_outgoing(sk, skb);
-       else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
+       else if (sk->sk_no_check == UDP_CSUM_NOXMIT) {   /* UDP csum disabled */
+               skb->ip_summed = CHECKSUM_NONE;
+               goto send;
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
                udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr,
                                     up->len);
                goto send;
@@ -1232,14 +1261,8 @@ do_udp_sendmsg:
                goto out;
        }
 
-       if (hlimit < 0) {
-               if (ipv6_addr_is_multicast(&fl6.daddr))
-                       hlimit = np->mcast_hops;
-               else
-                       hlimit = np->hop_limit;
-               if (hlimit < 0)
-                       hlimit = ip6_dst_hoplimit(dst);
-       }
+       if (hlimit < 0)
+               hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        if (tclass < 0)
                tclass = np->tclass;
index 19ef329bdbf8e7418fa1d352bb6c90218935831e..b930d080c66f231f338c7ea860c8c1d798d91fea 100644 (file)
@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
        if (err)
                return err;
 
-       memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-#ifdef CONFIG_NETFILTER
-       IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
-#endif
-
-       skb->protocol = htons(ETH_P_IPV6);
        skb->local_df = 1;
 
        return x->outer_mode->output2(x, skb);
@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
 
 int xfrm6_output_finish(struct sk_buff *skb)
 {
+       memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+       skb->protocol = htons(ETH_P_IPV6);
+
 #ifdef CONFIG_NETFILTER
        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
 #endif
 
-       skb->protocol = htons(ETH_P_IPV6);
        return xfrm_output(skb);
 }
 
@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb)
        struct xfrm_state *x = dst->xfrm;
        int mtu;
 
+#ifdef CONFIG_NETFILTER
+       if (!x) {
+               IP6CB(skb)->flags |= IP6SKB_REROUTED;
+               return dst_output(skb);
+       }
+#endif
+
        if (skb->protocol == htons(ETH_P_IPV6))
                mtu = ip6_skb_dst_mtu(skb);
        else
@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb)
 
 int xfrm6_output(struct sock *sk, struct sk_buff *skb)
 {
-       return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
-                      skb_dst(skb)->dev, __xfrm6_output);
+       return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
+                           NULL, skb_dst(skb)->dev, __xfrm6_output,
+                           !(IP6CB(skb)->flags & IP6SKB_REROUTED));
 }
index f3c83073afc49f7aad98262cc5776b3edddc7f87..b47f8e542aae969c29b797d8ac072788e38bd6a0 100644 (file)
@@ -1476,9 +1476,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, const struct sadb_msg
        else
                err = xfrm_state_update(x);
 
-       xfrm_audit_state_add(x, err ? 0 : 1,
-                            audit_get_loginuid(current),
-                            audit_get_sessionid(current), 0);
+       xfrm_audit_state_add(x, err ? 0 : 1, true);
 
        if (err < 0) {
                x->km.state = XFRM_STATE_DEAD;
@@ -1532,9 +1530,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, const struct sadb_
        c.event = XFRM_MSG_DELSA;
        km_state_notify(x, &c);
 out:
-       xfrm_audit_state_delete(x, err ? 0 : 1,
-                               audit_get_loginuid(current),
-                               audit_get_sessionid(current), 0);
+       xfrm_audit_state_delete(x, err ? 0 : 1, true);
        xfrm_state_put(x);
 
        return err;
@@ -1726,17 +1722,13 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_m
        struct net *net = sock_net(sk);
        unsigned int proto;
        struct km_event c;
-       struct xfrm_audit audit_info;
        int err, err2;
 
        proto = pfkey_satype2proto(hdr->sadb_msg_satype);
        if (proto == 0)
                return -EINVAL;
 
-       audit_info.loginuid = audit_get_loginuid(current);
-       audit_info.sessionid = audit_get_sessionid(current);
-       audit_info.secid = 0;
-       err = xfrm_state_flush(net, proto, &audit_info);
+       err = xfrm_state_flush(net, proto, true);
        err2 = unicast_flush_resp(sk, hdr);
        if (err || err2) {
                if (err == -ESRCH) /* empty table - go quietly */
@@ -2288,9 +2280,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_
        err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
                                 hdr->sadb_msg_type != SADB_X_SPDUPDATE);
 
-       xfrm_audit_policy_add(xp, err ? 0 : 1,
-                             audit_get_loginuid(current),
-                             audit_get_sessionid(current), 0);
+       xfrm_audit_policy_add(xp, err ? 0 : 1, true);
 
        if (err)
                goto out;
@@ -2372,9 +2362,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
        if (xp == NULL)
                return -ENOENT;
 
-       xfrm_audit_policy_delete(xp, err ? 0 : 1,
-                                audit_get_loginuid(current),
-                                audit_get_sessionid(current), 0);
+       xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
 
        if (err)
                goto out;
@@ -2622,9 +2610,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_
                return -ENOENT;
 
        if (delete) {
-               xfrm_audit_policy_delete(xp, err ? 0 : 1,
-                               audit_get_loginuid(current),
-                               audit_get_sessionid(current), 0);
+               xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
 
                if (err)
                        goto out;
@@ -2733,13 +2719,9 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, const struct sad
 {
        struct net *net = sock_net(sk);
        struct km_event c;
-       struct xfrm_audit audit_info;
        int err, err2;
 
-       audit_info.loginuid = audit_get_loginuid(current);
-       audit_info.sessionid = audit_get_sessionid(current);
-       audit_info.secid = 0;
-       err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
+       err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, true);
        err2 = unicast_flush_resp(sk, hdr);
        if (err || err2) {
                if (err == -ESRCH) /* empty table - old silent behavior */
index 7704ea9502fdc9e49a2b8bb7fda4b9b9ec8d1722..e472d44a3b91eb74e5614d22c4c7c68811ca4a84 100644 (file)
@@ -605,14 +605,8 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
                goto out;
        }
 
-       if (hlimit < 0) {
-               if (ipv6_addr_is_multicast(&fl6.daddr))
-                       hlimit = np->mcast_hops;
-               else
-                       hlimit = np->hop_limit;
-               if (hlimit < 0)
-                       hlimit = ip6_dst_hoplimit(dst);
-       }
+       if (hlimit < 0)
+               hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        if (tclass < 0)
                tclass = np->tclass;
index 7c7df475a401693dd44cb1a6b9d68dd255b2acd5..ec24378caaafaf333152e856aa0e2e920ddbb13f 100644 (file)
@@ -23,12 +23,13 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
                               u8 *data, size_t data_len, u8 *mic)
 {
        struct scatterlist assoc, pt, ct[2];
-       struct {
-               struct aead_request     req;
-               u8                      priv[crypto_aead_reqsize(tfm)];
-       } aead_req;
 
-       memset(&aead_req, 0, sizeof(aead_req));
+       char aead_req_data[sizeof(struct aead_request) +
+                          crypto_aead_reqsize(tfm)]
+               __aligned(__alignof__(struct aead_request));
+       struct aead_request *aead_req = (void *) aead_req_data;
+
+       memset(aead_req, 0, sizeof(aead_req_data));
 
        sg_init_one(&pt, data, data_len);
        sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
@@ -36,23 +37,23 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
        sg_set_buf(&ct[0], data, data_len);
        sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
 
-       aead_request_set_tfm(&aead_req.req, tfm);
-       aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
-       aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0);
+       aead_request_set_tfm(aead_req, tfm);
+       aead_request_set_assoc(aead_req, &assoc, assoc.length);
+       aead_request_set_crypt(aead_req, &pt, ct, data_len, b_0);
 
-       crypto_aead_encrypt(&aead_req.req);
+       crypto_aead_encrypt(aead_req);
 }
 
 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
                              u8 *data, size_t data_len, u8 *mic)
 {
        struct scatterlist assoc, pt, ct[2];
-       struct {
-               struct aead_request     req;
-               u8                      priv[crypto_aead_reqsize(tfm)];
-       } aead_req;
+       char aead_req_data[sizeof(struct aead_request) +
+                          crypto_aead_reqsize(tfm)]
+               __aligned(__alignof__(struct aead_request));
+       struct aead_request *aead_req = (void *) aead_req_data;
 
-       memset(&aead_req, 0, sizeof(aead_req));
+       memset(aead_req, 0, sizeof(aead_req_data));
 
        sg_init_one(&pt, data, data_len);
        sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
@@ -60,12 +61,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
        sg_set_buf(&ct[0], data, data_len);
        sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
 
-       aead_request_set_tfm(&aead_req.req, tfm);
-       aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
-       aead_request_set_crypt(&aead_req.req, ct, &pt,
+       aead_request_set_tfm(aead_req, tfm);
+       aead_request_set_assoc(aead_req, &assoc, assoc.length);
+       aead_request_set_crypt(aead_req, ct, &pt,
                               data_len + IEEE80211_CCMP_MIC_LEN, b_0);
 
-       return crypto_aead_decrypt(&aead_req.req);
+       return crypto_aead_decrypt(aead_req);
 }
 
 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[])
index aaa59d719592c0b7dc6ef3ddb4df8aaa578bc45c..7b8d3cf8957407f2decb1c87a3307e45055b9213 100644 (file)
@@ -109,6 +109,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 static int ieee80211_start_p2p_device(struct wiphy *wiphy,
                                      struct wireless_dev *wdev)
 {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+       int ret;
+
+       mutex_lock(&sdata->local->chanctx_mtx);
+       ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
+       mutex_unlock(&sdata->local->chanctx_mtx);
+       if (ret < 0)
+               return ret;
+
        return ieee80211_do_open(wdev, true);
 }
 
@@ -972,13 +981,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        sdata->needed_rx_chains = sdata->local->rx_chains;
 
        mutex_lock(&local->mtx);
-       sdata->radar_required = params->radar_required;
        err = ieee80211_vif_use_channel(sdata, &params->chandef,
                                        IEEE80211_CHANCTX_SHARED);
+       if (!err)
+               ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
        mutex_unlock(&local->mtx);
        if (err)
                return err;
-       ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
        /*
         * Apply control port protocol, this allows us to
@@ -1131,8 +1140,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
        skb_queue_purge(&sdata->u.ap.ps.bc_buf);
 
-       ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
        mutex_lock(&local->mtx);
+       ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
        ieee80211_vif_release_channel(sdata);
        mutex_unlock(&local->mtx);
 
@@ -1566,7 +1575,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 
                if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
                    sta->sdata->u.vlan.sta) {
-                       rcu_assign_pointer(sta->sdata->u.vlan.sta, NULL);
+                       RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
                        prev_4addr = true;
                }
 
@@ -2930,7 +2939,6 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
        /* whatever, but channel contexts should not complain about that one */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = local->rx_chains;
-       sdata->radar_required = true;
 
        err = ieee80211_vif_use_channel(sdata, chandef,
                                        IEEE80211_CHANCTX_SHARED);
@@ -3217,7 +3225,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *chanctx;
        int err, num_chanctx, changed = 0;
 
@@ -3233,23 +3241,24 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                                       &sdata->vif.bss_conf.chandef))
                return -EINVAL;
 
-       rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-       if (!chanctx_conf) {
-               rcu_read_unlock();
+       mutex_lock(&local->chanctx_mtx);
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+       if (!conf) {
+               mutex_unlock(&local->chanctx_mtx);
                return -EBUSY;
        }
 
        /* don't handle for multi-VIF cases */
-       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
-       if (chanctx->refcount > 1) {
-               rcu_read_unlock();
+       chanctx = container_of(conf, struct ieee80211_chanctx, conf);
+       if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+               mutex_unlock(&local->chanctx_mtx);
                return -EBUSY;
        }
        num_chanctx = 0;
        list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
                num_chanctx++;
-       rcu_read_unlock();
+       mutex_unlock(&local->chanctx_mtx);
 
        if (num_chanctx > 1)
                return -EBUSY;
@@ -3949,6 +3958,21 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy,
        return 0;
 }
 
+static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
+                                     struct net_device *dev,
+                                     struct cfg80211_chan_def *chandef)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int ret;
+       u32 changed = 0;
+
+       ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed);
+       if (ret == 0)
+               ieee80211_bss_info_change_notify(sdata, changed);
+
+       return ret;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -4029,4 +4053,5 @@ const struct cfg80211_ops mac80211_config_ops = {
        .start_radar_detection = ieee80211_start_radar_detection,
        .channel_switch = ieee80211_channel_switch,
        .set_qos_map = ieee80211_set_qos_map,
+       .set_ap_chanwidth = ieee80211_set_ap_chanwidth,
 };
index 75b5dd2c9267f10e8cb0e5680c3aa11c94a5dbe4..48e6d6f010cd0f26acd379fea0c601bf8d67e33f 100644 (file)
@@ -9,6 +9,170 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+                                         struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_sub_if_data *sdata;
+       int num = 0;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+               num++;
+
+       return num;
+}
+
+static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
+                                         struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_sub_if_data *sdata;
+       int num = 0;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+               num++;
+
+       return num;
+}
+
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+                              struct ieee80211_chanctx *ctx)
+{
+       return ieee80211_chanctx_num_assigned(local, ctx) +
+              ieee80211_chanctx_num_reserved(local, ctx);
+}
+
+static int ieee80211_num_chanctx(struct ieee80211_local *local)
+{
+       struct ieee80211_chanctx *ctx;
+       int num = 0;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(ctx, &local->chanctx_list, list)
+               num++;
+
+       return num;
+}
+
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+{
+       lockdep_assert_held(&local->chanctx_mtx);
+       return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
+                                  struct ieee80211_chanctx *ctx,
+                                  const struct cfg80211_chan_def *compat)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(sdata, &ctx->reserved_vifs,
+                           reserved_chanctx_list) {
+               if (!compat)
+                       compat = &sdata->reserved_chandef;
+
+               compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
+                                                    compat);
+               if (!compat)
+                       break;
+       }
+
+       return compat;
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
+                                      struct ieee80211_chanctx *ctx,
+                                      const struct cfg80211_chan_def *compat)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(sdata, &ctx->assigned_vifs,
+                           assigned_chanctx_list) {
+               if (sdata->reserved_chanctx != NULL)
+                       continue;
+
+               if (!compat)
+                       compat = &sdata->vif.bss_conf.chandef;
+
+               compat = cfg80211_chandef_compatible(
+                               &sdata->vif.bss_conf.chandef, compat);
+               if (!compat)
+                       break;
+       }
+
+       return compat;
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
+                                  struct ieee80211_chanctx *ctx,
+                                  const struct cfg80211_chan_def *compat)
+{
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
+       if (!compat)
+               return NULL;
+
+       compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
+       if (!compat)
+               return NULL;
+
+       return compat;
+}
+
+static bool
+ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx,
+                                     const struct cfg80211_chan_def *def)
+{
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       if (ieee80211_chanctx_combined_chandef(local, ctx, def))
+               return true;
+
+       if (!list_empty(&ctx->reserved_vifs) &&
+           ieee80211_chanctx_reserved_chandef(local, ctx, def))
+               return true;
+
+       return false;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
+                                  const struct cfg80211_chan_def *chandef,
+                                  enum ieee80211_chanctx_mode mode)
+{
+       struct ieee80211_chanctx *ctx;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
+               return NULL;
+
+       list_for_each_entry(ctx, &local->chanctx_list, list) {
+               if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+                       continue;
+
+               if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
+                                                          chandef))
+                       continue;
+
+               return ctx;
+       }
+
+       return NULL;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
        switch (sta->bandwidth) {
@@ -190,6 +354,11 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
                if (!compat)
                        continue;
 
+               compat = ieee80211_chanctx_reserved_chandef(local, ctx,
+                                                           compat);
+               if (!compat)
+                       continue;
+
                ieee80211_change_chanctx(local, ctx, compat);
 
                return ctx;
@@ -217,62 +386,91 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
 }
 
 static struct ieee80211_chanctx *
-ieee80211_new_chanctx(struct ieee80211_local *local,
-                     const struct cfg80211_chan_def *chandef,
-                     enum ieee80211_chanctx_mode mode)
+ieee80211_alloc_chanctx(struct ieee80211_local *local,
+                       const struct cfg80211_chan_def *chandef,
+                       enum ieee80211_chanctx_mode mode)
 {
        struct ieee80211_chanctx *ctx;
-       u32 changed;
-       int err;
 
        lockdep_assert_held(&local->chanctx_mtx);
 
        ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
        if (!ctx)
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
+       INIT_LIST_HEAD(&ctx->assigned_vifs);
+       INIT_LIST_HEAD(&ctx->reserved_vifs);
        ctx->conf.def = *chandef;
        ctx->conf.rx_chains_static = 1;
        ctx->conf.rx_chains_dynamic = 1;
        ctx->mode = mode;
        ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
        ieee80211_recalc_chanctx_min_def(local, ctx);
+
+       return ctx;
+}
+
+static int ieee80211_add_chanctx(struct ieee80211_local *local,
+                                struct ieee80211_chanctx *ctx)
+{
+       u32 changed;
+       int err;
+
+       lockdep_assert_held(&local->mtx);
+       lockdep_assert_held(&local->chanctx_mtx);
+
        if (!local->use_chanctx)
                local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-       /* we hold the mutex to prevent idle from changing */
-       lockdep_assert_held(&local->mtx);
        /* turn idle off *before* setting channel -- some drivers need that */
        changed = ieee80211_idle_off(local);
        if (changed)
                ieee80211_hw_config(local, changed);
 
        if (!local->use_chanctx) {
-               local->_oper_chandef = *chandef;
+               local->_oper_chandef = ctx->conf.def;
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
        } else {
                err = drv_add_chanctx(local, ctx);
                if (err) {
-                       kfree(ctx);
                        ieee80211_recalc_idle(local);
-                       return ERR_PTR(err);
+                       return err;
                }
        }
 
-       /* and keep the mutex held until the new chanctx is on the list */
-       list_add_rcu(&ctx->list, &local->chanctx_list);
+       return 0;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+                     const struct cfg80211_chan_def *chandef,
+                     enum ieee80211_chanctx_mode mode)
+{
+       struct ieee80211_chanctx *ctx;
+       int err;
+
+       lockdep_assert_held(&local->mtx);
+       lockdep_assert_held(&local->chanctx_mtx);
 
+       ctx = ieee80211_alloc_chanctx(local, chandef, mode);
+       if (!ctx)
+               return ERR_PTR(-ENOMEM);
+
+       err = ieee80211_add_chanctx(local, ctx);
+       if (err) {
+               kfree(ctx);
+               return ERR_PTR(err);
+       }
+
+       list_add_rcu(&ctx->list, &local->chanctx_list);
        return ctx;
 }
 
-static void ieee80211_free_chanctx(struct ieee80211_local *local,
-                                  struct ieee80211_chanctx *ctx)
+static void ieee80211_del_chanctx(struct ieee80211_local *local,
+                                 struct ieee80211_chanctx *ctx)
 {
-       bool check_single_channel = false;
        lockdep_assert_held(&local->chanctx_mtx);
 
-       WARN_ON_ONCE(ctx->refcount != 0);
-
        if (!local->use_chanctx) {
                struct cfg80211_chan_def *chandef = &local->_oper_chandef;
                chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -282,8 +480,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
                /* NOTE: Disabling radar is only valid here for
                 * single channel context. To be sure, check it ...
                 */
-               if (local->hw.conf.radar_enabled)
-                       check_single_channel = true;
+               WARN_ON(local->hw.conf.radar_enabled &&
+                       !list_empty(&local->chanctx_list));
+
                local->hw.conf.radar_enabled = false;
 
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
@@ -291,39 +490,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
                drv_remove_chanctx(local, ctx);
        }
 
-       list_del_rcu(&ctx->list);
-       kfree_rcu(ctx, rcu_head);
-
-       /* throw a warning if this wasn't the only channel context. */
-       WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
-
        ieee80211_recalc_idle(local);
 }
 
-static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
-                                       struct ieee80211_chanctx *ctx)
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+                                  struct ieee80211_chanctx *ctx)
 {
-       struct ieee80211_local *local = sdata->local;
-       int ret;
-
        lockdep_assert_held(&local->chanctx_mtx);
 
-       ret = drv_assign_vif_chanctx(local, sdata, ctx);
-       if (ret)
-               return ret;
-
-       rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
-       ctx->refcount++;
-
-       ieee80211_recalc_txpower(sdata);
-       ieee80211_recalc_chanctx_min_def(local, ctx);
-       sdata->vif.bss_conf.idle = false;
+       WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
 
-       if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
-           sdata->vif.type != NL80211_IFTYPE_MONITOR)
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
-
-       return 0;
+       list_del_rcu(&ctx->list);
+       ieee80211_del_chanctx(local, ctx);
+       kfree_rcu(ctx, rcu_head);
 }
 
 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
@@ -384,30 +563,58 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
        drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
 }
 
-static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
-                                          struct ieee80211_chanctx *ctx)
+static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
+                                       struct ieee80211_chanctx *new_ctx)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *conf;
+       struct ieee80211_chanctx *curr_ctx = NULL;
+       int ret = 0;
 
-       lockdep_assert_held(&local->chanctx_mtx);
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
 
-       ctx->refcount--;
-       rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
+       if (conf) {
+               curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       sdata->vif.bss_conf.idle = true;
+               drv_unassign_vif_chanctx(local, sdata, curr_ctx);
+               conf = NULL;
+               list_del(&sdata->assigned_chanctx_list);
+       }
 
-       if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
-           sdata->vif.type != NL80211_IFTYPE_MONITOR)
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
+       if (new_ctx) {
+               ret = drv_assign_vif_chanctx(local, sdata, new_ctx);
+               if (ret)
+                       goto out;
 
-       drv_unassign_vif_chanctx(local, sdata, ctx);
+               conf = &new_ctx->conf;
+               list_add(&sdata->assigned_chanctx_list,
+                        &new_ctx->assigned_vifs);
+       }
 
-       if (ctx->refcount > 0) {
-               ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
-               ieee80211_recalc_smps_chanctx(local, ctx);
-               ieee80211_recalc_radar_chanctx(local, ctx);
-               ieee80211_recalc_chanctx_min_def(local, ctx);
+out:
+       rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
+
+       sdata->vif.bss_conf.idle = !conf;
+
+       if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
+               ieee80211_recalc_chanctx_chantype(local, curr_ctx);
+               ieee80211_recalc_smps_chanctx(local, curr_ctx);
+               ieee80211_recalc_radar_chanctx(local, curr_ctx);
+               ieee80211_recalc_chanctx_min_def(local, curr_ctx);
        }
+
+       if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
+               ieee80211_recalc_txpower(sdata);
+               ieee80211_recalc_chanctx_min_def(local, new_ctx);
+       }
+
+       if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
+           sdata->vif.type != NL80211_IFTYPE_MONITOR)
+               ieee80211_bss_info_change_notify(sdata,
+                                                BSS_CHANGED_IDLE);
+
+       return ret;
 }
 
 static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
@@ -425,8 +632,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 
        ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       ieee80211_unassign_vif_chanctx(sdata, ctx);
-       if (ctx->refcount == 0)
+       if (sdata->reserved_chanctx)
+               ieee80211_vif_unreserve_chanctx(sdata);
+
+       ieee80211_assign_vif_chanctx(sdata, NULL);
+       if (ieee80211_chanctx_refcount(local, ctx) == 0)
                ieee80211_free_chanctx(local, ctx);
 }
 
@@ -526,6 +736,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx *ctx;
+       u8 radar_detect_width = 0;
        int ret;
 
        lockdep_assert_held(&local->mtx);
@@ -533,6 +744,22 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 
        mutex_lock(&local->chanctx_mtx);
+
+       ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
+                                           chandef,
+                                           sdata->wdev.iftype);
+       if (ret < 0)
+               goto out;
+       if (ret > 0)
+               radar_detect_width = BIT(chandef->width);
+
+       sdata->radar_required = ret;
+
+       ret = ieee80211_check_combinations(sdata, chandef, mode,
+                                          radar_detect_width);
+       if (ret < 0)
+               goto out;
+
        __ieee80211_vif_release_channel(sdata);
 
        ctx = ieee80211_find_chanctx(local, chandef, mode);
@@ -548,7 +775,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        ret = ieee80211_assign_vif_chanctx(sdata, ctx);
        if (ret) {
                /* if assign fails refcount stays the same */
-               if (ctx->refcount == 0)
+               if (ieee80211_chanctx_refcount(local, ctx) == 0)
                        ieee80211_free_chanctx(local, ctx);
                goto out;
        }
@@ -560,15 +787,47 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        return ret;
 }
 
+static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
+                                         struct ieee80211_chanctx *ctx,
+                                         u32 *changed)
+{
+       struct ieee80211_local *local = sdata->local;
+       const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
+       u32 chanctx_changed = 0;
+
+       if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
+                                    IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
+
+       if (ieee80211_chanctx_refcount(local, ctx) != 1)
+               return -EINVAL;
+
+       if (sdata->vif.bss_conf.chandef.width != chandef->width) {
+               chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
+               *changed |= BSS_CHANGED_BANDWIDTH;
+       }
+
+       sdata->vif.bss_conf.chandef = *chandef;
+       ctx->conf.def = *chandef;
+
+       chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
+       drv_change_chanctx(local, ctx, chanctx_changed);
+
+       ieee80211_recalc_chanctx_chantype(local, ctx);
+       ieee80211_recalc_smps_chanctx(local, ctx);
+       ieee80211_recalc_radar_chanctx(local, ctx);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
+
+       return 0;
+}
+
 int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
                                 u32 *changed)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *ctx;
-       const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
        int ret;
-       u32 chanctx_changed = 0;
 
        lockdep_assert_held(&local->mtx);
 
@@ -576,11 +835,94 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON(!sdata->vif.csa_active))
                return -EINVAL;
 
-       if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-                                    IEEE80211_CHAN_DISABLED))
+       mutex_lock(&local->chanctx_mtx);
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+       if (!conf) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+       ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
+ out:
+       mutex_unlock(&local->chanctx_mtx);
+       return ret;
+}
+
+static void
+__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
+                                     bool clear)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_sub_if_data *vlan;
+       struct ieee80211_chanctx_conf *conf;
+
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
+               return;
+
+       lockdep_assert_held(&local->mtx);
+
+       /* Check that conf exists, even when clearing this function
+        * must be called with the AP's channel context still there
+        * as it would otherwise cause VLANs to have an invalid
+        * channel context pointer for a while, possibly pointing
+        * to a channel context that has already been freed.
+        */
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                               lockdep_is_held(&local->chanctx_mtx));
+       WARN_ON(!conf);
+
+       if (clear)
+               conf = NULL;
+
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+               rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
+}
+
+void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
+                                        bool clear)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       mutex_lock(&local->chanctx_mtx);
+
+       __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear);
+
+       mutex_unlock(&local->chanctx_mtx);
+}
+
+int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
+
+       lockdep_assert_held(&sdata->local->chanctx_mtx);
+
+       if (WARN_ON(!ctx))
                return -EINVAL;
 
+       list_del(&sdata->reserved_chanctx_list);
+       sdata->reserved_chanctx = NULL;
+
+       if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
+               ieee80211_free_chanctx(sdata->local, ctx);
+
+       return 0;
+}
+
+int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
+                                 const struct cfg80211_chan_def *chandef,
+                                 enum ieee80211_chanctx_mode mode,
+                                 bool radar_required)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *conf;
+       struct ieee80211_chanctx *new_ctx, *curr_ctx;
+       int ret = 0;
+
        mutex_lock(&local->chanctx_mtx);
+
        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
                                         lockdep_is_held(&local->chanctx_mtx));
        if (!conf) {
@@ -588,30 +930,108 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
                goto out;
        }
 
-       ctx = container_of(conf, struct ieee80211_chanctx, conf);
-       if (ctx->refcount != 1) {
+       curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+       new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
+       if (!new_ctx) {
+               if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
+                   (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
+                       /* if we're the only users of the chanctx and
+                        * the driver supports changing a running
+                        * context, reserve our current context
+                        */
+                       new_ctx = curr_ctx;
+               } else if (ieee80211_can_create_new_chanctx(local)) {
+                       /* create a new context and reserve it */
+                       new_ctx = ieee80211_new_chanctx(local, chandef, mode);
+                       if (IS_ERR(new_ctx)) {
+                               ret = PTR_ERR(new_ctx);
+                               goto out;
+                       }
+               } else {
+                       ret = -EBUSY;
+                       goto out;
+               }
+       }
+
+       list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
+       sdata->reserved_chanctx = new_ctx;
+       sdata->reserved_chandef = *chandef;
+       sdata->reserved_radar_required = radar_required;
+out:
+       mutex_unlock(&local->chanctx_mtx);
+       return ret;
+}
+
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
+                                      u32 *changed)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx *ctx;
+       struct ieee80211_chanctx *old_ctx;
+       struct ieee80211_chanctx_conf *conf;
+       int ret;
+       u32 tmp_changed = *changed;
+
+       /* TODO: need to recheck if the chandef is usable etc.? */
+
+       lockdep_assert_held(&local->mtx);
+
+       mutex_lock(&local->chanctx_mtx);
+
+       ctx = sdata->reserved_chanctx;
+       if (WARN_ON(!ctx)) {
                ret = -EINVAL;
                goto out;
        }
 
-       if (sdata->vif.bss_conf.chandef.width != chandef->width) {
-               chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
-               *changed |= BSS_CHANGED_BANDWIDTH;
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+       if (!conf) {
+               ret = -EINVAL;
+               goto out;
        }
 
-       sdata->vif.bss_conf.chandef = *chandef;
-       ctx->conf.def = *chandef;
+       old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
-       drv_change_chanctx(local, ctx, chanctx_changed);
+       if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
+               tmp_changed |= BSS_CHANGED_BANDWIDTH;
+
+       sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+
+       /* unref our reservation */
+       sdata->reserved_chanctx = NULL;
+       sdata->radar_required = sdata->reserved_radar_required;
+       list_del(&sdata->reserved_chanctx_list);
+
+       if (old_ctx == ctx) {
+               /* This is our own context, just change it */
+               ret = __ieee80211_vif_change_channel(sdata, old_ctx,
+                                                    &tmp_changed);
+               if (ret)
+                       goto out;
+       } else {
+               ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+               if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
+                       ieee80211_free_chanctx(local, old_ctx);
+               if (ret) {
+                       /* if assign fails refcount stays the same */
+                       if (ieee80211_chanctx_refcount(local, ctx) == 0)
+                               ieee80211_free_chanctx(local, ctx);
+                       goto out;
+               }
+
+               if (sdata->vif.type == NL80211_IFTYPE_AP)
+                       __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+       }
+
+       *changed = tmp_changed;
 
        ieee80211_recalc_chanctx_chantype(local, ctx);
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
        ieee80211_recalc_chanctx_min_def(local, ctx);
-
-       ret = 0;
- out:
+out:
        mutex_unlock(&local->chanctx_mtx);
        return ret;
 }
@@ -695,40 +1115,6 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&local->chanctx_mtx);
 }
 
-void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
-                                        bool clear)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_sub_if_data *vlan;
-       struct ieee80211_chanctx_conf *conf;
-
-       ASSERT_RTNL();
-
-       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
-               return;
-
-       mutex_lock(&local->chanctx_mtx);
-
-       /*
-        * Check that conf exists, even when clearing this function
-        * must be called with the AP's channel context still there
-        * as it would otherwise cause VLANs to have an invalid
-        * channel context pointer for a while, possibly pointing
-        * to a channel context that has already been freed.
-        */
-       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-                               lockdep_is_held(&local->chanctx_mtx));
-       WARN_ON(!conf);
-
-       if (clear)
-               conf = NULL;
-
-       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
-               rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
-
-       mutex_unlock(&local->chanctx_mtx);
-}
-
 void ieee80211_iter_chan_contexts_atomic(
        struct ieee80211_hw *hw,
        void (*iter)(struct ieee80211_hw *hw,
index fa16e54980a1d3e76ce2f85fcb3253eb2599e838..0e963bc1ceac3109f378431a617b853a7166df37 100644 (file)
@@ -128,7 +128,7 @@ static ssize_t sta_tx_latency_stat_write(struct file *file,
        if (!strcmp(buf, TX_LATENCY_DISABLED)) {
                if (!tx_latency)
                        goto unlock;
-               rcu_assign_pointer(local->tx_latency, NULL);
+               RCU_INIT_POINTER(local->tx_latency, NULL);
                synchronize_rcu();
                kfree(tx_latency);
                goto unlock;
index 214ed4ecd739f10ae201e6dfa9112c0dd943f5b8..60c35afee29d551727a2969b25b84998ca5501c4 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __MAC80211_DEBUGFS_H
 #define __MAC80211_DEBUGFS_H
 
+#include "ieee80211_i.h"
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 void debugfs_hw_add(struct ieee80211_local *local);
 int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count,
index 79025e79f4d6459dd99de5ad496e351e123f53b7..9f5501a9a79506266decdb83d0ad78c9d6e9bdf9 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef __IEEE80211_DEBUGFS_NETDEV_H
 #define __IEEE80211_DEBUGFS_NETDEV_H
 
+#include "ieee80211_i.h"
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
index fc689f5d971e259381f0a26e13079f1a727fe704..5331582a2c817184db6f72ee9e2aa6f6841a10f0 100644 (file)
@@ -726,13 +726,19 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
 }
 
 static inline void drv_flush(struct ieee80211_local *local,
+                            struct ieee80211_sub_if_data *sdata,
                             u32 queues, bool drop)
 {
+       struct ieee80211_vif *vif = sdata ? &sdata->vif : NULL;
+
        might_sleep();
 
+       if (sdata)
+               check_sdata_in_driver(sdata);
+
        trace_drv_flush(local, queues, drop);
        if (local->ops->flush)
-               local->ops->flush(&local->hw, queues, drop);
+               local->ops->flush(&local->hw, vif, queues, drop);
        trace_drv_return_void(local);
 }
 
index c150b68436d78ada5bfbb0825d128d8e89f916e3..15702ff64a4c89fb89541f620b9da7dcccc2a7bd 100644 (file)
@@ -31,6 +31,18 @@ static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa,
        }
 }
 
+static void __check_htcap_enable(struct ieee80211_ht_cap *ht_capa,
+                                 struct ieee80211_ht_cap *ht_capa_mask,
+                                 struct ieee80211_sta_ht_cap *ht_cap,
+                                 u16 flag)
+{
+       __le16 le_flag = cpu_to_le16(flag);
+
+       if ((ht_capa_mask->cap_info & le_flag) &&
+           (ht_capa->cap_info & le_flag))
+               ht_cap->cap |= flag;
+}
+
 void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_sta_ht_cap *ht_cap)
 {
@@ -59,7 +71,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
        smask = (u8 *)(&ht_capa_mask->mcs.rx_mask);
 
        /* NOTE:  If you add more over-rides here, update register_hw
-        * ht_capa_mod_msk logic in main.c as well.
+        * ht_capa_mod_mask logic in main.c as well.
         * And, if this method can ever change ht_cap.ht_supported, fix
         * the check in ieee80211_add_ht_ie.
         */
@@ -86,6 +98,14 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
        __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
                              IEEE80211_HT_CAP_MAX_AMSDU);
 
+       /* Allow user to disable LDPC */
+       __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
+                             IEEE80211_HT_CAP_LDPC_CODING);
+
+       /* Allow user to enable 40 MHz intolerant bit. */
+       __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap,
+                            IEEE80211_HT_CAP_40MHZ_INTOLERANT);
+
        /* Allow user to decrease AMPDU factor */
        if (ht_capa_mask->ampdu_params_info &
            IEEE80211_HT_AMPDU_PARM_FACTOR) {
index 06d28787945b513e6672457a1e6990da0fd644d8..ff4d4155a84d26f982d820858dddf206a49dbba7 100644 (file)
@@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        struct beacon_data *presp;
        enum nl80211_bss_scan_width scan_width;
        bool have_higher_than_11mbit;
-       bool radar_required = false;
+       bool radar_required;
        int err;
 
        sdata_assert_lock(sdata);
@@ -253,7 +253,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        presp = rcu_dereference_protected(ifibss->presp,
                                          lockdep_is_held(&sdata->wdev.mtx));
-       rcu_assign_pointer(ifibss->presp, NULL);
+       RCU_INIT_POINTER(ifibss->presp, NULL);
        if (presp)
                kfree_rcu(presp, rcu_head);
 
@@ -262,7 +262,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        /* make a copy of the chandef, it could be modified below. */
        chandef = *req_chandef;
        chan = chandef.chan;
-       if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+       if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
+                                    NL80211_IFTYPE_ADHOC)) {
                if (chandef.width == NL80211_CHAN_WIDTH_5 ||
                    chandef.width == NL80211_CHAN_WIDTH_10 ||
                    chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
@@ -274,7 +275,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                chandef.width = NL80211_CHAN_WIDTH_20;
                chandef.center_freq1 = chan->center_freq;
                /* check again for downgraded chandef */
-               if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+               if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
+                                            NL80211_IFTYPE_ADHOC)) {
                        sdata_info(sdata,
                                   "Failed to join IBSS, beacons forbidden\n");
                        return;
@@ -282,21 +284,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        }
 
        err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-                                           &chandef);
+                                           &chandef, NL80211_IFTYPE_ADHOC);
        if (err < 0) {
                sdata_info(sdata,
                           "Failed to join IBSS, invalid chandef\n");
                return;
        }
-       if (err > 0) {
-               if (!ifibss->userspace_handles_dfs) {
-                       sdata_info(sdata,
-                                  "Failed to join IBSS, DFS channel without control program\n");
-                       return;
-               }
-               radar_required = true;
+       if (err > 0 && !ifibss->userspace_handles_dfs) {
+               sdata_info(sdata,
+                          "Failed to join IBSS, DFS channel without control program\n");
+               return;
        }
 
+       radar_required = err;
+
        mutex_lock(&local->mtx);
        if (ieee80211_vif_use_channel(sdata, &chandef,
                                      ifibss->fixed_channel ?
@@ -775,7 +776,8 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
         * unavailable.
         */
        err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-                                           &ifibss->chandef);
+                                           &ifibss->chandef,
+                                           NL80211_IFTYPE_ADHOC);
        if (err > 0)
                cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
                                     GFP_ATOMIC);
@@ -861,7 +863,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                goto disconnect;
        }
 
-       if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) {
+       if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
+                                    NL80211_IFTYPE_ADHOC)) {
                sdata_info(sdata,
                           "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
                           ifibss->bssid,
@@ -873,17 +876,17 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
 
        err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-                                           &params.chandef);
+                                           &params.chandef,
+                                           NL80211_IFTYPE_ADHOC);
        if (err < 0)
                goto disconnect;
-       if (err) {
+       if (err > 0 && !ifibss->userspace_handles_dfs) {
                /* IBSS-DFS only allowed with a control program */
-               if (!ifibss->userspace_handles_dfs)
-                       goto disconnect;
-
-               params.radar_required = true;
+               goto disconnect;
        }
 
+       params.radar_required = err;
+
        if (cfg80211_chandef_identical(&params.chandef,
                                       &sdata->vif.bss_conf.chandef)) {
                ibss_dbg(sdata,
@@ -1636,7 +1639,33 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        u32 changed = 0;
        u32 rate_flags;
        struct ieee80211_supported_band *sband;
+       enum ieee80211_chanctx_mode chanmode;
+       struct ieee80211_local *local = sdata->local;
+       int radar_detect_width = 0;
        int i;
+       int ret;
+
+       ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
+                                           &params->chandef,
+                                           sdata->wdev.iftype);
+       if (ret < 0)
+               return ret;
+
+       if (ret > 0) {
+               if (!params->userspace_handles_dfs)
+                       return -EINVAL;
+               radar_detect_width = BIT(params->chandef.width);
+       }
+
+       chanmode = (params->channel_fixed && !ret) ?
+               IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
+
+       mutex_lock(&local->chanctx_mtx);
+       ret = ieee80211_check_combinations(sdata, &params->chandef, chanmode,
+                                          radar_detect_width);
+       mutex_unlock(&local->chanctx_mtx);
+       if (ret < 0)
+               return ret;
 
        if (params->bssid) {
                memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
@@ -1651,7 +1680,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 
        /* fix basic_rates if channel does not support these rates */
        rate_flags = ieee80211_chandef_rate_flags(&params->chandef);
-       sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band];
+       sband = local->hw.wiphy->bands[params->chandef.chan->band];
        for (i = 0; i < sband->n_bitrates; i++) {
                if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
                        sdata->u.ibss.basic_rates &= ~BIT(i);
@@ -1700,9 +1729,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        ieee80211_bss_info_change_notify(sdata, changed);
 
        sdata->smps_mode = IEEE80211_SMPS_OFF;
-       sdata->needed_rx_chains = sdata->local->rx_chains;
+       sdata->needed_rx_chains = local->rx_chains;
 
-       ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+       ieee80211_queue_work(&local->hw, &sdata->work);
 
        return 0;
 }
index 222c28b75315f1ab43226e08566a5f911c6bacc7..b455f62d357ad6675bad1eda38c9019b6a7539c9 100644 (file)
@@ -260,7 +260,7 @@ struct ieee80211_if_ap {
 
        /* to be used after channel switch. */
        struct cfg80211_beacon_data *next_beacon;
-       struct list_head vlans;
+       struct list_head vlans; /* write-protected with RTNL and local->mtx */
 
        struct ps_data ps;
        atomic_t num_mcast_sta; /* number of stations receiving multicast */
@@ -276,7 +276,7 @@ struct ieee80211_if_wds {
 };
 
 struct ieee80211_if_vlan {
-       struct list_head list;
+       struct list_head list; /* write-protected with RTNL and local->mtx */
 
        /* used for all tx if the VLAN is configured to 4-addr mode */
        struct sta_info __rcu *sta;
@@ -691,8 +691,10 @@ struct ieee80211_chanctx {
        struct list_head list;
        struct rcu_head rcu_head;
 
+       struct list_head assigned_vifs;
+       struct list_head reserved_vifs;
+
        enum ieee80211_chanctx_mode mode;
-       int refcount;
        bool driver_present;
 
        struct ieee80211_chanctx_conf conf;
@@ -756,6 +758,14 @@ struct ieee80211_sub_if_data {
        bool csa_radar_required;
        struct cfg80211_chan_def csa_chandef;
 
+       struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
+       struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
+
+       /* context reservation -- protected with chanctx_mtx */
+       struct ieee80211_chanctx *reserved_chanctx;
+       struct cfg80211_chan_def reserved_chandef;
+       bool reserved_radar_required;
+
        /* used to reconfigure hardware SM PS */
        struct work_struct recalc_smps;
 
@@ -1770,6 +1780,16 @@ int __must_check
 ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
                          const struct cfg80211_chan_def *chandef,
                          enum ieee80211_chanctx_mode mode);
+int __must_check
+ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
+                             const struct cfg80211_chan_def *chandef,
+                             enum ieee80211_chanctx_mode mode,
+                             bool radar_required);
+int __must_check
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
+                                  u32 *changed);
+int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
+
 int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
                               const struct cfg80211_chan_def *chandef,
@@ -1782,6 +1802,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
                                         bool clear);
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+                              struct ieee80211_chanctx *ctx);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
@@ -1805,6 +1827,11 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
                          enum nl80211_iftype iftype);
 void ieee80211_recalc_dtim(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata);
+int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
+                                const struct cfg80211_chan_def *chandef,
+                                enum ieee80211_chanctx_mode chanmode,
+                                u8 radar_detect);
+int ieee80211_max_num_channels(struct ieee80211_local *local);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index b8d331e7d883d50fd4fc3adf12c2869ac3beedb7..7fff3dcaac43fb93034519a3f1b8b1aaae0579bc 100644 (file)
@@ -250,6 +250,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sub_if_data *nsdata;
+       int ret;
 
        ASSERT_RTNL();
 
@@ -300,7 +301,10 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       return 0;
+       mutex_lock(&local->chanctx_mtx);
+       ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
+       mutex_unlock(&local->chanctx_mtx);
+       return ret;
 }
 
 static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
@@ -423,7 +427,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        mutex_unlock(&local->mtx);
        if (ret) {
                mutex_lock(&local->iflist_mtx);
-               rcu_assign_pointer(local->monitor_sdata, NULL);
+               RCU_INIT_POINTER(local->monitor_sdata, NULL);
                mutex_unlock(&local->iflist_mtx);
                synchronize_net();
                drv_remove_interface(local, sdata);
@@ -452,7 +456,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
                return;
        }
 
-       rcu_assign_pointer(local->monitor_sdata, NULL);
+       RCU_INIT_POINTER(local->monitor_sdata, NULL);
        mutex_unlock(&local->iflist_mtx);
 
        synchronize_net();
@@ -492,7 +496,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                if (!sdata->bss)
                        return -ENOLINK;
 
+               mutex_lock(&local->mtx);
                list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+               mutex_unlock(&local->mtx);
 
                master = container_of(sdata->bss,
                                      struct ieee80211_sub_if_data, u.ap);
@@ -722,8 +728,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                drv_stop(local);
  err_del_bss:
        sdata->bss = NULL;
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+               mutex_lock(&local->mtx);
                list_del(&sdata->u.vlan.list);
+               mutex_unlock(&local->mtx);
+       }
        /* might already be clear but that doesn't matter */
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
        return res;
@@ -875,8 +884,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
+               mutex_lock(&local->mtx);
                list_del(&sdata->u.vlan.list);
-               rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
+               mutex_unlock(&local->mtx);
+               RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
                /* no need to tell driver */
                break;
        case NL80211_IFTYPE_MONITOR:
@@ -895,7 +906,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                break;
        case NL80211_IFTYPE_P2P_DEVICE:
                /* relies on synchronize_rcu() below */
-               rcu_assign_pointer(local->p2p_sdata, NULL);
+               RCU_INIT_POINTER(local->p2p_sdata, NULL);
                /* fall through */
        default:
                cancel_work_sync(&sdata->work);
@@ -1280,6 +1291,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        INIT_WORK(&sdata->work, ieee80211_iface_work);
        INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
        INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
+       INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
+       INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 
        switch (type) {
        case NL80211_IFTYPE_P2P_GO:
@@ -1774,20 +1787,19 @@ static int netdev_notify(struct notifier_block *nb,
        struct ieee80211_sub_if_data *sdata;
 
        if (state != NETDEV_CHANGENAME)
-               return 0;
+               return NOTIFY_DONE;
 
        if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
-               return 0;
+               return NOTIFY_DONE;
 
        if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
-               return 0;
+               return NOTIFY_DONE;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
        memcpy(sdata->name, dev->name, IFNAMSIZ);
-
        ieee80211_debugfs_rename_netdev(sdata);
-       return 0;
+
+       return NOTIFY_OK;
 }
 
 static struct notifier_block mac80211_netdev_notifier = {
index 4c1bf61bc778683dc352ebb32a585d45649168a6..27b9364cdf177d8f28e410bf50eff708bc40e424 100644 (file)
@@ -340,7 +340,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
 
        sdata_unlock(sdata);
 
-       return NOTIFY_DONE;
+       return NOTIFY_OK;
 }
 #endif
 
@@ -371,7 +371,7 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb,
 
        drv_ipv6_addr_change(local, sdata, idev);
 
-       return NOTIFY_DONE;
+       return NOTIFY_OK;
 }
 #endif
 
@@ -446,7 +446,9 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
        .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
                                IEEE80211_HT_CAP_MAX_AMSDU |
                                IEEE80211_HT_CAP_SGI_20 |
-                               IEEE80211_HT_CAP_SGI_40),
+                               IEEE80211_HT_CAP_SGI_40 |
+                               IEEE80211_HT_CAP_LDPC_CODING |
+                               IEEE80211_HT_CAP_40MHZ_INTOLERANT),
        .mcs = {
                .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
                             0xff, 0xff, 0xff, 0xff, 0xff, },
index f70e9cd10552dac6729d703edd2e9ae12750a3a6..b06ddc9519ce07a4464a6a8460108031abc2c4a9 100644 (file)
@@ -366,20 +366,15 @@ int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
                return 0;
 
        /* find RSN IE */
-       data = ifmsh->ie;
-       while (data < ifmsh->ie + ifmsh->ie_len) {
-               if (*data == WLAN_EID_RSN) {
-                       len = data[1] + 2;
-                       break;
-               }
-               data++;
-       }
+       data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len);
+       if (!data)
+               return 0;
 
-       if (len) {
-               if (skb_tailroom(skb) < len)
-                       return -ENOMEM;
-               memcpy(skb_put(skb, len), data, len);
-       }
+       len = data[1] + 2;
+
+       if (skb_tailroom(skb) < len)
+               return -ENOMEM;
+       memcpy(skb_put(skb, len), data, len);
 
        return 0;
 }
@@ -829,7 +824,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
        bcn = rcu_dereference_protected(ifmsh->beacon,
                                        lockdep_is_held(&sdata->wdev.mtx));
-       rcu_assign_pointer(ifmsh->beacon, NULL);
+       RCU_INIT_POINTER(ifmsh->beacon, NULL);
        kfree_rcu(bcn, rcu_head);
 
        /* flush STAs and mpaths on this iface */
@@ -903,14 +898,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
        }
 
        err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-                                           &params.chandef);
+                                           &params.chandef,
+                                           NL80211_IFTYPE_MESH_POINT);
        if (err < 0)
                return false;
-       if (err) {
-               params.radar_required = true;
+       if (err > 0)
                /* TODO: DFS not (yet) supported */
                return false;
-       }
+
+       params.radar_required = err;
 
        if (cfg80211_chandef_identical(&params.chandef,
                                       &sdata->vif.bss_conf.chandef)) {
@@ -1068,7 +1064,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
 
        /* Remove the CSA and MCSP elements from the beacon */
        tmp_csa_settings = rcu_dereference(ifmsh->csa);
-       rcu_assign_pointer(ifmsh->csa, NULL);
+       RCU_INIT_POINTER(ifmsh->csa, NULL);
        if (tmp_csa_settings)
                kfree_rcu(tmp_csa_settings, rcu_head);
        ret = ieee80211_mesh_rebuild_beacon(sdata);
@@ -1102,7 +1098,7 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
        ret = ieee80211_mesh_rebuild_beacon(sdata);
        if (ret) {
                tmp_csa_settings = rcu_dereference(ifmsh->csa);
-               rcu_assign_pointer(ifmsh->csa, NULL);
+               RCU_INIT_POINTER(ifmsh->csa, NULL);
                kfree_rcu(tmp_csa_settings, rcu_head);
                return ret;
        }
index f9514685d45a54802cb0f21dce0953ccbe9b78f4..94758b9c9ed48a5d1ea9921f4f9f0da40e34bd0b 100644 (file)
@@ -37,7 +37,7 @@ static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae)
        return get_unaligned_le32(preq_elem + offset);
 }
 
-static inline u32 u16_field_get(const u8 *preq_elem, int offset, bool ae)
+static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae)
 {
        if (ae)
                offset += 6;
@@ -544,9 +544,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                if (time_after(jiffies, ifmsh->last_sn_update +
                                        net_traversal_jiffies(sdata)) ||
                    time_before(jiffies, ifmsh->last_sn_update)) {
-                       target_sn = ++ifmsh->sn;
+                       ++ifmsh->sn;
                        ifmsh->last_sn_update = jiffies;
                }
+               target_sn = ifmsh->sn;
        } else if (is_broadcast_ether_addr(target_addr) &&
                   (target_flags & IEEE80211_PREQ_TO_FLAG)) {
                rcu_read_lock();
index 3b848dad958762ccfc48732623d9ddf1f56aa8ae..0e4886f881f1e49f438fa0f61d5c2b021877bf30 100644 (file)
@@ -11,6 +11,7 @@
 #define MICHAEL_H
 
 #include <linux/types.h>
+#include <linux/ieee80211.h>
 
 #define MICHAEL_MIC_LEN 8
 
index dee50aefd6e868e247ba869e9e9883d4640330e3..488826f188a7a8a7f903fea8d9249ac9819b6c7c 100644 (file)
@@ -1089,7 +1089,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
        chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
                               struct ieee80211_chanctx, conf);
-       if (chanctx->refcount > 1) {
+       if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
                sdata_info(sdata,
                           "channel switch with multiple interfaces on the same channel, disconnecting\n");
                ieee80211_queue_work(&local->hw,
@@ -3701,7 +3701,7 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
        ieee80211_recalc_ps(local, latency_usec);
        mutex_unlock(&local->iflist_mtx);
 
-       return 0;
+       return NOTIFY_OK;
 }
 
 static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
index 216c45b949e513382447050eb560098a5edaa4b3..0e5b67015650b489b6741924698d72aff52f75f5 100644 (file)
@@ -54,24 +54,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
        return skb;
 }
 
-static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)
+static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len)
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_hdr *hdr;
-
-       hdr = (void *)(skb->data);
+       struct ieee80211_hdr *hdr = (void *)skb->data;
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
                            RX_FLAG_FAILED_PLCP_CRC |
                            RX_FLAG_AMPDU_IS_ZEROLEN))
-               return 1;
+               return true;
+
        if (unlikely(skb->len < 16 + present_fcs_len))
-               return 1;
+               return true;
+
        if (ieee80211_is_ctl(hdr->frame_control) &&
            !ieee80211_is_pspoll(hdr->frame_control) &&
            !ieee80211_is_back_req(hdr->frame_control))
-               return 1;
-       return 0;
+               return true;
+
+       return false;
 }
 
 static int
@@ -3190,7 +3191,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
 }
 
 /*
- * This is the actual Rx frames handler. as it blongs to Rx path it must
+ * This is the actual Rx frames handler. as it belongs to Rx path it must
  * be called with rcu_read_lock protection.
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
index 3ce7f2c8539a1f626f7488833ee966fb3af5d502..28185c8dc19a302b31af1e0efe11dbaea8000b2f 100644 (file)
@@ -309,7 +309,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        if (local->scan_req != local->int_scan_req)
                cfg80211_scan_done(local->scan_req, aborted);
        local->scan_req = NULL;
-       rcu_assign_pointer(local->scan_sdata, NULL);
+       RCU_INIT_POINTER(local->scan_sdata, NULL);
 
        local->scanning = 0;
        local->scan_chandef.chan = NULL;
@@ -559,7 +559,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                ieee80211_recalc_idle(local);
 
                local->scan_req = NULL;
-               rcu_assign_pointer(local->scan_sdata, NULL);
+               RCU_INIT_POINTER(local->scan_sdata, NULL);
        }
 
        return rc;
@@ -773,7 +773,7 @@ void ieee80211_scan_work(struct work_struct *work)
                int rc;
 
                local->scan_req = NULL;
-               rcu_assign_pointer(local->scan_sdata, NULL);
+               RCU_INIT_POINTER(local->scan_sdata, NULL);
 
                rc = __ieee80211_start_scan(sdata, req);
                if (rc) {
@@ -1014,7 +1014,7 @@ out_free:
 
        if (ret) {
                /* Clean in case of failure after HW restart or upon resume. */
-               rcu_assign_pointer(local->sched_scan_sdata, NULL);
+               RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
                local->sched_scan_req = NULL;
        }
 
@@ -1089,7 +1089,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
                return;
        }
 
-       rcu_assign_pointer(local->sched_scan_sdata, NULL);
+       RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
 
        /* If sched scan was aborted by the driver. */
        local->sched_scan_req = NULL;
index 137a192e64bc3c2aa61cc9c5912a89bd3008cbe3..c34a5f97abc74ff8791b20676130dd1ce5d55c0c 100644 (file)
@@ -552,7 +552,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
 {
        struct ieee80211_local *local = sta->local;
-       int err = 0;
+       int err;
 
        might_sleep();
 
@@ -570,7 +570,6 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
 
        return 0;
  out_free:
-       BUG_ON(!err);
        sta_info_free(local, sta);
        return err;
 }
index 275c94f995f7c8401749cbbafb249bb52a418be7..ad058759e85e1124073029c7ccd7e516707513d0 100644 (file)
@@ -554,7 +554,7 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
        ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_FLUSH);
 
-       drv_flush(local, queues, false);
+       drv_flush(local, sdata, queues, false);
 
        ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_FLUSH);
@@ -1546,7 +1546,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                WARN_ON(local->resuming);
                res = drv_add_interface(local, sdata);
                if (WARN_ON(res)) {
-                       rcu_assign_pointer(local->monitor_sdata, NULL);
+                       RCU_INIT_POINTER(local->monitor_sdata, NULL);
                        synchronize_net();
                        kfree(sdata);
                }
@@ -1565,17 +1565,17 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                list_for_each_entry(ctx, &local->chanctx_list, list)
                        WARN_ON(drv_add_chanctx(local, ctx));
                mutex_unlock(&local->chanctx_mtx);
-       }
 
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
-                       continue;
-               ieee80211_assign_chanctx(local, sdata);
-       }
+               list_for_each_entry(sdata, &local->interfaces, list) {
+                       if (!ieee80211_sdata_running(sdata))
+                               continue;
+                       ieee80211_assign_chanctx(local, sdata);
+               }
 
-       sdata = rtnl_dereference(local->monitor_sdata);
-       if (sdata && ieee80211_sdata_running(sdata))
-               ieee80211_assign_chanctx(local, sdata);
+               sdata = rtnl_dereference(local->monitor_sdata);
+               if (sdata && ieee80211_sdata_running(sdata))
+                       ieee80211_assign_chanctx(local, sdata);
+       }
 
        /* add STAs back */
        mutex_lock(&local->sta_mtx);
@@ -1671,13 +1671,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        }
                        break;
                case NL80211_IFTYPE_WDS:
-                       break;
                case NL80211_IFTYPE_AP_VLAN:
                case NL80211_IFTYPE_MONITOR:
-                       /* ignore virtual */
-                       break;
                case NL80211_IFTYPE_P2P_DEVICE:
-                       changed = BSS_CHANGED_IDLE;
+                       /* nothing to do */
                        break;
                case NL80211_IFTYPE_UNSPECIFIED:
                case NUM_NL80211_IFTYPES:
@@ -2797,3 +2794,121 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 
        ps->dtim_count = dtim_count;
 }
+
+int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
+                                const struct cfg80211_chan_def *chandef,
+                                enum ieee80211_chanctx_mode chanmode,
+                                u8 radar_detect)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_sub_if_data *sdata_iter;
+       enum nl80211_iftype iftype = sdata->wdev.iftype;
+       int num[NUM_NL80211_IFTYPES];
+       struct ieee80211_chanctx *ctx;
+       int num_different_channels = 0;
+       int total = 1;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       if (WARN_ON(hweight32(radar_detect) > 1))
+               return -EINVAL;
+
+       if (WARN_ON(chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
+                   !chandef->chan))
+               return -EINVAL;
+
+       if (chandef)
+               num_different_channels = 1;
+
+       if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
+               return -EINVAL;
+
+       /* Always allow software iftypes */
+       if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
+               if (radar_detect)
+                       return -EINVAL;
+               return 0;
+       }
+
+       memset(num, 0, sizeof(num));
+
+       if (iftype != NL80211_IFTYPE_UNSPECIFIED)
+               num[iftype] = 1;
+
+       list_for_each_entry(ctx, &local->chanctx_list, list) {
+               if (ctx->conf.radar_enabled)
+                       radar_detect |= BIT(ctx->conf.def.width);
+               if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
+                       num_different_channels++;
+                       continue;
+               }
+               if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
+                   cfg80211_chandef_compatible(chandef,
+                                               &ctx->conf.def))
+                       continue;
+               num_different_channels++;
+       }
+
+       list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
+               struct wireless_dev *wdev_iter;
+
+               wdev_iter = &sdata_iter->wdev;
+
+               if (sdata_iter == sdata ||
+                   rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
+                   local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
+                       continue;
+
+               num[wdev_iter->iftype]++;
+               total++;
+       }
+
+       if (total == 1 && !radar_detect)
+               return 0;
+
+       return cfg80211_check_combinations(local->hw.wiphy,
+                                          num_different_channels,
+                                          radar_detect, num);
+}
+
+static void
+ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
+                        void *data)
+{
+       u32 *max_num_different_channels = data;
+
+       *max_num_different_channels = max(*max_num_different_channels,
+                                         c->num_different_channels);
+}
+
+int ieee80211_max_num_channels(struct ieee80211_local *local)
+{
+       struct ieee80211_sub_if_data *sdata;
+       int num[NUM_NL80211_IFTYPES] = {};
+       struct ieee80211_chanctx *ctx;
+       int num_different_channels = 0;
+       u8 radar_detect = 0;
+       u32 max_num_different_channels = 1;
+       int err;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(ctx, &local->chanctx_list, list) {
+               num_different_channels++;
+
+               if (ctx->conf.radar_enabled)
+                       radar_detect |= BIT(ctx->conf.def.width);
+       }
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list)
+               num[sdata->wdev.iftype]++;
+
+       err = cfg80211_iter_combinations(local->hw.wiphy,
+                                        num_different_channels, radar_detect,
+                                        num, ieee80211_iter_max_chans,
+                                        &max_num_different_channels);
+       if (err < 0)
+               return err;
+
+       return max_num_different_channels;
+}
index b8600e3c29c828d918b3676397f73a4d0fe7892c..9b3dcc201145dd3942bf30771e1638ea973759f7 100644 (file)
@@ -406,7 +406,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        if (info->control.hw_key &&
            !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
-           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
+           !((info->control.hw_key->flags &
+              IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) &&
+             ieee80211_is_mgmt(hdr->frame_control))) {
                /*
                 * hwaccel has no need for preallocated room for CCMP
                 * header or MIC fields
index e8138da4c14f70f40449c72ec4dc4d31f2960b8e..81df6ce23cbc37090d4341340f784839bab5cd5f 100644 (file)
@@ -368,14 +368,13 @@ done:
 static void nfnetlink_rcv(struct sk_buff *skb)
 {
        struct nlmsghdr *nlh = nlmsg_hdr(skb);
-       struct net *net = sock_net(skb->sk);
        int msglen;
 
        if (nlh->nlmsg_len < NLMSG_HDRLEN ||
            skb->len < nlh->nlmsg_len)
                return;
 
-       if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
+       if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
                netlink_ack(skb, nlh, -EPERM);
                return;
        }
@@ -400,19 +399,17 @@ static void nfnetlink_rcv(struct sk_buff *skb)
 }
 
 #ifdef CONFIG_MODULES
-static void nfnetlink_bind(int group)
+static int nfnetlink_bind(int group)
 {
        const struct nfnetlink_subsystem *ss;
        int type = nfnl_group2type[group];
 
        rcu_read_lock();
        ss = nfnetlink_get_subsys(type);
-       if (!ss) {
-               rcu_read_unlock();
-               request_module("nfnetlink-subsys-%d", type);
-               return;
-       }
        rcu_read_unlock();
+       if (!ss)
+               request_module("nfnetlink-subsys-%d", type);
+       return 0;
 }
 #endif
 
index 894cda0206bb9b8a32488ec81959482a7cc582d5..e0ccd84d4d6781ab761349e0ac913f6ddc3e8994 100644 (file)
@@ -1206,7 +1206,8 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
        struct module *module = NULL;
        struct mutex *cb_mutex;
        struct netlink_sock *nlk;
-       void (*bind)(int group);
+       int (*bind)(int group);
+       void (*unbind)(int group);
        int err = 0;
 
        sock->state = SS_UNCONNECTED;
@@ -1232,6 +1233,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
                err = -EPROTONOSUPPORT;
        cb_mutex = nl_table[protocol].cb_mutex;
        bind = nl_table[protocol].bind;
+       unbind = nl_table[protocol].unbind;
        netlink_unlock_table();
 
        if (err < 0)
@@ -1248,6 +1250,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
        nlk = nlk_sk(sock->sk);
        nlk->module = module;
        nlk->netlink_bind = bind;
+       nlk->netlink_unbind = unbind;
 out:
        return err;
 
@@ -1301,6 +1304,7 @@ static int netlink_release(struct socket *sock)
                        kfree_rcu(old, rcu);
                        nl_table[sk->sk_protocol].module = NULL;
                        nl_table[sk->sk_protocol].bind = NULL;
+                       nl_table[sk->sk_protocol].unbind = NULL;
                        nl_table[sk->sk_protocol].flags = 0;
                        nl_table[sk->sk_protocol].registered = 0;
                }
@@ -1360,7 +1364,72 @@ retry:
        return err;
 }
 
-static inline int netlink_capable(const struct socket *sock, unsigned int flag)
+/**
+ * __netlink_ns_capable - General netlink message capability test
+ * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace.
+ * @user_ns: The user namespace of the capability to use
+ * @cap: The capability to use
+ *
+ * Test to see if the opener of the socket we received the message
+ * from had when the netlink socket was created and the sender of the
+ * message has has the capability @cap in the user namespace @user_ns.
+ */
+bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
+                       struct user_namespace *user_ns, int cap)
+{
+       return sk_ns_capable(nsp->sk, user_ns, cap);
+}
+EXPORT_SYMBOL(__netlink_ns_capable);
+
+/**
+ * netlink_ns_capable - General netlink message capability test
+ * @skb: socket buffer holding a netlink command from userspace
+ * @user_ns: The user namespace of the capability to use
+ * @cap: The capability to use
+ *
+ * Test to see if the opener of the socket we received the message
+ * from had when the netlink socket was created and the sender of the
+ * message has has the capability @cap in the user namespace @user_ns.
+ */
+bool netlink_ns_capable(const struct sk_buff *skb,
+                       struct user_namespace *user_ns, int cap)
+{
+       return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap);
+}
+EXPORT_SYMBOL(netlink_ns_capable);
+
+/**
+ * netlink_capable - Netlink global message capability test
+ * @skb: socket buffer holding a netlink command from userspace
+ * @cap: The capability to use
+ *
+ * Test to see if the opener of the socket we received the message
+ * from had when the netlink socket was created and the sender of the
+ * message has has the capability @cap in all user namespaces.
+ */
+bool netlink_capable(const struct sk_buff *skb, int cap)
+{
+       return netlink_ns_capable(skb, &init_user_ns, cap);
+}
+EXPORT_SYMBOL(netlink_capable);
+
+/**
+ * netlink_net_capable - Netlink network namespace message capability test
+ * @skb: socket buffer holding a netlink command from userspace
+ * @cap: The capability to use
+ *
+ * Test to see if the opener of the socket we received the message
+ * from had when the netlink socket was created and the sender of the
+ * message has has the capability @cap over the network namespace of
+ * the socket we received the message from.
+ */
+bool netlink_net_capable(const struct sk_buff *skb, int cap)
+{
+       return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap);
+}
+EXPORT_SYMBOL(netlink_net_capable);
+
+static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
 {
        return (nl_table[sock->sk->sk_protocol].flags & flag) ||
                ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN);
@@ -1411,6 +1480,19 @@ static int netlink_realloc_groups(struct sock *sk)
        return err;
 }
 
+static void netlink_unbind(int group, long unsigned int groups,
+                          struct netlink_sock *nlk)
+{
+       int undo;
+
+       if (!nlk->netlink_unbind)
+               return;
+
+       for (undo = 0; undo < group; undo++)
+               if (test_bit(group, &groups))
+                       nlk->netlink_unbind(undo);
+}
+
 static int netlink_bind(struct socket *sock, struct sockaddr *addr,
                        int addr_len)
 {
@@ -1419,6 +1501,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
        struct netlink_sock *nlk = nlk_sk(sk);
        struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
        int err;
+       long unsigned int groups = nladdr->nl_groups;
 
        if (addr_len < sizeof(struct sockaddr_nl))
                return -EINVAL;
@@ -1427,45 +1510,53 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
                return -EINVAL;
 
        /* Only superuser is allowed to listen multicasts */
-       if (nladdr->nl_groups) {
-               if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV))
+       if (groups) {
+               if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
                        return -EPERM;
                err = netlink_realloc_groups(sk);
                if (err)
                        return err;
        }
 
-       if (nlk->portid) {
+       if (nlk->portid)
                if (nladdr->nl_pid != nlk->portid)
                        return -EINVAL;
-       } else {
+
+       if (nlk->netlink_bind && groups) {
+               int group;
+
+               for (group = 0; group < nlk->ngroups; group++) {
+                       if (!test_bit(group, &groups))
+                               continue;
+                       err = nlk->netlink_bind(group);
+                       if (!err)
+                               continue;
+                       netlink_unbind(group, groups, nlk);
+                       return err;
+               }
+       }
+
+       if (!nlk->portid) {
                err = nladdr->nl_pid ?
                        netlink_insert(sk, net, nladdr->nl_pid) :
                        netlink_autobind(sock);
-               if (err)
+               if (err) {
+                       netlink_unbind(nlk->ngroups - 1, groups, nlk);
                        return err;
+               }
        }
 
-       if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
+       if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
                return 0;
 
        netlink_table_grab();
        netlink_update_subscriptions(sk, nlk->subscriptions +
-                                        hweight32(nladdr->nl_groups) -
+                                        hweight32(groups) -
                                         hweight32(nlk->groups[0]));
-       nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups;
+       nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups;
        netlink_update_listeners(sk);
        netlink_table_ungrab();
 
-       if (nlk->netlink_bind && nlk->groups[0]) {
-               int i;
-
-               for (i = 0; i < nlk->ngroups; i++) {
-                       if (test_bit(i, nlk->groups))
-                               nlk->netlink_bind(i);
-               }
-       }
-
        return 0;
 }
 
@@ -1490,7 +1581,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
                return -EINVAL;
 
        if ((nladdr->nl_groups || nladdr->nl_pid) &&
-           !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
+           !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
                return -EPERM;
 
        if (!nlk->portid)
@@ -2096,20 +2187,24 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                break;
        case NETLINK_ADD_MEMBERSHIP:
        case NETLINK_DROP_MEMBERSHIP: {
-               if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV))
+               if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
                        return -EPERM;
                err = netlink_realloc_groups(sk);
                if (err)
                        return err;
                if (!val || val - 1 >= nlk->ngroups)
                        return -EINVAL;
+               if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) {
+                       err = nlk->netlink_bind(val);
+                       if (err)
+                               return err;
+               }
                netlink_table_grab();
                netlink_update_socket_mc(nlk, val,
                                         optname == NETLINK_ADD_MEMBERSHIP);
                netlink_table_ungrab();
-
-               if (nlk->netlink_bind)
-                       nlk->netlink_bind(val);
+               if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind)
+                       nlk->netlink_unbind(val);
 
                err = 0;
                break;
@@ -2247,7 +2342,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
                dst_group = ffs(addr->nl_groups);
                err =  -EPERM;
                if ((dst_group || dst_portid) &&
-                   !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
+                   !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
                        goto out;
        } else {
                dst_portid = nlk->dst_portid;
index ed13a790b00e1684215e04c6a68f71f9491cb3c9..0b59d441f5b6bcff8d03b08211e5a901c170dfe8 100644 (file)
@@ -38,7 +38,8 @@ struct netlink_sock {
        struct mutex            *cb_mutex;
        struct mutex            cb_def_mutex;
        void                    (*netlink_rcv)(struct sk_buff *skb);
-       void                    (*netlink_bind)(int group);
+       int                     (*netlink_bind)(int group);
+       void                    (*netlink_unbind)(int group);
        struct module           *module;
 #ifdef CONFIG_NETLINK_MMAP
        struct mutex            pg_vec_lock;
@@ -74,7 +75,8 @@ struct netlink_table {
        unsigned int            groups;
        struct mutex            *cb_mutex;
        struct module           *module;
-       void                    (*bind)(int group);
+       int                     (*bind)(int group);
+       void                    (*unbind)(int group);
        bool                    (*compare)(struct net *net, struct sock *sock);
        int                     registered;
 };
index b1dcdb932a86ee919642f47f58dd3b716995ad76..a3ba3ca0ff9281dec15c0b4d42002394583c1d8d 100644 (file)
@@ -561,7 +561,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
                return -EOPNOTSUPP;
 
        if ((ops->flags & GENL_ADMIN_PERM) &&
-           !capable(CAP_NET_ADMIN))
+           !netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
index e797a50ac2beec3a019bacf15e2e7c593355a46f..21cceb3bdf7871b2664643172eb4510d814d725b 100644 (file)
@@ -180,7 +180,8 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
                             OVS_CB(skb)->tun_key->ipv4_tos,
                             OVS_CB(skb)->tun_key->ipv4_ttl, df,
                             src_port, dst_port,
-                            htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8));
+                            htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8),
+                            false);
        if (err < 0)
                ip_rt_put(rt);
 error:
index 533ce4ff108ad94ff0a1e5205bc17f9c91c0b3ce..92f2c7107eec4f307cc50cdfedfb4ea2db0e59de 100644 (file)
@@ -128,6 +128,7 @@ static int pdiag_put_fanout(struct packet_sock *po, struct sk_buff *nlskb)
 
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
                        struct packet_diag_req *req,
+                       bool may_report_filterinfo,
                        struct user_namespace *user_ns,
                        u32 portid, u32 seq, u32 flags, int sk_ino)
 {
@@ -172,7 +173,8 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
                goto out_nlmsg_trim;
 
        if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
-           sock_diag_put_filterinfo(user_ns, sk, skb, PACKET_DIAG_FILTER))
+           sock_diag_put_filterinfo(may_report_filterinfo, sk, skb,
+                                    PACKET_DIAG_FILTER))
                goto out_nlmsg_trim;
 
        return nlmsg_end(skb, nlh);
@@ -188,9 +190,11 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
        struct packet_diag_req *req;
        struct net *net;
        struct sock *sk;
+       bool may_report_filterinfo;
 
        net = sock_net(skb->sk);
        req = nlmsg_data(cb->nlh);
+       may_report_filterinfo = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
 
        mutex_lock(&net->packet.sklist_lock);
        sk_for_each(sk, &net->packet.sklist) {
@@ -200,6 +204,7 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        goto next;
 
                if (sk_diag_fill(sk, skb, req,
+                                may_report_filterinfo,
                                 sk_user_ns(NETLINK_CB(cb->skb).sk),
                                 NETLINK_CB(cb->skb).portid,
                                 cb->nlh->nlmsg_seq, NLM_F_MULTI,
index dc15f430080831e74fade00799a661ab10cc6f84..b64151ade6b33a9cbacb0980d3ddbe03d8f7b4c8 100644 (file)
@@ -70,10 +70,10 @@ static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
        int err;
        u8 pnaddr;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!netlink_capable(skb, CAP_SYS_ADMIN))
                return -EPERM;
 
        ASSERT_RTNL();
@@ -233,10 +233,10 @@ static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
        int err;
        u8 dst;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!netlink_capable(skb, CAP_SYS_ADMIN))
                return -EPERM;
 
        ASSERT_RTNL();
index 8a5ba5add4bcd60e59a9b2468df88812212012f4..648778aef1a254b9739443e93012798a134d0d86 100644 (file)
@@ -948,7 +948,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n)
        u32 portid = skb ? NETLINK_CB(skb).portid : 0;
        int ret = 0, ovr = 0;
 
-       if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN))
+       if ((n->nlmsg_type != RTM_GETACTION) && !netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
index 29a30a14c31596cc51028be8db46eb4df9756f6e..45527e6b52dbf396cbb7415bb0613152a8320096 100644 (file)
@@ -134,7 +134,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
        int err;
        int tp_created = 0;
 
-       if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN))
+       if ((n->nlmsg_type != RTM_GETTFILTER) &&
+           !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
 replay:
@@ -317,7 +318,8 @@ replay:
                }
        }
 
-       err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh);
+       err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
+                             n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE);
        if (err == 0) {
                if (tp_created) {
                        spin_lock_bh(root_lock);
@@ -504,7 +506,7 @@ void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
 EXPORT_SYMBOL(tcf_exts_destroy);
 
 int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
-                 struct nlattr *rate_tlv, struct tcf_exts *exts)
+                 struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr)
 {
 #ifdef CONFIG_NET_CLS_ACT
        {
@@ -513,7 +515,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
                INIT_LIST_HEAD(&exts->actions);
                if (exts->police && tb[exts->police]) {
                        act = tcf_action_init_1(net, tb[exts->police], rate_tlv,
-                                               "police", TCA_ACT_NOREPLACE,
+                                               "police", ovr,
                                                TCA_ACT_BIND);
                        if (IS_ERR(act))
                                return PTR_ERR(act);
@@ -523,7 +525,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
                } else if (exts->action && tb[exts->action]) {
                        int err;
                        err = tcf_action_init(net, tb[exts->action], rate_tlv,
-                                             NULL, TCA_ACT_NOREPLACE,
+                                             NULL, ovr,
                                              TCA_ACT_BIND, &exts->actions);
                        if (err)
                                return err;
@@ -543,14 +545,12 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
                     struct tcf_exts *src)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       if (!list_empty(&src->actions)) {
-               LIST_HEAD(tmp);
-               tcf_tree_lock(tp);
-               list_splice_init(&dst->actions, &tmp);
-               list_splice(&src->actions, &dst->actions);
-               tcf_tree_unlock(tp);
-               tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
-       }
+       LIST_HEAD(tmp);
+       tcf_tree_lock(tp);
+       list_splice_init(&dst->actions, &tmp);
+       list_splice(&src->actions, &dst->actions);
+       tcf_tree_unlock(tp);
+       tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
 #endif
 }
 EXPORT_SYMBOL(tcf_exts_change);
index e98ca99c202bb5af6db77260f0996e6cacb098cf..0ae1813e3e90d55a1bf5993364502cebd58c1b22 100644 (file)
@@ -130,14 +130,14 @@ static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = {
 static int basic_set_parms(struct net *net, struct tcf_proto *tp,
                           struct basic_filter *f, unsigned long base,
                           struct nlattr **tb,
-                          struct nlattr *est)
+                          struct nlattr *est, bool ovr)
 {
        int err;
        struct tcf_exts e;
        struct tcf_ematch_tree t;
 
        tcf_exts_init(&e, TCA_BASIC_ACT, TCA_BASIC_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e);
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
        if (err < 0)
                return err;
 
@@ -161,7 +161,7 @@ errout:
 
 static int basic_change(struct net *net, struct sk_buff *in_skb,
                        struct tcf_proto *tp, unsigned long base, u32 handle,
-                       struct nlattr **tca, unsigned long *arg)
+                       struct nlattr **tca, unsigned long *arg, bool ovr)
 {
        int err;
        struct basic_head *head = tp->root;
@@ -179,7 +179,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
        if (f != NULL) {
                if (handle && f->handle != handle)
                        return -EINVAL;
-               return basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE]);
+               return basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
        }
 
        err = -ENOBUFS;
@@ -206,7 +206,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
                f->handle = head->hgenerator;
        }
 
-       err = basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE]);
+       err = basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
        if (err < 0)
                goto errout;
 
index 8e3cf49118e3a2297214de12313bb499cbfe9054..16186965af97fd4cc7cad6725842aba8a56225dc 100644 (file)
@@ -156,7 +156,7 @@ static void cls_bpf_put(struct tcf_proto *tp, unsigned long f)
 static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp,
                                   struct cls_bpf_prog *prog,
                                   unsigned long base, struct nlattr **tb,
-                                  struct nlattr *est)
+                                  struct nlattr *est, bool ovr)
 {
        struct sock_filter *bpf_ops, *bpf_old;
        struct tcf_exts exts;
@@ -170,7 +170,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp,
                return -EINVAL;
 
        tcf_exts_init(&exts, TCA_BPF_ACT, TCA_BPF_POLICE);
-       ret = tcf_exts_validate(net, tp, tb, est, &exts);
+       ret = tcf_exts_validate(net, tp, tb, est, &exts, ovr);
        if (ret < 0)
                return ret;
 
@@ -242,7 +242,7 @@ static u32 cls_bpf_grab_new_handle(struct tcf_proto *tp,
 static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                          struct tcf_proto *tp, unsigned long base,
                          u32 handle, struct nlattr **tca,
-                         unsigned long *arg)
+                         unsigned long *arg, bool ovr)
 {
        struct cls_bpf_head *head = tp->root;
        struct cls_bpf_prog *prog = (struct cls_bpf_prog *) *arg;
@@ -260,7 +260,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                if (handle && prog->handle != handle)
                        return -EINVAL;
                return cls_bpf_modify_existing(net, tp, prog, base, tb,
-                                              tca[TCA_RATE]);
+                                              tca[TCA_RATE], ovr);
        }
 
        prog = kzalloc(sizeof(*prog), GFP_KERNEL);
@@ -277,7 +277,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                goto errout;
        }
 
-       ret = cls_bpf_modify_existing(net, tp, prog, base, tb, tca[TCA_RATE]);
+       ret = cls_bpf_modify_existing(net, tp, prog, base, tb, tca[TCA_RATE], ovr);
        if (ret < 0)
                goto errout;
 
index 8e2158ab551c0c9d7258ffae3e474788bfc64565..cacf01bd04f0a96660050c0e71da0840c8af0f95 100644 (file)
@@ -83,7 +83,7 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
 static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
                             struct tcf_proto *tp, unsigned long base,
                             u32 handle, struct nlattr **tca,
-                            unsigned long *arg)
+                            unsigned long *arg, bool ovr)
 {
        struct nlattr *tb[TCA_CGROUP_MAX + 1];
        struct cls_cgroup_head *head = tp->root;
@@ -119,7 +119,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
                return err;
 
        tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
        if (err < 0)
                return err;
 
index 257029c5433298f62101533ada3a81c246eb0d7a..35be16f7c192dc8d5d2ebdd38c2b27a144c41076 100644 (file)
@@ -349,7 +349,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
 static int flow_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle, struct nlattr **tca,
-                      unsigned long *arg)
+                      unsigned long *arg, bool ovr)
 {
        struct flow_head *head = tp->root;
        struct flow_filter *f;
@@ -393,7 +393,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
        }
 
        tcf_exts_init(&e, TCA_FLOW_ACT, TCA_FLOW_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
        if (err < 0)
                return err;
 
index 63a3ce75c02ee959fe67d6b203e01420d86b03ad..861b03ccfed0a55007ceb001a297b05906b36ed3 100644 (file)
@@ -169,7 +169,7 @@ static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = {
 
 static int
 fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
-       struct nlattr **tb, struct nlattr **tca, unsigned long base)
+       struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr)
 {
        struct fw_head *head = tp->root;
        struct tcf_exts e;
@@ -177,7 +177,7 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
        int err;
 
        tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
        if (err < 0)
                return err;
 
@@ -218,7 +218,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
                     struct tcf_proto *tp, unsigned long base,
                     u32 handle,
                     struct nlattr **tca,
-                    unsigned long *arg)
+                    unsigned long *arg, bool ovr)
 {
        struct fw_head *head = tp->root;
        struct fw_filter *f = (struct fw_filter *) *arg;
@@ -236,7 +236,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
        if (f != NULL) {
                if (f->id != handle && handle)
                        return -EINVAL;
-               return fw_change_attrs(net, tp, f, tb, tca, base);
+               return fw_change_attrs(net, tp, f, tb, tca, base, ovr);
        }
 
        if (!handle)
@@ -264,7 +264,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
        tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE);
        f->id = handle;
 
-       err = fw_change_attrs(net, tp, f, tb, tca, base);
+       err = fw_change_attrs(net, tp, f, tb, tca, base, ovr);
        if (err < 0)
                goto errout;
 
index 1ad3068f2ce16e2c6ba15985c40cf899a7030ba7..dd9fc2523c76a2b0b9fe4c5225328cc29c1649f6 100644 (file)
@@ -333,7 +333,8 @@ static const struct nla_policy route4_policy[TCA_ROUTE4_MAX + 1] = {
 static int route4_set_parms(struct net *net, struct tcf_proto *tp,
                            unsigned long base, struct route4_filter *f,
                            u32 handle, struct route4_head *head,
-                           struct nlattr **tb, struct nlattr *est, int new)
+                           struct nlattr **tb, struct nlattr *est, int new,
+                           bool ovr)
 {
        int err;
        u32 id = 0, to = 0, nhandle = 0x8000;
@@ -343,7 +344,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,
        struct tcf_exts e;
 
        tcf_exts_init(&e, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e);
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
        if (err < 0)
                return err;
 
@@ -428,7 +429,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle,
                       struct nlattr **tca,
-                      unsigned long *arg)
+                      unsigned long *arg, bool ovr)
 {
        struct route4_head *head = tp->root;
        struct route4_filter *f, *f1, **fp;
@@ -455,7 +456,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
                        old_handle = f->handle;
 
                err = route4_set_parms(net, tp, base, f, handle, head, tb,
-                       tca[TCA_RATE], 0);
+                       tca[TCA_RATE], 0, ovr);
                if (err < 0)
                        return err;
 
@@ -479,7 +480,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
 
        tcf_exts_init(&f->exts, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE);
        err = route4_set_parms(net, tp, base, f, handle, head, tb,
-               tca[TCA_RATE], 1);
+               tca[TCA_RATE], 1, ovr);
        if (err < 0)
                goto errout;
 
index 19f8e5dfa8bdaebcd9ab903050047e7e49690530..1020e233a5d6c74092fb153133b1bfed7f4177a9 100644 (file)
@@ -415,7 +415,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle,
                       struct nlattr **tca,
-                      unsigned long *arg)
+                      unsigned long *arg, bool ovr)
 {
        struct rsvp_head *data = tp->root;
        struct rsvp_filter *f, **fp;
@@ -436,7 +436,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb,
                return err;
 
        tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE);
-       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
        if (err < 0)
                return err;
 
index eed8404443d8f0145942c3e459b79934ada9c48d..d11d0a4fbe34f6af8390e9752468b2446079733a 100644 (file)
@@ -192,7 +192,7 @@ static int
 tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
                  u32 handle, struct tcindex_data *p,
                  struct tcindex_filter_result *r, struct nlattr **tb,
-                struct nlattr *est)
+                 struct nlattr *est, bool ovr)
 {
        int err, balloc = 0;
        struct tcindex_filter_result new_filter_result, *old_r = r;
@@ -202,7 +202,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
        struct tcf_exts e;
 
        tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e);
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
        if (err < 0)
                return err;
 
@@ -331,7 +331,7 @@ errout:
 static int
 tcindex_change(struct net *net, struct sk_buff *in_skb,
               struct tcf_proto *tp, unsigned long base, u32 handle,
-              struct nlattr **tca, unsigned long *arg)
+              struct nlattr **tca, unsigned long *arg, bool ovr)
 {
        struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_TCINDEX_MAX + 1];
@@ -351,7 +351,7 @@ tcindex_change(struct net *net, struct sk_buff *in_skb,
                return err;
 
        return tcindex_set_parms(net, tp, base, handle, p, r, tb,
-                                tca[TCA_RATE]);
+                                tca[TCA_RATE], ovr);
 }
 
 
index 84c28daff8484f643e5bed4176f6b225eec34e66..c39b583ace3229d4bae6a7b3774593e5eebd7141 100644 (file)
@@ -486,13 +486,13 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
 static int u32_set_parms(struct net *net, struct tcf_proto *tp,
                         unsigned long base, struct tc_u_hnode *ht,
                         struct tc_u_knode *n, struct nlattr **tb,
-                        struct nlattr *est)
+                        struct nlattr *est, bool ovr)
 {
        int err;
        struct tcf_exts e;
 
        tcf_exts_init(&e, TCA_U32_ACT, TCA_U32_POLICE);
-       err = tcf_exts_validate(net, tp, tb, est, &e);
+       err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
        if (err < 0)
                return err;
 
@@ -545,7 +545,7 @@ errout:
 static int u32_change(struct net *net, struct sk_buff *in_skb,
                      struct tcf_proto *tp, unsigned long base, u32 handle,
                      struct nlattr **tca,
-                     unsigned long *arg)
+                     unsigned long *arg, bool ovr)
 {
        struct tc_u_common *tp_c = tp->data;
        struct tc_u_hnode *ht;
@@ -569,7 +569,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                        return -EINVAL;
 
                return u32_set_parms(net, tp, base, n->ht_up, n, tb,
-                                    tca[TCA_RATE]);
+                                    tca[TCA_RATE], ovr);
        }
 
        if (tb[TCA_U32_DIVISOR]) {
@@ -656,7 +656,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
        }
 #endif
 
-       err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE]);
+       err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE], ovr);
        if (err == 0) {
                struct tc_u_knode **ins;
                for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next)
index a0b84e0e22deb4c9e998499b1e202ebaafda95f8..fd14df56e5ffdc2d96d61abbe55b2607c95179c5 100644 (file)
@@ -1084,7 +1084,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
        struct Qdisc *p = NULL;
        int err;
 
-       if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN))
+       if ((n->nlmsg_type != RTM_GETQDISC) &&
+           !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -1151,7 +1152,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
        struct Qdisc *q, *p;
        int err;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
 replay:
@@ -1490,7 +1491,8 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n)
        u32 qid;
        int err;
 
-       if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN))
+       if ((n->nlmsg_type != RTM_GETTCLASS) &&
+           !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
index edee03d922e28678cc4f4ba843f600236cf06f08..6e957c3b9854acc025e43d9028b94f0af7f4d6c1 100644 (file)
@@ -553,11 +553,6 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
        if (err < 0)
                return err;
 
-       sch_tree_lock(sch);
-
-       if (tb[TCA_HHF_BACKLOG_LIMIT])
-               sch->limit = nla_get_u32(tb[TCA_HHF_BACKLOG_LIMIT]);
-
        if (tb[TCA_HHF_QUANTUM])
                new_quantum = nla_get_u32(tb[TCA_HHF_QUANTUM]);
 
@@ -567,6 +562,12 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
        non_hh_quantum = (u64)new_quantum * new_hhf_non_hh_weight;
        if (non_hh_quantum > INT_MAX)
                return -EINVAL;
+
+       sch_tree_lock(sch);
+
+       if (tb[TCA_HHF_BACKLOG_LIMIT])
+               sch->limit = nla_get_u32(tb[TCA_HHF_BACKLOG_LIMIT]);
+
        q->quantum = new_quantum;
        q->hhf_non_hh_weight = new_hhf_non_hh_weight;
 
index c09757fbf8039e76c935c1dbf33ab2b19be228b1..44cbb54c85746a586407015c952e7f8d60ab4d91 100644 (file)
@@ -491,8 +491,13 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                        continue;
                if ((laddr->state == SCTP_ADDR_SRC) &&
                    (AF_INET == laddr->a.sa.sa_family)) {
-                       fl4->saddr = laddr->a.v4.sin_addr.s_addr;
                        fl4->fl4_sport = laddr->a.v4.sin_port;
+                       flowi4_update_output(fl4,
+                                            asoc->base.sk->sk_bound_dev_if,
+                                            RT_CONN_FLAGS(asoc->base.sk),
+                                            daddr->v4.sin_addr.s_addr,
+                                            laddr->a.v4.sin_addr.s_addr);
+
                        rt = ip_route_output_key(sock_net(sk), fl4);
                        if (!IS_ERR(rt)) {
                                dst = &rt->dst;
index 5d6883ff00c3b7056639f06254caffcb14349e27..fef2acdf4a2e675c55dc9fbf2124d132499b89e3 100644 (file)
@@ -496,11 +496,10 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
 
        /* If the transport error count is greater than the pf_retrans
         * threshold, and less than pathmaxrtx, and if the current state
-        * is not SCTP_UNCONFIRMED, then mark this transport as Partially
-        * Failed, see SCTP Quick Failover Draft, section 5.1
+        * is SCTP_ACTIVE, then mark this transport as Partially Failed,
+        * see SCTP Quick Failover Draft, section 5.1
         */
-       if ((transport->state != SCTP_PF) &&
-          (transport->state != SCTP_UNCONFIRMED) &&
+       if ((transport->state == SCTP_ACTIVE) &&
           (asoc->pf_retrans < transport->pathmaxrxt) &&
           (transport->error_count > asoc->pf_retrans)) {
 
index fee06b99a4da8dab4d2b094196af08e23d1f22d4..e37b2cbbf177da9739d54a2b101d3a4e74299745 100644 (file)
@@ -71,6 +71,7 @@
 #include <net/route.h>
 #include <net/ipv6.h>
 #include <net/inet_common.h>
+#include <net/busy_poll.h>
 
 #include <linux/socket.h> /* for sa_family_t */
 #include <linux/export.h>
@@ -6557,6 +6558,10 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
                if (sk->sk_shutdown & RCV_SHUTDOWN)
                        break;
 
+               if (sk_can_busy_loop(sk) &&
+                   sk_busy_loop(sk, noblock))
+                       continue;
+
                /* User doesn't want to wait.  */
                error = -EAGAIN;
                if (!timeo)
index 7144eb6a1b95ccad39f9376f723756e0b2c75a2c..d49dc2ed30adb97a809eb37902b9956c366a2862 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
+#include <net/busy_poll.h>
 #include <net/sctp/structs.h>
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
@@ -204,6 +205,9 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
        if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN))
                goto out_free;
 
+       if (!sctp_ulpevent_is_notification(event))
+               sk_mark_napi_id(sk, skb);
+
        /* Check if the user wishes to receive this event.  */
        if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe))
                goto out_free;
index b282f7130d2bb51f0dee12e4800a9a0ad54a33a7..a080c66d819a032233a963512d849f757cc979e2 100644 (file)
@@ -5,7 +5,7 @@
 obj-$(CONFIG_TIPC) := tipc.o
 
 tipc-y += addr.o bcast.o bearer.o config.o \
-          core.o handler.o link.o discover.o msg.o  \
+          core.o link.o discover.o msg.o  \
           name_distr.o  subscr.o name_table.o net.o  \
           netlink.o node.o node_subscr.o port.o ref.o  \
           socket.o log.o eth_media.o server.o
index 95ab5ef92920fddf34c02478973b98ebbe96ba59..a0978d0890cb3376a9a6aa4b44c20190ad766cc7 100644 (file)
@@ -71,7 +71,7 @@ struct tipc_bcbearer_pair {
  * Note: The fields labelled "temporary" are incorporated into the bearer
  * to avoid consuming potentially limited stack space through the use of
  * large local variables within multicast routines.  Concurrent access is
- * prevented through use of the spinlock "bc_lock".
+ * prevented through use of the spinlock "bclink_lock".
  */
 struct tipc_bcbearer {
        struct tipc_bearer bearer;
@@ -84,34 +84,64 @@ struct tipc_bcbearer {
 
 /**
  * struct tipc_bclink - link used for broadcast messages
+ * @lock: spinlock governing access to structure
  * @link: (non-standard) broadcast link structure
  * @node: (non-standard) node structure representing b'cast link's peer node
+ * @flags: represent bclink states
  * @bcast_nodes: map of broadcast-capable nodes
  * @retransmit_to: node that most recently requested a retransmit
  *
  * Handles sequence numbering, fragmentation, bundling, etc.
  */
 struct tipc_bclink {
+       spinlock_t lock;
        struct tipc_link link;
        struct tipc_node node;
+       unsigned int flags;
        struct tipc_node_map bcast_nodes;
        struct tipc_node *retransmit_to;
 };
 
-static struct tipc_bcbearer bcast_bearer;
-static struct tipc_bclink bcast_link;
-
-static struct tipc_bcbearer *bcbearer = &bcast_bearer;
-static struct tipc_bclink *bclink = &bcast_link;
-static struct tipc_link *bcl = &bcast_link.link;
-
-static DEFINE_SPINLOCK(bc_lock);
+static struct tipc_bcbearer *bcbearer;
+static struct tipc_bclink *bclink;
+static struct tipc_link *bcl;
 
 const char tipc_bclink_name[] = "broadcast-link";
 
 static void tipc_nmap_diff(struct tipc_node_map *nm_a,
                           struct tipc_node_map *nm_b,
                           struct tipc_node_map *nm_diff);
+static void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node);
+static void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node);
+
+static void tipc_bclink_lock(void)
+{
+       spin_lock_bh(&bclink->lock);
+}
+
+static void tipc_bclink_unlock(void)
+{
+       struct tipc_node *node = NULL;
+
+       if (likely(!bclink->flags)) {
+               spin_unlock_bh(&bclink->lock);
+               return;
+       }
+
+       if (bclink->flags & TIPC_BCLINK_RESET) {
+               bclink->flags &= ~TIPC_BCLINK_RESET;
+               node = tipc_bclink_retransmit_to();
+       }
+       spin_unlock_bh(&bclink->lock);
+
+       if (node)
+               tipc_link_reset_all(node);
+}
+
+void tipc_bclink_set_flags(unsigned int flags)
+{
+       bclink->flags |= flags;
+}
 
 static u32 bcbuf_acks(struct sk_buff *buf)
 {
@@ -130,16 +160,16 @@ static void bcbuf_decr_acks(struct sk_buff *buf)
 
 void tipc_bclink_add_node(u32 addr)
 {
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
        tipc_nmap_add(&bclink->bcast_nodes, addr);
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
 }
 
 void tipc_bclink_remove_node(u32 addr)
 {
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
        tipc_nmap_remove(&bclink->bcast_nodes, addr);
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
 }
 
 static void bclink_set_last_sent(void)
@@ -165,7 +195,7 @@ static void bclink_update_last_sent(struct tipc_node *node, u32 seqno)
 /**
  * tipc_bclink_retransmit_to - get most recent node to request retransmission
  *
- * Called with bc_lock locked
+ * Called with bclink_lock locked
  */
 struct tipc_node *tipc_bclink_retransmit_to(void)
 {
@@ -177,7 +207,7 @@ struct tipc_node *tipc_bclink_retransmit_to(void)
  * @after: sequence number of last packet to *not* retransmit
  * @to: sequence number of last packet to retransmit
  *
- * Called with bc_lock locked
+ * Called with bclink_lock locked
  */
 static void bclink_retransmit_pkt(u32 after, u32 to)
 {
@@ -194,7 +224,7 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
  * @n_ptr: node that sent acknowledgement info
  * @acked: broadcast sequence # that has been acknowledged
  *
- * Node is locked, bc_lock unlocked.
+ * Node is locked, bclink_lock unlocked.
  */
 void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
 {
@@ -202,8 +232,7 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
        struct sk_buff *next;
        unsigned int released = 0;
 
-       spin_lock_bh(&bc_lock);
-
+       tipc_bclink_lock();
        /* Bail out if tx queue is empty (no clean up is required) */
        crs = bcl->first_out;
        if (!crs)
@@ -267,13 +296,13 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
        if (unlikely(released && !list_empty(&bcl->waiting_ports)))
                tipc_link_wakeup_ports(bcl, 0);
 exit:
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
 }
 
 /**
  * tipc_bclink_update_link_state - update broadcast link state
  *
- * tipc_net_lock and node lock set
+ * RCU and node lock set
  */
 void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
 {
@@ -320,10 +349,10 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
                                 ? buf_seqno(n_ptr->bclink.deferred_head) - 1
                                 : n_ptr->bclink.last_sent);
 
-               spin_lock_bh(&bc_lock);
-               tipc_bearer_send(&bcbearer->bearer, buf, NULL);
+               tipc_bclink_lock();
+               tipc_bearer_send(MAX_BEARERS, buf, NULL);
                bcl->stats.sent_nacks++;
-               spin_unlock_bh(&bc_lock);
+               tipc_bclink_unlock();
                kfree_skb(buf);
 
                n_ptr->bclink.oos_state++;
@@ -335,8 +364,6 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
  *
  * Delay any upcoming NACK by this node if another node has already
  * requested the first message this node is going to ask for.
- *
- * Only tipc_net_lock set.
  */
 static void bclink_peek_nack(struct tipc_msg *msg)
 {
@@ -362,7 +389,7 @@ int tipc_bclink_xmit(struct sk_buff *buf)
 {
        int res;
 
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
 
        if (!bclink->bcast_nodes.count) {
                res = msg_data_sz(buf_msg(buf));
@@ -377,14 +404,14 @@ int tipc_bclink_xmit(struct sk_buff *buf)
                bcl->stats.accu_queue_sz += bcl->out_queue_size;
        }
 exit:
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
        return res;
 }
 
 /**
  * bclink_accept_pkt - accept an incoming, in-sequence broadcast packet
  *
- * Called with both sending node's lock and bc_lock taken.
+ * Called with both sending node's lock and bclink_lock taken.
  */
 static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
 {
@@ -408,7 +435,7 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
 /**
  * tipc_bclink_rcv - receive a broadcast packet, and deliver upwards
  *
- * tipc_net_lock is read_locked, no other locks set
+ * RCU is locked, no other locks set
  */
 void tipc_bclink_rcv(struct sk_buff *buf)
 {
@@ -439,12 +466,12 @@ void tipc_bclink_rcv(struct sk_buff *buf)
                if (msg_destnode(msg) == tipc_own_addr) {
                        tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
                        tipc_node_unlock(node);
-                       spin_lock_bh(&bc_lock);
+                       tipc_bclink_lock();
                        bcl->stats.recv_nacks++;
                        bclink->retransmit_to = node;
                        bclink_retransmit_pkt(msg_bcgap_after(msg),
                                              msg_bcgap_to(msg));
-                       spin_unlock_bh(&bc_lock);
+                       tipc_bclink_unlock();
                } else {
                        tipc_node_unlock(node);
                        bclink_peek_nack(msg);
@@ -462,20 +489,20 @@ receive:
                /* Deliver message to destination */
 
                if (likely(msg_isdata(msg))) {
-                       spin_lock_bh(&bc_lock);
+                       tipc_bclink_lock();
                        bclink_accept_pkt(node, seqno);
-                       spin_unlock_bh(&bc_lock);
+                       tipc_bclink_unlock();
                        tipc_node_unlock(node);
                        if (likely(msg_mcast(msg)))
                                tipc_port_mcast_rcv(buf, NULL);
                        else
                                kfree_skb(buf);
                } else if (msg_user(msg) == MSG_BUNDLER) {
-                       spin_lock_bh(&bc_lock);
+                       tipc_bclink_lock();
                        bclink_accept_pkt(node, seqno);
                        bcl->stats.recv_bundles++;
                        bcl->stats.recv_bundled += msg_msgcnt(msg);
-                       spin_unlock_bh(&bc_lock);
+                       tipc_bclink_unlock();
                        tipc_node_unlock(node);
                        tipc_link_bundle_rcv(buf);
                } else if (msg_user(msg) == MSG_FRAGMENTER) {
@@ -485,28 +512,28 @@ receive:
                                                 &buf);
                        if (ret == LINK_REASM_ERROR)
                                goto unlock;
-                       spin_lock_bh(&bc_lock);
+                       tipc_bclink_lock();
                        bclink_accept_pkt(node, seqno);
                        bcl->stats.recv_fragments++;
                        if (ret == LINK_REASM_COMPLETE) {
                                bcl->stats.recv_fragmented++;
                                /* Point msg to inner header */
                                msg = buf_msg(buf);
-                               spin_unlock_bh(&bc_lock);
+                               tipc_bclink_unlock();
                                goto receive;
                        }
-                       spin_unlock_bh(&bc_lock);
+                       tipc_bclink_unlock();
                        tipc_node_unlock(node);
                } else if (msg_user(msg) == NAME_DISTRIBUTOR) {
-                       spin_lock_bh(&bc_lock);
+                       tipc_bclink_lock();
                        bclink_accept_pkt(node, seqno);
-                       spin_unlock_bh(&bc_lock);
+                       tipc_bclink_unlock();
                        tipc_node_unlock(node);
                        tipc_named_rcv(buf);
                } else {
-                       spin_lock_bh(&bc_lock);
+                       tipc_bclink_lock();
                        bclink_accept_pkt(node, seqno);
-                       spin_unlock_bh(&bc_lock);
+                       tipc_bclink_unlock();
                        tipc_node_unlock(node);
                        kfree_skb(buf);
                }
@@ -552,14 +579,14 @@ receive:
        } else
                deferred = 0;
 
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
 
        if (deferred)
                bcl->stats.deferred_recv++;
        else
                bcl->stats.duplicates++;
 
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
 
 unlock:
        tipc_node_unlock(node);
@@ -627,13 +654,13 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
 
                if (bp_index == 0) {
                        /* Use original buffer for first bearer */
-                       tipc_bearer_send(b, buf, &b->bcast_addr);
+                       tipc_bearer_send(b->identity, buf, &b->bcast_addr);
                } else {
                        /* Avoid concurrent buffer access */
                        tbuf = pskb_copy(buf, GFP_ATOMIC);
                        if (!tbuf)
                                break;
-                       tipc_bearer_send(b, tbuf, &b->bcast_addr);
+                       tipc_bearer_send(b->identity, tbuf, &b->bcast_addr);
                        kfree_skb(tbuf); /* Bearer keeps a clone */
                }
 
@@ -655,20 +682,27 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
 /**
  * tipc_bcbearer_sort - create sets of bearer pairs used by broadcast bearer
  */
-void tipc_bcbearer_sort(void)
+void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action)
 {
        struct tipc_bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
        struct tipc_bcbearer_pair *bp_curr;
+       struct tipc_bearer *b;
        int b_index;
        int pri;
 
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
+
+       if (action)
+               tipc_nmap_add(nm_ptr, node);
+       else
+               tipc_nmap_remove(nm_ptr, node);
 
        /* Group bearers by priority (can assume max of two per priority) */
        memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
 
+       rcu_read_lock();
        for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
-               struct tipc_bearer *b = bearer_list[b_index];
+               b = rcu_dereference_rtnl(bearer_list[b_index]);
                if (!b || !b->nodes.count)
                        continue;
 
@@ -677,6 +711,7 @@ void tipc_bcbearer_sort(void)
                else
                        bp_temp[b->priority].secondary = b;
        }
+       rcu_read_unlock();
 
        /* Create array of bearer pairs for broadcasting */
        bp_curr = bcbearer->bpairs;
@@ -702,7 +737,7 @@ void tipc_bcbearer_sort(void)
                bp_curr++;
        }
 
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
 }
 
 
@@ -714,7 +749,7 @@ int tipc_bclink_stats(char *buf, const u32 buf_size)
        if (!bcl)
                return 0;
 
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
 
        s = &bcl->stats;
 
@@ -743,7 +778,7 @@ int tipc_bclink_stats(char *buf, const u32 buf_size)
                             s->queue_sz_counts ?
                             (s->accu_queue_sz / s->queue_sz_counts) : 0);
 
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
        return ret;
 }
 
@@ -752,9 +787,9 @@ int tipc_bclink_reset_stats(void)
        if (!bcl)
                return -ENOPROTOOPT;
 
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
        memset(&bcl->stats, 0, sizeof(bcl->stats));
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
        return 0;
 }
 
@@ -765,46 +800,59 @@ int tipc_bclink_set_queue_limits(u32 limit)
        if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN))
                return -EINVAL;
 
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
        tipc_link_set_queue_limits(bcl, limit);
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
        return 0;
 }
 
-void tipc_bclink_init(void)
+int tipc_bclink_init(void)
 {
+       bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC);
+       if (!bcbearer)
+               return -ENOMEM;
+
+       bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC);
+       if (!bclink) {
+               kfree(bcbearer);
+               return -ENOMEM;
+       }
+
+       bcl = &bclink->link;
        bcbearer->bearer.media = &bcbearer->media;
        bcbearer->media.send_msg = tipc_bcbearer_send;
        sprintf(bcbearer->media.name, "tipc-broadcast");
 
+       spin_lock_init(&bclink->lock);
        INIT_LIST_HEAD(&bcl->waiting_ports);
        bcl->next_out_no = 1;
        spin_lock_init(&bclink->node.lock);
        bcl->owner = &bclink->node;
        bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
-       bcl->b_ptr = &bcbearer->bearer;
-       bearer_list[BCBEARER] = &bcbearer->bearer;
+       bcl->bearer_id = MAX_BEARERS;
+       rcu_assign_pointer(bearer_list[MAX_BEARERS], &bcbearer->bearer);
        bcl->state = WORKING_WORKING;
        strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
+       return 0;
 }
 
 void tipc_bclink_stop(void)
 {
-       spin_lock_bh(&bc_lock);
+       tipc_bclink_lock();
        tipc_link_purge_queues(bcl);
-       spin_unlock_bh(&bc_lock);
+       tipc_bclink_unlock();
 
-       bearer_list[BCBEARER] = NULL;
-       memset(bclink, 0, sizeof(*bclink));
-       memset(bcbearer, 0, sizeof(*bcbearer));
+       RCU_INIT_POINTER(bearer_list[BCBEARER], NULL);
+       synchronize_net();
+       kfree(bcbearer);
+       kfree(bclink);
 }
 
-
 /**
  * tipc_nmap_add - add a node to a node map
  */
-void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
+static void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
 {
        int n = tipc_node(node);
        int w = n / WSIZE;
@@ -819,7 +867,7 @@ void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
 /**
  * tipc_nmap_remove - remove a node from a node map
  */
-void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
+static void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
 {
        int n = tipc_node(node);
        int w = n / WSIZE;
index a80ef54b818e221a98bd9bd69a3adf28d0001f88..00330c45df3e04d03626a31d5f2ee6ba66569298 100644 (file)
@@ -39,6 +39,7 @@
 
 #define MAX_NODES 4096
 #define WSIZE 32
+#define TIPC_BCLINK_RESET 1
 
 /**
  * struct tipc_node_map - set of node identifiers
@@ -69,9 +70,6 @@ struct tipc_node;
 
 extern const char tipc_bclink_name[];
 
-void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node);
-void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node);
-
 /**
  * tipc_nmap_equal - test for equality of node maps
  */
@@ -84,8 +82,9 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a,
 void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port);
 void tipc_port_list_free(struct tipc_port_list *pl_ptr);
 
-void tipc_bclink_init(void);
+int tipc_bclink_init(void);
 void tipc_bclink_stop(void);
+void tipc_bclink_set_flags(unsigned int flags);
 void tipc_bclink_add_node(u32 addr);
 void tipc_bclink_remove_node(u32 addr);
 struct tipc_node *tipc_bclink_retransmit_to(void);
@@ -98,6 +97,6 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent);
 int  tipc_bclink_stats(char *stats_buf, const u32 buf_size);
 int  tipc_bclink_reset_stats(void);
 int  tipc_bclink_set_queue_limits(u32 limit);
-void tipc_bcbearer_sort(void);
+void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action);
 
 #endif
index 3fef7eb776dc12934654b2bfa7500cfa75138ad4..f3259d4133b62f16702fb945e468f1553bbdd859 100644 (file)
@@ -49,7 +49,7 @@ static struct tipc_media * const media_info_array[] = {
        NULL
 };
 
-struct tipc_bearer *bearer_list[MAX_BEARERS + 1];
+struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
 
 static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
 
@@ -178,7 +178,7 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
        u32 i;
 
        for (i = 0; i < MAX_BEARERS; i++) {
-               b_ptr = bearer_list[i];
+               b_ptr = rtnl_dereference(bearer_list[i]);
                if (b_ptr && (!strcmp(b_ptr->name, name)))
                        return b_ptr;
        }
@@ -198,10 +198,9 @@ struct sk_buff *tipc_bearer_get_names(void)
        if (!buf)
                return NULL;
 
-       read_lock_bh(&tipc_net_lock);
        for (i = 0; media_info_array[i] != NULL; i++) {
                for (j = 0; j < MAX_BEARERS; j++) {
-                       b = bearer_list[j];
+                       b = rtnl_dereference(bearer_list[j]);
                        if (!b)
                                continue;
                        if (b->media == media_info_array[i]) {
@@ -211,22 +210,33 @@ struct sk_buff *tipc_bearer_get_names(void)
                        }
                }
        }
-       read_unlock_bh(&tipc_net_lock);
        return buf;
 }
 
-void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest)
+void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
 {
-       tipc_nmap_add(&b_ptr->nodes, dest);
-       tipc_bcbearer_sort();
-       tipc_disc_add_dest(b_ptr->link_req);
+       struct tipc_bearer *b_ptr;
+
+       rcu_read_lock();
+       b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
+       if (b_ptr) {
+               tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
+               tipc_disc_add_dest(b_ptr->link_req);
+       }
+       rcu_read_unlock();
 }
 
-void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
+void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
 {
-       tipc_nmap_remove(&b_ptr->nodes, dest);
-       tipc_bcbearer_sort();
-       tipc_disc_remove_dest(b_ptr->link_req);
+       struct tipc_bearer *b_ptr;
+
+       rcu_read_lock();
+       b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
+       if (b_ptr) {
+               tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
+               tipc_disc_remove_dest(b_ptr->link_req);
+       }
+       rcu_read_unlock();
 }
 
 /**
@@ -271,13 +281,11 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
                return -EINVAL;
        }
 
-       write_lock_bh(&tipc_net_lock);
-
        m_ptr = tipc_media_find(b_names.media_name);
        if (!m_ptr) {
                pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
                        name, b_names.media_name);
-               goto exit;
+               return -EINVAL;
        }
 
        if (priority == TIPC_MEDIA_LINK_PRI)
@@ -287,7 +295,7 @@ restart:
        bearer_id = MAX_BEARERS;
        with_this_prio = 1;
        for (i = MAX_BEARERS; i-- != 0; ) {
-               b_ptr = bearer_list[i];
+               b_ptr = rtnl_dereference(bearer_list[i]);
                if (!b_ptr) {
                        bearer_id = i;
                        continue;
@@ -295,14 +303,14 @@ restart:
                if (!strcmp(name, b_ptr->name)) {
                        pr_warn("Bearer <%s> rejected, already enabled\n",
                                name);
-                       goto exit;
+                       return -EINVAL;
                }
                if ((b_ptr->priority == priority) &&
                    (++with_this_prio > 2)) {
                        if (priority-- == 0) {
                                pr_warn("Bearer <%s> rejected, duplicate priority\n",
                                        name);
-                               goto exit;
+                               return -EINVAL;
                        }
                        pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
                                name, priority + 1, priority);
@@ -312,21 +320,20 @@ restart:
        if (bearer_id >= MAX_BEARERS) {
                pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
                        name, MAX_BEARERS);
-               goto exit;
+               return -EINVAL;
        }
 
        b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
-       if (!b_ptr) {
-               res = -ENOMEM;
-               goto exit;
-       }
+       if (!b_ptr)
+               return -ENOMEM;
+
        strcpy(b_ptr->name, name);
        b_ptr->media = m_ptr;
        res = m_ptr->enable_media(b_ptr);
        if (res) {
                pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
                        name, -res);
-               goto exit;
+               return -EINVAL;
        }
 
        b_ptr->identity = bearer_id;
@@ -341,16 +348,14 @@ restart:
                bearer_disable(b_ptr, false);
                pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
                        name);
-               goto exit;
+               return -EINVAL;
        }
 
-       bearer_list[bearer_id] = b_ptr;
+       rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
 
        pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
                name,
                tipc_addr_string_fill(addr_string, disc_domain), priority);
-exit:
-       write_unlock_bh(&tipc_net_lock);
        return res;
 }
 
@@ -359,19 +364,16 @@ exit:
  */
 static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
 {
-       read_lock_bh(&tipc_net_lock);
        pr_info("Resetting bearer <%s>\n", b_ptr->name);
-       tipc_disc_delete(b_ptr->link_req);
        tipc_link_reset_list(b_ptr->identity);
-       tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
-       read_unlock_bh(&tipc_net_lock);
+       tipc_disc_reset(b_ptr);
        return 0;
 }
 
 /**
  * bearer_disable
  *
- * Note: This routine assumes caller holds tipc_net_lock.
+ * Note: This routine assumes caller holds RTNL lock.
  */
 static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
 {
@@ -385,12 +387,12 @@ static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
                tipc_disc_delete(b_ptr->link_req);
 
        for (i = 0; i < MAX_BEARERS; i++) {
-               if (b_ptr == bearer_list[i]) {
-                       bearer_list[i] = NULL;
+               if (b_ptr == rtnl_dereference(bearer_list[i])) {
+                       RCU_INIT_POINTER(bearer_list[i], NULL);
                        break;
                }
        }
-       kfree(b_ptr);
+       kfree_rcu(b_ptr, rcu);
 }
 
 int tipc_disable_bearer(const char *name)
@@ -398,7 +400,6 @@ int tipc_disable_bearer(const char *name)
        struct tipc_bearer *b_ptr;
        int res;
 
-       write_lock_bh(&tipc_net_lock);
        b_ptr = tipc_bearer_find(name);
        if (b_ptr == NULL) {
                pr_warn("Attempt to disable unknown bearer <%s>\n", name);
@@ -407,7 +408,6 @@ int tipc_disable_bearer(const char *name)
                bearer_disable(b_ptr, false);
                res = 0;
        }
-       write_unlock_bh(&tipc_net_lock);
        return res;
 }
 
@@ -444,7 +444,7 @@ int tipc_enable_l2_media(struct tipc_bearer *b)
                return -ENODEV;
 
        /* Associate TIPC bearer with Ethernet bearer */
-       b->media_ptr = dev;
+       rcu_assign_pointer(b->media_ptr, dev);
        memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value));
        memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
        b->bcast_addr.media_id = b->media->type_id;
@@ -463,8 +463,12 @@ int tipc_enable_l2_media(struct tipc_bearer *b)
  */
 void tipc_disable_l2_media(struct tipc_bearer *b)
 {
-       struct net_device *dev = (struct net_device *)b->media_ptr;
+       struct net_device *dev;
+
+       dev = (struct net_device *)rtnl_dereference(b->media_ptr);
+       RCU_INIT_POINTER(b->media_ptr, NULL);
        RCU_INIT_POINTER(dev->tipc_ptr, NULL);
+       synchronize_net();
        dev_put(dev);
 }
 
@@ -478,8 +482,12 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
                     struct tipc_media_addr *dest)
 {
        struct sk_buff *clone;
+       struct net_device *dev;
        int delta;
-       struct net_device *dev = (struct net_device *)b->media_ptr;
+
+       dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
+       if (!dev)
+               return 0;
 
        clone = skb_clone(buf, GFP_ATOMIC);
        if (!clone)
@@ -507,10 +515,16 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
  * The media send routine must not alter the buffer being passed in
  * as it may be needed for later retransmission!
  */
-void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf,
+void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
                      struct tipc_media_addr *dest)
 {
-       b->media->send_msg(buf, b, dest);
+       struct tipc_bearer *b_ptr;
+
+       rcu_read_lock();
+       b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
+       if (likely(b_ptr))
+               b_ptr->media->send_msg(buf, b_ptr, dest);
+       rcu_read_unlock();
 }
 
 /**
@@ -535,7 +549,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
        }
 
        rcu_read_lock();
-       b_ptr = rcu_dereference(dev->tipc_ptr);
+       b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
        if (likely(b_ptr)) {
                if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
                        buf->next = NULL;
@@ -568,12 +582,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
        if (!net_eq(dev_net(dev), &init_net))
                return NOTIFY_DONE;
 
-       rcu_read_lock();
-       b_ptr = rcu_dereference(dev->tipc_ptr);
-       if (!b_ptr) {
-               rcu_read_unlock();
+       b_ptr = rtnl_dereference(dev->tipc_ptr);
+       if (!b_ptr)
                return NOTIFY_DONE;
-       }
 
        b_ptr->mtu = dev->mtu;
 
@@ -592,11 +603,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
                break;
        case NETDEV_UNREGISTER:
        case NETDEV_CHANGENAME:
-               tipc_disable_bearer(b_ptr->name);
+               bearer_disable(b_ptr, false);
                break;
        }
-       rcu_read_unlock();
-
        return NOTIFY_OK;
 }
 
@@ -633,7 +642,7 @@ void tipc_bearer_stop(void)
        u32 i;
 
        for (i = 0; i < MAX_BEARERS; i++) {
-               b_ptr = bearer_list[i];
+               b_ptr = rtnl_dereference(bearer_list[i]);
                if (b_ptr) {
                        bearer_disable(b_ptr, true);
                        bearer_list[i] = NULL;
index ba48145e871dd8dcd357a193b61e9234e5ad7f0d..a983b3005e715b577d78060854edc373324514bd 100644 (file)
@@ -113,6 +113,7 @@ struct tipc_media {
  * @name: bearer name (format = media:interface)
  * @media: ptr to media structure associated with bearer
  * @bcast_addr: media address used in broadcasting
+ * @rcu: rcu struct for tipc_bearer
  * @priority: default link priority for bearer
  * @window: default window size for bearer
  * @tolerance: default link tolerance for bearer
@@ -127,12 +128,13 @@ struct tipc_media {
  * care of initializing all other fields.
  */
 struct tipc_bearer {
-       void *media_ptr;                        /* initalized by media */
+       void __rcu *media_ptr;                  /* initalized by media */
        u32 mtu;                                /* initalized by media */
        struct tipc_media_addr addr;            /* initalized by media */
        char name[TIPC_MAX_BEARER_NAME];
        struct tipc_media *media;
        struct tipc_media_addr bcast_addr;
+       struct rcu_head rcu;
        u32 priority;
        u32 window;
        u32 tolerance;
@@ -150,7 +152,7 @@ struct tipc_bearer_names {
 
 struct tipc_link;
 
-extern struct tipc_bearer *bearer_list[];
+extern struct tipc_bearer __rcu *bearer_list[];
 
 /*
  * TIPC routines available to supported media types
@@ -181,14 +183,14 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
                     struct tipc_media_addr *dest);
 
 struct sk_buff *tipc_bearer_get_names(void);
-void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest);
-void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest);
+void tipc_bearer_add_dest(u32 bearer_id, u32 dest);
+void tipc_bearer_remove_dest(u32 bearer_id, u32 dest);
 struct tipc_bearer *tipc_bearer_find(const char *name);
 struct tipc_media *tipc_media_find(const char *name);
 int tipc_bearer_setup(void);
 void tipc_bearer_cleanup(void);
 void tipc_bearer_stop(void);
-void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf,
+void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
                      struct tipc_media_addr *dest);
 
 #endif /* _TIPC_BEARER_H */
index 4b981c053823e90cc31963277aedd8c3682bc1a0..2b42403ad33a690221456ff25fb4be50a2235255 100644 (file)
@@ -42,8 +42,6 @@
 
 #define REPLY_TRUNCATED "<truncated>\n"
 
-static DEFINE_MUTEX(config_mutex);
-
 static const void *req_tlv_area;       /* request message TLV area */
 static int req_tlv_space;              /* request message TLV area size */
 static int rep_headroom;               /* reply message headroom to use */
@@ -179,8 +177,10 @@ static struct sk_buff *cfg_set_own_addr(void)
        if (tipc_own_addr)
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (cannot change node address once assigned)");
-       tipc_net_start(addr);
-       return tipc_cfg_reply_none();
+       if (!tipc_net_start(addr))
+               return tipc_cfg_reply_none();
+
+       return tipc_cfg_reply_error_string("cannot change to network mode");
 }
 
 static struct sk_buff *cfg_set_max_ports(void)
@@ -223,7 +223,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
 {
        struct sk_buff *rep_tlv_buf;
 
-       mutex_lock(&config_mutex);
+       rtnl_lock();
 
        /* Save request and reply details in a well-known location */
        req_tlv_area = request_area;
@@ -337,6 +337,6 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
 
        /* Return reply buffer */
 exit:
-       mutex_unlock(&config_mutex);
+       rtnl_unlock();
        return rep_tlv_buf;
 }
index 50d57429ebcaf82b8d36bcf49f6fa1585664180a..57f8ae9aa466660afd49026aebd0958a8d1aa657 100644 (file)
@@ -80,7 +80,6 @@ struct sk_buff *tipc_buf_acquire(u32 size)
  */
 static void tipc_core_stop(void)
 {
-       tipc_handler_stop();
        tipc_net_stop();
        tipc_bearer_cleanup();
        tipc_netlink_stop();
@@ -100,10 +99,6 @@ static int tipc_core_start(void)
 
        get_random_bytes(&tipc_random, sizeof(tipc_random));
 
-       err = tipc_handler_start();
-       if (err)
-               goto out_handler;
-
        err = tipc_ref_table_init(tipc_max_ports, tipc_random);
        if (err)
                goto out_reftbl;
@@ -146,8 +141,6 @@ out_netlink:
 out_nametbl:
        tipc_ref_table_stop();
 out_reftbl:
-       tipc_handler_stop();
-out_handler:
        return err;
 }
 
index 8985bbcb942bdb3d6ef839c3249d4e547c2f75ce..ae55d37267e6a34eedf7bac78bdd336847a1d4de 100644 (file)
@@ -56,7 +56,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-
+#include <linux/rtnetlink.h>
 
 #define TIPC_MOD_VER "2.0.0"
 
@@ -89,8 +89,6 @@ extern int tipc_random __read_mostly;
 /*
  * Routines available to privileged subsystems
  */
-int tipc_handler_start(void);
-void tipc_handler_stop(void);
 int tipc_netlink_start(void);
 void tipc_netlink_stop(void);
 int tipc_socket_init(void);
@@ -109,12 +107,10 @@ void tipc_unregister_sysctl(void);
 #endif
 
 /*
- * TIPC timer and signal code
+ * TIPC timer code
  */
 typedef void (*Handler) (unsigned long);
 
-u32 tipc_k_signal(Handler routine, unsigned long argument);
-
 /**
  * k_init_timer - initialize a timer
  * @timer: pointer to timer structure
index 542fe3413dc4e8d06d97eb2d5a409d2a7b26459a..bd35c4a0746f3aba884ad71b3f6a17e0f4e25155 100644 (file)
@@ -46,8 +46,9 @@
 
 /**
  * struct tipc_link_req - information about an ongoing link setup request
- * @bearer: bearer issuing requests
+ * @bearer_id: identity of bearer issuing requests
  * @dest: destination address for request messages
+ * @domain: network domain to which links can be established
  * @num_nodes: number of nodes currently discovered (i.e. with an active link)
  * @lock: spinlock for controlling access to requests
  * @buf: request message to be (repeatedly) sent
@@ -55,8 +56,9 @@
  * @timer_intv: current interval between requests (in ms)
  */
 struct tipc_link_req {
-       struct tipc_bearer *bearer;
+       u32 bearer_id;
        struct tipc_media_addr dest;
+       u32 domain;
        int num_nodes;
        spinlock_t lock;
        struct sk_buff *buf;
@@ -69,22 +71,19 @@ struct tipc_link_req {
  * @type: message type (request or response)
  * @b_ptr: ptr to bearer issuing message
  */
-static struct sk_buff *tipc_disc_init_msg(u32 type, struct tipc_bearer *b_ptr)
+static void tipc_disc_init_msg(struct sk_buff *buf, u32 type,
+                              struct tipc_bearer *b_ptr)
 {
-       struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
        struct tipc_msg *msg;
        u32 dest_domain = b_ptr->domain;
 
-       if (buf) {
-               msg = buf_msg(buf);
-               tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
-               msg_set_non_seq(msg, 1);
-               msg_set_node_sig(msg, tipc_random);
-               msg_set_dest_domain(msg, dest_domain);
-               msg_set_bc_netid(msg, tipc_net_id);
-               b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
-       }
-       return buf;
+       msg = buf_msg(buf);
+       tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
+       msg_set_non_seq(msg, 1);
+       msg_set_node_sig(msg, tipc_random);
+       msg_set_dest_domain(msg, dest_domain);
+       msg_set_bc_netid(msg, tipc_net_id);
+       b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
 }
 
 /**
@@ -239,9 +238,10 @@ void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr)
        link_fully_up = link_working_working(link);
 
        if ((type == DSC_REQ_MSG) && !link_fully_up) {
-               rbuf = tipc_disc_init_msg(DSC_RESP_MSG, b_ptr);
+               rbuf = tipc_buf_acquire(INT_H_SIZE);
                if (rbuf) {
-                       tipc_bearer_send(b_ptr, rbuf, &media_addr);
+                       tipc_disc_init_msg(rbuf, DSC_RESP_MSG, b_ptr);
+                       tipc_bearer_send(b_ptr->identity, rbuf, &media_addr);
                        kfree_skb(rbuf);
                }
        }
@@ -303,7 +303,7 @@ static void disc_timeout(struct tipc_link_req *req)
        spin_lock_bh(&req->lock);
 
        /* Stop searching if only desired node has been found */
-       if (tipc_node(req->bearer->domain) && req->num_nodes) {
+       if (tipc_node(req->domain) && req->num_nodes) {
                req->timer_intv = TIPC_LINK_REQ_INACTIVE;
                goto exit;
        }
@@ -315,7 +315,7 @@ static void disc_timeout(struct tipc_link_req *req)
         * hold at fast polling rate if don't have any associated nodes,
         * otherwise hold at slow polling rate
         */
-       tipc_bearer_send(req->bearer, req->buf, &req->dest);
+       tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
 
 
        req->timer_intv *= 2;
@@ -347,21 +347,23 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
        if (!req)
                return -ENOMEM;
 
-       req->buf = tipc_disc_init_msg(DSC_REQ_MSG, b_ptr);
+       req->buf = tipc_buf_acquire(INT_H_SIZE);
        if (!req->buf) {
                kfree(req);
-               return -ENOMSG;
+               return -ENOMEM;
        }
 
+       tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
        memcpy(&req->dest, dest, sizeof(*dest));
-       req->bearer = b_ptr;
+       req->bearer_id = b_ptr->identity;
+       req->domain = b_ptr->domain;
        req->num_nodes = 0;
        req->timer_intv = TIPC_LINK_REQ_INIT;
        spin_lock_init(&req->lock);
        k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
        k_start_timer(&req->timer, req->timer_intv);
        b_ptr->link_req = req;
-       tipc_bearer_send(req->bearer, req->buf, &req->dest);
+       tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
        return 0;
 }
 
@@ -376,3 +378,23 @@ void tipc_disc_delete(struct tipc_link_req *req)
        kfree_skb(req->buf);
        kfree(req);
 }
+
+/**
+ * tipc_disc_reset - reset object to send periodic link setup requests
+ * @b_ptr: ptr to bearer issuing requests
+ * @dest_domain: network domain to which links can be established
+ */
+void tipc_disc_reset(struct tipc_bearer *b_ptr)
+{
+       struct tipc_link_req *req = b_ptr->link_req;
+
+       spin_lock_bh(&req->lock);
+       tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
+       req->bearer_id = b_ptr->identity;
+       req->domain = b_ptr->domain;
+       req->num_nodes = 0;
+       req->timer_intv = TIPC_LINK_REQ_INIT;
+       k_start_timer(&req->timer, req->timer_intv);
+       tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
+       spin_unlock_bh(&req->lock);
+}
index 07f34729459dcacb93b71d8a56c69263db5f563b..515b57392f4d881b567d6d29cc7677bfece5e4c7 100644 (file)
@@ -41,6 +41,7 @@ struct tipc_link_req;
 
 int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest);
 void tipc_disc_delete(struct tipc_link_req *req);
+void tipc_disc_reset(struct tipc_bearer *b_ptr);
 void tipc_disc_add_dest(struct tipc_link_req *req);
 void tipc_disc_remove_dest(struct tipc_link_req *req);
 void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr);
diff --git a/net/tipc/handler.c b/net/tipc/handler.c
deleted file mode 100644 (file)
index 1fabf16..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * net/tipc/handler.c: TIPC signal handling
- *
- * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
- * All rights reserved.
- *
- * 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.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core.h"
-
-struct queue_item {
-       struct list_head next_signal;
-       void (*handler) (unsigned long);
-       unsigned long data;
-};
-
-static struct kmem_cache *tipc_queue_item_cache;
-static struct list_head signal_queue_head;
-static DEFINE_SPINLOCK(qitem_lock);
-static int handler_enabled __read_mostly;
-
-static void process_signal_queue(unsigned long dummy);
-
-static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0);
-
-
-unsigned int tipc_k_signal(Handler routine, unsigned long argument)
-{
-       struct queue_item *item;
-
-       spin_lock_bh(&qitem_lock);
-       if (!handler_enabled) {
-               spin_unlock_bh(&qitem_lock);
-               return -ENOPROTOOPT;
-       }
-
-       item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
-       if (!item) {
-               pr_err("Signal queue out of memory\n");
-               spin_unlock_bh(&qitem_lock);
-               return -ENOMEM;
-       }
-       item->handler = routine;
-       item->data = argument;
-       list_add_tail(&item->next_signal, &signal_queue_head);
-       spin_unlock_bh(&qitem_lock);
-       tasklet_schedule(&tipc_tasklet);
-       return 0;
-}
-
-static void process_signal_queue(unsigned long dummy)
-{
-       struct queue_item *__volatile__ item;
-       struct list_head *l, *n;
-
-       spin_lock_bh(&qitem_lock);
-       list_for_each_safe(l, n, &signal_queue_head) {
-               item = list_entry(l, struct queue_item, next_signal);
-               list_del(&item->next_signal);
-               spin_unlock_bh(&qitem_lock);
-               item->handler(item->data);
-               spin_lock_bh(&qitem_lock);
-               kmem_cache_free(tipc_queue_item_cache, item);
-       }
-       spin_unlock_bh(&qitem_lock);
-}
-
-int tipc_handler_start(void)
-{
-       tipc_queue_item_cache =
-               kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
-                                 0, SLAB_HWCACHE_ALIGN, NULL);
-       if (!tipc_queue_item_cache)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&signal_queue_head);
-       tasklet_enable(&tipc_tasklet);
-       handler_enabled = 1;
-       return 0;
-}
-
-void tipc_handler_stop(void)
-{
-       struct list_head *l, *n;
-       struct queue_item *item;
-
-       spin_lock_bh(&qitem_lock);
-       if (!handler_enabled) {
-               spin_unlock_bh(&qitem_lock);
-               return;
-       }
-       handler_enabled = 0;
-       spin_unlock_bh(&qitem_lock);
-
-       tasklet_kill(&tipc_tasklet);
-
-       spin_lock_bh(&qitem_lock);
-       list_for_each_safe(l, n, &signal_queue_head) {
-               item = list_entry(l, struct queue_item, next_signal);
-               list_del(&item->next_signal);
-               kmem_cache_free(tipc_queue_item_cache, item);
-       }
-       spin_unlock_bh(&qitem_lock);
-
-       kmem_cache_destroy(tipc_queue_item_cache);
-}
index c5190ab75290d04202b99a3e923a69fe1a9dad38..dce2bef817206dce31aa726b23be1eb0970f5114 100644 (file)
@@ -101,9 +101,18 @@ static unsigned int align(unsigned int i)
 
 static void link_init_max_pkt(struct tipc_link *l_ptr)
 {
+       struct tipc_bearer *b_ptr;
        u32 max_pkt;
 
-       max_pkt = (l_ptr->b_ptr->mtu & ~3);
+       rcu_read_lock();
+       b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]);
+       if (!b_ptr) {
+               rcu_read_unlock();
+               return;
+       }
+       max_pkt = (b_ptr->mtu & ~3);
+       rcu_read_unlock();
+
        if (max_pkt > MAX_MSG_SIZE)
                max_pkt = MAX_MSG_SIZE;
 
@@ -248,7 +257,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
        l_ptr->owner = n_ptr;
        l_ptr->checkpoint = 1;
        l_ptr->peer_session = INVALID_SESSION;
-       l_ptr->b_ptr = b_ptr;
+       l_ptr->bearer_id = b_ptr->identity;
        link_set_supervision_props(l_ptr, b_ptr->tolerance);
        l_ptr->state = RESET_UNKNOWN;
 
@@ -263,6 +272,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
        l_ptr->priority = b_ptr->priority;
        tipc_link_set_queue_limits(l_ptr, b_ptr->window);
 
+       l_ptr->net_plane = b_ptr->net_plane;
        link_init_max_pkt(l_ptr);
 
        l_ptr->next_out_no = 1;
@@ -287,14 +297,14 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
 
        rcu_read_lock();
        list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
-               spin_lock_bh(&n_ptr->lock);
+               tipc_node_lock(n_ptr);
                l_ptr = n_ptr->links[bearer_id];
                if (l_ptr) {
                        tipc_link_reset(l_ptr);
                        if (shutting_down || !tipc_node_is_up(n_ptr)) {
                                tipc_node_detach_link(l_ptr->owner, l_ptr);
                                tipc_link_reset_fragments(l_ptr);
-                               spin_unlock_bh(&n_ptr->lock);
+                               tipc_node_unlock(n_ptr);
 
                                /* Nobody else can access this link now: */
                                del_timer_sync(&l_ptr->timer);
@@ -302,12 +312,12 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
                        } else {
                                /* Detach/delete when failover is finished: */
                                l_ptr->flags |= LINK_STOPPED;
-                               spin_unlock_bh(&n_ptr->lock);
+                               tipc_node_unlock(n_ptr);
                                del_timer_sync(&l_ptr->timer);
                        }
                        continue;
                }
-               spin_unlock_bh(&n_ptr->lock);
+               tipc_node_unlock(n_ptr);
        }
        rcu_read_unlock();
 }
@@ -426,7 +436,7 @@ void tipc_link_reset(struct tipc_link *l_ptr)
                return;
 
        tipc_node_link_down(l_ptr->owner, l_ptr);
-       tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
+       tipc_bearer_remove_dest(l_ptr->bearer_id, l_ptr->addr);
 
        if (was_active_link && tipc_node_active_links(l_ptr->owner)) {
                l_ptr->reset_checkpoint = checkpoint;
@@ -464,11 +474,11 @@ void tipc_link_reset_list(unsigned int bearer_id)
 
        rcu_read_lock();
        list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
-               spin_lock_bh(&n_ptr->lock);
+               tipc_node_lock(n_ptr);
                l_ptr = n_ptr->links[bearer_id];
                if (l_ptr)
                        tipc_link_reset(l_ptr);
-               spin_unlock_bh(&n_ptr->lock);
+               tipc_node_unlock(n_ptr);
        }
        rcu_read_unlock();
 }
@@ -477,7 +487,7 @@ static void link_activate(struct tipc_link *l_ptr)
 {
        l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
        tipc_node_link_up(l_ptr->owner, l_ptr);
-       tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
+       tipc_bearer_add_dest(l_ptr->bearer_id, l_ptr->addr);
 }
 
 /**
@@ -777,7 +787,7 @@ int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf)
        if (likely(!link_congested(l_ptr))) {
                link_add_to_outqueue(l_ptr, buf, msg);
 
-               tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
+               tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr);
                l_ptr->unacked_window = 0;
                return dsz;
        }
@@ -825,7 +835,6 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector)
        struct tipc_node *n_ptr;
        int res = -ELINKCONG;
 
-       read_lock_bh(&tipc_net_lock);
        n_ptr = tipc_node_find(dest);
        if (n_ptr) {
                tipc_node_lock(n_ptr);
@@ -838,7 +847,6 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector)
        } else {
                kfree_skb(buf);
        }
-       read_unlock_bh(&tipc_net_lock);
        return res;
 }
 
@@ -902,7 +910,6 @@ void tipc_link_names_xmit(struct list_head *message_list, u32 dest)
        if (list_empty(message_list))
                return;
 
-       read_lock_bh(&tipc_net_lock);
        n_ptr = tipc_node_find(dest);
        if (n_ptr) {
                tipc_node_lock(n_ptr);
@@ -917,7 +924,6 @@ void tipc_link_names_xmit(struct list_head *message_list, u32 dest)
                }
                tipc_node_unlock(n_ptr);
        }
-       read_unlock_bh(&tipc_net_lock);
 
        /* discard the messages if they couldn't be sent */
        list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) {
@@ -941,7 +947,7 @@ static int tipc_link_xmit_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
        if (likely(!link_congested(l_ptr))) {
                if (likely(msg_size(msg) <= l_ptr->max_pkt)) {
                        link_add_to_outqueue(l_ptr, buf, msg);
-                       tipc_bearer_send(l_ptr->b_ptr, buf,
+                       tipc_bearer_send(l_ptr->bearer_id, buf,
                                         &l_ptr->media_addr);
                        l_ptr->unacked_window = 0;
                        return res;
@@ -979,7 +985,6 @@ again:
        if (unlikely(res < 0))
                return res;
 
-       read_lock_bh(&tipc_net_lock);
        node = tipc_node_find(destaddr);
        if (likely(node)) {
                tipc_node_lock(node);
@@ -990,7 +995,6 @@ again:
                                                          &sender->max_pkt);
 exit:
                                tipc_node_unlock(node);
-                               read_unlock_bh(&tipc_net_lock);
                                return res;
                        }
 
@@ -1007,7 +1011,6 @@ exit:
                         */
                        sender->max_pkt = l_ptr->max_pkt;
                        tipc_node_unlock(node);
-                       read_unlock_bh(&tipc_net_lock);
 
 
                        if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
@@ -1018,7 +1021,6 @@ exit:
                }
                tipc_node_unlock(node);
        }
-       read_unlock_bh(&tipc_net_lock);
 
        /* Couldn't find a link to the destination node */
        kfree_skb(buf);
@@ -1204,7 +1206,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr)
        if (r_q_size && buf) {
                msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
                msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);
-               tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
+               tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr);
                l_ptr->retransm_queue_head = mod(++r_q_head);
                l_ptr->retransm_queue_size = --r_q_size;
                l_ptr->stats.retransmitted++;
@@ -1216,7 +1218,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr)
        if (buf) {
                msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
                msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);
-               tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
+               tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr);
                l_ptr->unacked_window = 0;
                kfree_skb(buf);
                l_ptr->proto_msg_queue = NULL;
@@ -1233,7 +1235,8 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr)
                if (mod(next - first) < l_ptr->queue_limit[0]) {
                        msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
                        msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
-                       tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
+                       tipc_bearer_send(l_ptr->bearer_id, buf,
+                                        &l_ptr->media_addr);
                        if (msg_user(msg) == MSG_BUNDLER)
                                msg_set_type(msg, CLOSED_MSG);
                        l_ptr->next_out = buf->next;
@@ -1256,33 +1259,24 @@ void tipc_link_push_queue(struct tipc_link *l_ptr)
        } while (!res);
 }
 
-static void link_reset_all(unsigned long addr)
+void tipc_link_reset_all(struct tipc_node *node)
 {
-       struct tipc_node *n_ptr;
        char addr_string[16];
        u32 i;
 
-       read_lock_bh(&tipc_net_lock);
-       n_ptr = tipc_node_find((u32)addr);
-       if (!n_ptr) {
-               read_unlock_bh(&tipc_net_lock);
-               return; /* node no longer exists */
-       }
-
-       tipc_node_lock(n_ptr);
+       tipc_node_lock(node);
 
        pr_warn("Resetting all links to %s\n",
-               tipc_addr_string_fill(addr_string, n_ptr->addr));
+               tipc_addr_string_fill(addr_string, node->addr));
 
        for (i = 0; i < MAX_BEARERS; i++) {
-               if (n_ptr->links[i]) {
-                       link_print(n_ptr->links[i], "Resetting link\n");
-                       tipc_link_reset(n_ptr->links[i]);
+               if (node->links[i]) {
+                       link_print(node->links[i], "Resetting link\n");
+                       tipc_link_reset(node->links[i]);
                }
        }
 
-       tipc_node_unlock(n_ptr);
-       read_unlock_bh(&tipc_net_lock);
+       tipc_node_unlock(node);
 }
 
 static void link_retransmit_failure(struct tipc_link *l_ptr,
@@ -1319,10 +1313,9 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
                        n_ptr->bclink.oos_state,
                        n_ptr->bclink.last_sent);
 
-               tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
-
                tipc_node_unlock(n_ptr);
 
+               tipc_bclink_set_flags(TIPC_BCLINK_RESET);
                l_ptr->stale_count = 0;
        }
 }
@@ -1352,7 +1345,7 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf,
                msg = buf_msg(buf);
                msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
                msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
-               tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
+               tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr);
                buf = buf->next;
                retransmits--;
                l_ptr->stats.retransmitted++;
@@ -1440,14 +1433,13 @@ static int link_recv_buf_validate(struct sk_buff *buf)
 /**
  * tipc_rcv - process TIPC packets/messages arriving from off-node
  * @head: pointer to message buffer chain
- * @tb_ptr: pointer to bearer message arrived on
+ * @b_ptr: pointer to bearer message arrived on
  *
  * Invoked with no locks held.  Bearer pointer must point to a valid bearer
  * structure (i.e. cannot be NULL), but bearer can be inactive.
  */
 void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
 {
-       read_lock_bh(&tipc_net_lock);
        while (head) {
                struct tipc_node *n_ptr;
                struct tipc_link *l_ptr;
@@ -1497,14 +1489,14 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                        goto unlock_discard;
 
                /* Verify that communication with node is currently allowed */
-               if ((n_ptr->block_setup & WAIT_PEER_DOWN) &&
-                       msg_user(msg) == LINK_PROTOCOL &&
-                       (msg_type(msg) == RESET_MSG ||
-                        msg_type(msg) == ACTIVATE_MSG) &&
-                       !msg_redundant_link(msg))
-                       n_ptr->block_setup &= ~WAIT_PEER_DOWN;
-
-               if (n_ptr->block_setup)
+               if ((n_ptr->flags & TIPC_NODE_DOWN) &&
+                   msg_user(msg) == LINK_PROTOCOL &&
+                   (msg_type(msg) == RESET_MSG ||
+                   msg_type(msg) == ACTIVATE_MSG) &&
+                   !msg_redundant_link(msg))
+                       n_ptr->flags &= ~TIPC_NODE_DOWN;
+
+               if (tipc_node_blocked(n_ptr))
                        goto unlock_discard;
 
                /* Validate message sequence number info */
@@ -1635,7 +1627,6 @@ unlock_discard:
 discard:
                kfree_skb(buf);
        }
-       read_unlock_bh(&tipc_net_lock);
 }
 
 /**
@@ -1747,12 +1738,12 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
                return;
 
        /* Abort non-RESET send if communication with node is prohibited */
-       if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG))
+       if ((tipc_node_blocked(l_ptr->owner)) && (msg_typ != RESET_MSG))
                return;
 
        /* Create protocol message with "out-of-sequence" sequence number */
        msg_set_type(msg, msg_typ);
-       msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
+       msg_set_net_plane(msg, l_ptr->net_plane);
        msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
        msg_set_last_bcast(msg, tipc_bclink_get_last_sent());
 
@@ -1818,7 +1809,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
        skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
        buf->priority = TC_PRIO_CONTROL;
 
-       tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
+       tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr);
        l_ptr->unacked_window = 0;
        kfree_skb(buf);
 }
@@ -1843,9 +1834,9 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
        /* record unnumbered packet arrival (force mismatch on next timeout) */
        l_ptr->checkpoint--;
 
-       if (l_ptr->b_ptr->net_plane != msg_net_plane(msg))
+       if (l_ptr->net_plane != msg_net_plane(msg))
                if (tipc_own_addr > msg_prevnode(msg))
-                       l_ptr->b_ptr->net_plane = msg_net_plane(msg);
+                       l_ptr->net_plane = msg_net_plane(msg);
 
        switch (msg_type(msg)) {
 
@@ -1862,7 +1853,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
                         * peer has lost contact -- don't allow peer's links
                         * to reactivate before we recognize loss & clean up
                         */
-                       l_ptr->owner->block_setup = WAIT_NODE_DOWN;
+                       l_ptr->owner->flags = TIPC_NODE_RESET;
                }
 
                link_state_event(l_ptr, RESET_MSG);
@@ -2397,8 +2388,6 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
 /* tipc_link_find_owner - locate owner node of link by link's name
  * @name: pointer to link name string
  * @bearer_id: pointer to index in 'node->links' array where the link was found.
- * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted;
- * this also prevents link deletion.
  *
  * Returns pointer to node owning the link, or 0 if no matching link is found.
  */
@@ -2460,7 +2449,7 @@ static int link_value_is_valid(u16 cmd, u32 new_value)
  * @new_value: new value of link, bearer, or media setting
  * @cmd: which link, bearer, or media attribute to set (TIPC_CMD_SET_LINK_*)
  *
- * Caller must hold 'tipc_net_lock' to ensure link/bearer/media is not deleted.
+ * Caller must hold RTNL lock to ensure link/bearer/media is not deleted.
  *
  * Returns 0 if value updated and negative value on error.
  */
@@ -2566,9 +2555,7 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space
                                                   " (cannot change setting on broadcast link)");
        }
 
-       read_lock_bh(&tipc_net_lock);
        res = link_cmd_set_value(args->name, new_value, cmd);
-       read_unlock_bh(&tipc_net_lock);
        if (res)
                return tipc_cfg_reply_error_string("cannot change link setting");
 
@@ -2602,22 +2589,18 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
                        return tipc_cfg_reply_error_string("link not found");
                return tipc_cfg_reply_none();
        }
-       read_lock_bh(&tipc_net_lock);
        node = tipc_link_find_owner(link_name, &bearer_id);
-       if (!node) {
-               read_unlock_bh(&tipc_net_lock);
+       if (!node)
                return tipc_cfg_reply_error_string("link not found");
-       }
+
        tipc_node_lock(node);
        l_ptr = node->links[bearer_id];
        if (!l_ptr) {
                tipc_node_unlock(node);
-               read_unlock_bh(&tipc_net_lock);
                return tipc_cfg_reply_error_string("link not found");
        }
        link_reset_statistics(l_ptr);
        tipc_node_unlock(node);
-       read_unlock_bh(&tipc_net_lock);
        return tipc_cfg_reply_none();
 }
 
@@ -2650,18 +2633,15 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
        if (!strcmp(name, tipc_bclink_name))
                return tipc_bclink_stats(buf, buf_size);
 
-       read_lock_bh(&tipc_net_lock);
        node = tipc_link_find_owner(name, &bearer_id);
-       if (!node) {
-               read_unlock_bh(&tipc_net_lock);
+       if (!node)
                return 0;
-       }
+
        tipc_node_lock(node);
 
        l = node->links[bearer_id];
        if (!l) {
                tipc_node_unlock(node);
-               read_unlock_bh(&tipc_net_lock);
                return 0;
        }
 
@@ -2727,7 +2707,6 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
                             (s->accu_queue_sz / s->queue_sz_counts) : 0);
 
        tipc_node_unlock(node);
-       read_unlock_bh(&tipc_net_lock);
        return ret;
 }
 
@@ -2778,7 +2757,6 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
        if (dest == tipc_own_addr)
                return MAX_MSG_SIZE;
 
-       read_lock_bh(&tipc_net_lock);
        n_ptr = tipc_node_find(dest);
        if (n_ptr) {
                tipc_node_lock(n_ptr);
@@ -2787,13 +2765,18 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
                        res = l_ptr->max_pkt;
                tipc_node_unlock(n_ptr);
        }
-       read_unlock_bh(&tipc_net_lock);
        return res;
 }
 
 static void link_print(struct tipc_link *l_ptr, const char *str)
 {
-       pr_info("%s Link %x<%s>:", str, l_ptr->addr, l_ptr->b_ptr->name);
+       struct tipc_bearer *b_ptr;
+
+       rcu_read_lock();
+       b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]);
+       if (b_ptr)
+               pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name);
+       rcu_read_unlock();
 
        if (link_working_unknown(l_ptr))
                pr_cont(":WU\n");
index 8c0b49b5b2ee6b0751f248cf740254a33e424c6a..7ba73fa6b81ea1aedc5061770dd3d7186a363e5c 100644 (file)
@@ -107,7 +107,7 @@ struct tipc_stats {
  * @checkpoint: reference point for triggering link continuity checking
  * @peer_session: link session # being used by peer end of link
  * @peer_bearer_id: bearer id used by link's peer endpoint
- * @b_ptr: pointer to bearer used by link
+ * @bearer_id: local bearer id used by link
  * @tolerance: minimum link continuity loss needed to reset link [in ms]
  * @continuity_interval: link continuity testing interval [in ms]
  * @abort_limit: # of unacknowledged continuity probes needed to reset link
@@ -116,6 +116,7 @@ struct tipc_stats {
  * @proto_msg: template for control messages generated by link
  * @pmsg: convenience pointer to "proto_msg" field
  * @priority: current link priority
+ * @net_plane: current link network plane ('A' through 'H')
  * @queue_limit: outbound message queue congestion thresholds (indexed by user)
  * @exp_msg_count: # of tunnelled messages expected during link changeover
  * @reset_checkpoint: seq # of last acknowledged message at time of link reset
@@ -155,7 +156,7 @@ struct tipc_link {
        u32 checkpoint;
        u32 peer_session;
        u32 peer_bearer_id;
-       struct tipc_bearer *b_ptr;
+       u32 bearer_id;
        u32 tolerance;
        u32 continuity_interval;
        u32 abort_limit;
@@ -167,6 +168,7 @@ struct tipc_link {
        } proto_msg;
        struct tipc_msg *pmsg;
        u32 priority;
+       char net_plane;
        u32 queue_limit[15];    /* queue_limit[0]==window limit */
 
        /* Changeover */
@@ -228,6 +230,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area,
                                         int req_tlv_space);
 struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area,
                                          int req_tlv_space);
+void tipc_link_reset_all(struct tipc_node *node);
 void tipc_link_reset(struct tipc_link *l_ptr);
 void tipc_link_reset_list(unsigned int bearer_id);
 int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector);
index aff8041dc1573e3fea829e286e2675e322350b2e..8ce730984aa1f0d429b2325d58862e1ef7799d4d 100644 (file)
 #include "link.h"
 #include "name_distr.h"
 
-#define ITEM_SIZE sizeof(struct distr_item)
-
-/**
- * struct distr_item - publication info distributed to other nodes
- * @type: name sequence type
- * @lower: name sequence lower bound
- * @upper: name sequence upper bound
- * @ref: publishing port reference
- * @key: publication key
- *
- * ===> All fields are stored in network byte order. <===
- *
- * First 3 fields identify (name or) name sequence being published.
- * Reference field uniquely identifies port that published name sequence.
- * Key field uniquely identifies publication, in the event a port has
- * multiple publications of the same name sequence.
- *
- * Note: There is no field that identifies the publishing node because it is
- * the same for all items contained within a publication message.
- */
-struct distr_item {
-       __be32 type;
-       __be32 lower;
-       __be32 upper;
-       __be32 ref;
-       __be32 key;
-};
-
 /**
  * struct publ_list - list of publications made by this node
  * @list: circular list of publications
@@ -127,7 +99,7 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
        return buf;
 }
 
-static void named_cluster_distribute(struct sk_buff *buf)
+void named_cluster_distribute(struct sk_buff *buf)
 {
        struct sk_buff *buf_copy;
        struct tipc_node *n_ptr;
@@ -135,18 +107,18 @@ static void named_cluster_distribute(struct sk_buff *buf)
 
        rcu_read_lock();
        list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
-               spin_lock_bh(&n_ptr->lock);
+               tipc_node_lock(n_ptr);
                l_ptr = n_ptr->active_links[n_ptr->addr & 1];
                if (l_ptr) {
                        buf_copy = skb_copy(buf, GFP_ATOMIC);
                        if (!buf_copy) {
-                               spin_unlock_bh(&n_ptr->lock);
+                               tipc_node_unlock(n_ptr);
                                break;
                        }
                        msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
                        __tipc_link_xmit(l_ptr, buf_copy);
                }
-               spin_unlock_bh(&n_ptr->lock);
+               tipc_node_unlock(n_ptr);
        }
        rcu_read_unlock();
 
@@ -156,7 +128,7 @@ static void named_cluster_distribute(struct sk_buff *buf)
 /**
  * tipc_named_publish - tell other nodes about a new publication by this node
  */
-void tipc_named_publish(struct publication *publ)
+struct sk_buff *tipc_named_publish(struct publication *publ)
 {
        struct sk_buff *buf;
        struct distr_item *item;
@@ -165,23 +137,23 @@ void tipc_named_publish(struct publication *publ)
        publ_lists[publ->scope]->size++;
 
        if (publ->scope == TIPC_NODE_SCOPE)
-               return;
+               return NULL;
 
        buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
        if (!buf) {
                pr_warn("Publication distribution failure\n");
-               return;
+               return NULL;
        }
 
        item = (struct distr_item *)msg_data(buf_msg(buf));
        publ_to_item(item, publ);
-       named_cluster_distribute(buf);
+       return buf;
 }
 
 /**
  * tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
  */
-void tipc_named_withdraw(struct publication *publ)
+struct sk_buff *tipc_named_withdraw(struct publication *publ)
 {
        struct sk_buff *buf;
        struct distr_item *item;
@@ -190,17 +162,17 @@ void tipc_named_withdraw(struct publication *publ)
        publ_lists[publ->scope]->size--;
 
        if (publ->scope == TIPC_NODE_SCOPE)
-               return;
+               return NULL;
 
        buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
        if (!buf) {
                pr_warn("Withdrawal distribution failure\n");
-               return;
+               return NULL;
        }
 
        item = (struct distr_item *)msg_data(buf_msg(buf));
        publ_to_item(item, publ);
-       named_cluster_distribute(buf);
+       return buf;
 }
 
 /*
@@ -239,31 +211,9 @@ static void named_distribute(struct list_head *message_list, u32 node,
 /**
  * tipc_named_node_up - tell specified node about all publications by this node
  */
-void tipc_named_node_up(unsigned long nodearg)
+void tipc_named_node_up(u32 max_item_buf, u32 node)
 {
-       struct tipc_node *n_ptr;
-       struct tipc_link *l_ptr;
-       struct list_head message_list;
-       u32 node = (u32)nodearg;
-       u32 max_item_buf = 0;
-
-       /* compute maximum amount of publication data to send per message */
-       read_lock_bh(&tipc_net_lock);
-       n_ptr = tipc_node_find(node);
-       if (n_ptr) {
-               tipc_node_lock(n_ptr);
-               l_ptr = n_ptr->active_links[0];
-               if (l_ptr)
-                       max_item_buf = ((l_ptr->max_pkt - INT_H_SIZE) /
-                               ITEM_SIZE) * ITEM_SIZE;
-               tipc_node_unlock(n_ptr);
-       }
-       read_unlock_bh(&tipc_net_lock);
-       if (!max_item_buf)
-               return;
-
-       /* create list of publication messages, then send them as a unit */
-       INIT_LIST_HEAD(&message_list);
+       LIST_HEAD(message_list);
 
        read_lock_bh(&tipc_nametbl_lock);
        named_distribute(&message_list, node, &publ_cluster, max_item_buf);
index 9b312ccfd43e7da41bcab4ca33d5f0f4d5be86cf..b2eed4ec1526a34efd8b191e4b952bf9718f7a2e 100644 (file)
 
 #include "name_table.h"
 
-void tipc_named_publish(struct publication *publ);
-void tipc_named_withdraw(struct publication *publ);
-void tipc_named_node_up(unsigned long node);
+#define ITEM_SIZE sizeof(struct distr_item)
+
+/**
+ * struct distr_item - publication info distributed to other nodes
+ * @type: name sequence type
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @ref: publishing port reference
+ * @key: publication key
+ *
+ * ===> All fields are stored in network byte order. <===
+ *
+ * First 3 fields identify (name or) name sequence being published.
+ * Reference field uniquely identifies port that published name sequence.
+ * Key field uniquely identifies publication, in the event a port has
+ * multiple publications of the same name sequence.
+ *
+ * Note: There is no field that identifies the publishing node because it is
+ * the same for all items contained within a publication message.
+ */
+struct distr_item {
+       __be32 type;
+       __be32 lower;
+       __be32 upper;
+       __be32 ref;
+       __be32 key;
+};
+
+struct sk_buff *tipc_named_publish(struct publication *publ);
+struct sk_buff *tipc_named_withdraw(struct publication *publ);
+void named_cluster_distribute(struct sk_buff *buf);
+void tipc_named_node_up(u32 max_item_buf, u32 node);
 void tipc_named_rcv(struct sk_buff *buf);
 void tipc_named_reinit(void);
 
index 042e8e3cabc09f84aa5dce626c57a30faf3ca32d..9d7d37d95187c77d9d7490ce7aec4de147a9f2fd 100644 (file)
@@ -664,6 +664,7 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
                                         u32 scope, u32 port_ref, u32 key)
 {
        struct publication *publ;
+       struct sk_buff *buf = NULL;
 
        if (table.local_publ_count >= TIPC_MAX_PUBLICATIONS) {
                pr_warn("Publication failed, local publication limit reached (%u)\n",
@@ -676,9 +677,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
                                   tipc_own_addr, port_ref, key);
        if (likely(publ)) {
                table.local_publ_count++;
-               tipc_named_publish(publ);
+               buf = tipc_named_publish(publ);
        }
        write_unlock_bh(&tipc_nametbl_lock);
+
+       if (buf)
+               named_cluster_distribute(buf);
        return publ;
 }
 
@@ -688,15 +692,19 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
 int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
 {
        struct publication *publ;
+       struct sk_buff *buf;
 
        write_lock_bh(&tipc_nametbl_lock);
        publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
        if (likely(publ)) {
                table.local_publ_count--;
-               tipc_named_withdraw(publ);
+               buf = tipc_named_withdraw(publ);
                write_unlock_bh(&tipc_nametbl_lock);
                list_del_init(&publ->pport_list);
                kfree(publ);
+
+               if (buf)
+                       named_cluster_distribute(buf);
                return 1;
        }
        write_unlock_bh(&tipc_nametbl_lock);
@@ -961,6 +969,7 @@ static void tipc_purge_publications(struct name_seq *seq)
        list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
                tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
                                         publ->ref, publ->key);
+               kfree(publ);
        }
 }
 
@@ -982,7 +991,6 @@ void tipc_nametbl_stop(void)
                hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
                        tipc_purge_publications(seq);
                }
-               continue;
        }
        kfree(table.types);
        table.types = NULL;
index 4c564eb69e1ad9bd2695e78eb91464a0112e663c..f8fc95d58c0d9192c2f0a26e809de736d20b3430 100644 (file)
 /*
  * The TIPC locking policy is designed to ensure a very fine locking
  * granularity, permitting complete parallel access to individual
- * port and node/link instances. The code consists of three major
+ * port and node/link instances. The code consists of four major
  * locking domains, each protected with their own disjunct set of locks.
  *
- * 1: The routing hierarchy.
- *    Comprises the structures 'zone', 'cluster', 'node', 'link'
- *    and 'bearer'. The whole hierarchy is protected by a big
- *    read/write lock, tipc_net_lock, to enssure that nothing is added
- *    or removed while code is accessing any of these structures.
- *    This layer must not be called from the two others while they
- *    hold any of their own locks.
- *    Neither must it itself do any upcalls to the other two before
- *    it has released tipc_net_lock and other protective locks.
+ * 1: The bearer level.
+ *    RTNL lock is used to serialize the process of configuring bearer
+ *    on update side, and RCU lock is applied on read side to make
+ *    bearer instance valid on both paths of message transmission and
+ *    reception.
  *
- *   Within the tipc_net_lock domain there are two sub-domains;'node' and
- *   'bearer', where local write operations are permitted,
- *   provided that those are protected by individual spin_locks
- *   per instance. Code holding tipc_net_lock(read) and a node spin_lock
- *   is permitted to poke around in both the node itself and its
- *   subordinate links. I.e, it can update link counters and queues,
- *   change link state, send protocol messages, and alter the
- *   "active_links" array in the node; but it can _not_ remove a link
- *   or a node from the overall structure.
- *   Correspondingly, individual bearers may change status within a
- *   tipc_net_lock(read), protected by an individual spin_lock ber bearer
- *   instance, but it needs tipc_net_lock(write) to remove/add any bearers.
+ * 2: The node and link level.
+ *    All node instances are saved into two tipc_node_list and node_htable
+ *    lists. The two lists are protected by node_list_lock on write side,
+ *    and they are guarded with RCU lock on read side. Especially node
+ *    instance is destroyed only when TIPC module is removed, and we can
+ *    confirm that there has no any user who is accessing the node at the
+ *    moment. Therefore, Except for iterating the two lists within RCU
+ *    protection, it's no needed to hold RCU that we access node instance
+ *    in other places.
  *
+ *    In addition, all members in node structure including link instances
+ *    are protected by node spin lock.
  *
- *  2: The transport level of the protocol.
- *     This consists of the structures port, (and its user level
- *     representations, such as user_port and tipc_sock), reference and
- *     tipc_user (port.c, reg.c, socket.c).
+ * 3: The transport level of the protocol.
+ *    This consists of the structures port, (and its user level
+ *    representations, such as user_port and tipc_sock), reference and
+ *    tipc_user (port.c, reg.c, socket.c).
  *
- *     This layer has four different locks:
+ *    This layer has four different locks:
  *     - The tipc_port spin_lock. This is protecting each port instance
  *       from parallel data access and removal. Since we can not place
  *       this lock in the port itself, it has been placed in the
@@ -96,7 +91,7 @@
  *       There are two such lists; 'port_list', which is used for management,
  *       and 'wait_list', which is used to queue ports during congestion.
  *
- *  3: The name table (name_table.c, name_distr.c, subscription.c)
+ *  4: The name table (name_table.c, name_distr.c, subscription.c)
  *     - There is one big read/write-lock (tipc_nametbl_lock) protecting the
  *       overall name table structure. Nothing must be added/removed to
  *       this structure without holding write access to it.
  *     - A local spin_lock protecting the queue of subscriber events.
 */
 
-DEFINE_RWLOCK(tipc_net_lock);
-
 static void net_route_named_msg(struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
@@ -171,22 +164,25 @@ void tipc_net_route_msg(struct sk_buff *buf)
        tipc_link_xmit(buf, dnode, msg_link_selector(msg));
 }
 
-void tipc_net_start(u32 addr)
+int tipc_net_start(u32 addr)
 {
        char addr_string[16];
+       int res;
 
-       write_lock_bh(&tipc_net_lock);
        tipc_own_addr = addr;
        tipc_named_reinit();
        tipc_port_reinit();
-       tipc_bclink_init();
-       write_unlock_bh(&tipc_net_lock);
+       res = tipc_bclink_init();
+       if (res)
+               return res;
 
        tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr,
                             TIPC_ZONE_SCOPE, 0, tipc_own_addr);
+
        pr_info("Started in network mode\n");
        pr_info("Own node address %s, network identity %u\n",
                tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
+       return 0;
 }
 
 void tipc_net_stop(void)
@@ -195,11 +191,11 @@ void tipc_net_stop(void)
                return;
 
        tipc_nametbl_withdraw(TIPC_CFG_SRV, tipc_own_addr, 0, tipc_own_addr);
-       write_lock_bh(&tipc_net_lock);
+       rtnl_lock();
        tipc_bearer_stop();
        tipc_bclink_stop();
        tipc_node_stop();
-       write_unlock_bh(&tipc_net_lock);
+       rtnl_unlock();
 
        pr_info("Left network mode\n");
 }
index 079daadb3f7286471cd5146798f6b06328bf99ad..c6c2b46f7c283095c4e29c7e0b11c5cdea2bcc01 100644 (file)
 #ifndef _TIPC_NET_H
 #define _TIPC_NET_H
 
-extern rwlock_t tipc_net_lock;
-
 void tipc_net_route_msg(struct sk_buff *buf);
 
-void tipc_net_start(u32 addr);
+int tipc_net_start(u32 addr);
 void tipc_net_stop(void);
 
 #endif
index 3aaf73de9e2d017e96b3cc1124d5c9420d827abd..ad844d3653409a6f5ad2ceac53e1b52dc48eacaa 100644 (file)
@@ -47,7 +47,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
        int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
        u16 cmd;
 
-       if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
+       if ((req_userhdr->cmd & 0xC000) && (!netlink_capable(skb, CAP_NET_ADMIN)))
                cmd = TIPC_CMD_NOT_NET_ADMIN;
        else
                cmd = req_userhdr->cmd;
index 1d3a4999a70ff96a751f3908d0d8e274af63a962..74efebc1cb7a030c7d2674f070852ffcf87a234a 100644 (file)
@@ -108,7 +108,7 @@ struct tipc_node *tipc_node_create(u32 addr)
                        break;
        }
        list_add_tail_rcu(&n_ptr->list, &temp_node->list);
-       n_ptr->block_setup = WAIT_PEER_DOWN;
+       n_ptr->flags = TIPC_NODE_DOWN;
        n_ptr->signature = INVALID_NODE_SIG;
 
        tipc_num_nodes++;
@@ -144,11 +144,13 @@ void tipc_node_stop(void)
 void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 {
        struct tipc_link **active = &n_ptr->active_links[0];
+       u32 addr = n_ptr->addr;
 
        n_ptr->working_links++;
-
+       tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, TIPC_NODE_SCOPE,
+                            l_ptr->bearer_id, addr);
        pr_info("Established link <%s> on network plane %c\n",
-               l_ptr->name, l_ptr->b_ptr->net_plane);
+               l_ptr->name, l_ptr->net_plane);
 
        if (!active[0]) {
                active[0] = active[1] = l_ptr;
@@ -203,16 +205,18 @@ static void node_select_active_links(struct tipc_node *n_ptr)
 void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 {
        struct tipc_link **active;
+       u32 addr = n_ptr->addr;
 
        n_ptr->working_links--;
+       tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, l_ptr->bearer_id, addr);
 
        if (!tipc_link_is_active(l_ptr)) {
                pr_info("Lost standby link <%s> on network plane %c\n",
-                       l_ptr->name, l_ptr->b_ptr->net_plane);
+                       l_ptr->name, l_ptr->net_plane);
                return;
        }
        pr_info("Lost link <%s> on network plane %c\n",
-               l_ptr->name, l_ptr->b_ptr->net_plane);
+               l_ptr->name, l_ptr->net_plane);
 
        active = &n_ptr->active_links[0];
        if (active[0] == l_ptr)
@@ -239,7 +243,7 @@ int tipc_node_is_up(struct tipc_node *n_ptr)
 
 void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 {
-       n_ptr->links[l_ptr->b_ptr->identity] = l_ptr;
+       n_ptr->links[l_ptr->bearer_id] = l_ptr;
        spin_lock_bh(&node_list_lock);
        tipc_num_links++;
        spin_unlock_bh(&node_list_lock);
@@ -263,26 +267,12 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 
 static void node_established_contact(struct tipc_node *n_ptr)
 {
-       tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
+       n_ptr->flags |= TIPC_NODE_UP;
        n_ptr->bclink.oos_state = 0;
        n_ptr->bclink.acked = tipc_bclink_get_last_sent();
        tipc_bclink_add_node(n_ptr->addr);
 }
 
-static void node_name_purge_complete(unsigned long node_addr)
-{
-       struct tipc_node *n_ptr;
-
-       read_lock_bh(&tipc_net_lock);
-       n_ptr = tipc_node_find(node_addr);
-       if (n_ptr) {
-               tipc_node_lock(n_ptr);
-               n_ptr->block_setup &= ~WAIT_NAMES_GONE;
-               tipc_node_unlock(n_ptr);
-       }
-       read_unlock_bh(&tipc_net_lock);
-}
-
 static void node_lost_contact(struct tipc_node *n_ptr)
 {
        char addr_string[16];
@@ -318,12 +308,10 @@ static void node_lost_contact(struct tipc_node *n_ptr)
                tipc_link_reset_fragments(l_ptr);
        }
 
-       /* Notify subscribers */
-       tipc_nodesub_notify(n_ptr);
-
-       /* Prevent re-contact with node until cleanup is done */
-       n_ptr->block_setup = WAIT_PEER_DOWN | WAIT_NAMES_GONE;
-       tipc_k_signal((Handler)node_name_purge_complete, n_ptr->addr);
+       /* Notify subscribers and prevent re-contact with node until
+        * cleanup is done.
+        */
+       n_ptr->flags = TIPC_NODE_DOWN | TIPC_NODE_LOST;
 }
 
 struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
@@ -436,3 +424,63 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
        rcu_read_unlock();
        return buf;
 }
+
+/**
+ * tipc_node_get_linkname - get the name of a link
+ *
+ * @bearer_id: id of the bearer
+ * @node: peer node address
+ * @linkname: link name output buffer
+ *
+ * Returns 0 on success
+ */
+int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
+{
+       struct tipc_link *link;
+       struct tipc_node *node = tipc_node_find(addr);
+
+       if ((bearer_id >= MAX_BEARERS) || !node)
+               return -EINVAL;
+       tipc_node_lock(node);
+       link = node->links[bearer_id];
+       if (link) {
+               strncpy(linkname, link->name, len);
+               tipc_node_unlock(node);
+               return 0;
+       }
+       tipc_node_unlock(node);
+       return -EINVAL;
+}
+
+void tipc_node_unlock(struct tipc_node *node)
+{
+       LIST_HEAD(nsub_list);
+       struct tipc_link *link;
+       int pkt_sz = 0;
+       u32 addr = 0;
+
+       if (likely(!node->flags)) {
+               spin_unlock_bh(&node->lock);
+               return;
+       }
+
+       if (node->flags & TIPC_NODE_LOST) {
+               list_replace_init(&node->nsub, &nsub_list);
+               node->flags &= ~TIPC_NODE_LOST;
+       }
+       if (node->flags & TIPC_NODE_UP) {
+               link = node->active_links[0];
+               node->flags &= ~TIPC_NODE_UP;
+               if (link) {
+                       pkt_sz = ((link->max_pkt - INT_H_SIZE) / ITEM_SIZE) *
+                                 ITEM_SIZE;
+                       addr = node->addr;
+               }
+       }
+       spin_unlock_bh(&node->lock);
+
+       if (!list_empty(&nsub_list))
+               tipc_nodesub_notify(&nsub_list);
+       if (pkt_sz)
+               tipc_named_node_up(pkt_sz, addr);
+}
index 7cbb8cec1a932f881cd636a71edb0342070530ae..38f710fb75dc0290fb5d4b807646ab766febcef5 100644 (file)
  */
 #define INVALID_NODE_SIG 0x10000
 
-/* Flags used to block (re)establishment of contact with a neighboring node */
-#define WAIT_PEER_DOWN 0x0001  /* wait to see that peer's links are down */
-#define WAIT_NAMES_GONE        0x0002  /* wait for peer's publications to be purged */
-#define WAIT_NODE_DOWN 0x0004  /* wait until peer node is declared down */
+/* Flags used to block (re)establishment of contact with a neighboring node
+ * TIPC_NODE_DOWN: indicate node is down and it's used to block the node's
+ *                 links until RESET or ACTIVE message arrives
+ * TIPC_NODE_RESET: indicate node is reset
+ * TIPC_NODE_LOST: indicate node is lost and it's used to notify subscriptions
+ *                 when node lock is released
+ * TIPC_NODE_UP: indicate node is up and it's used to deliver local name table
+ *               when node lock is released
+ */
+enum {
+       TIPC_NODE_DOWN  = (1 << 1),
+       TIPC_NODE_RESET = (1 << 2),
+       TIPC_NODE_LOST  = (1 << 3),
+       TIPC_NODE_UP    = (1 << 4)
+};
+
+/**
+ * struct tipc_node_bclink - TIPC node bclink structure
+ * @acked: sequence # of last outbound b'cast message acknowledged by node
+ * @last_in: sequence # of last in-sequence b'cast message received from node
+ * @last_sent: sequence # of last b'cast message sent by node
+ * @oos_state: state tracker for handling OOS b'cast messages
+ * @deferred_size: number of OOS b'cast messages in deferred queue
+ * @deferred_head: oldest OOS b'cast message received from node
+ * @deferred_tail: newest OOS b'cast message received from node
+ * @reasm_head: broadcast reassembly queue head from node
+ * @reasm_tail: last broadcast fragment received from node
+ * @recv_permitted: true if node is allowed to receive b'cast messages
+ */
+struct tipc_node_bclink {
+       u32 acked;
+       u32 last_in;
+       u32 last_sent;
+       u32 oos_state;
+       u32 deferred_size;
+       struct sk_buff *deferred_head;
+       struct sk_buff *deferred_tail;
+       struct sk_buff *reasm_head;
+       struct sk_buff *reasm_tail;
+       bool recv_permitted;
+};
 
 /**
  * struct tipc_node - TIPC node structure
  * @addr: network address of node
  * @lock: spinlock governing access to structure
  * @hash: links to adjacent nodes in unsorted hash chain
- * @list: links to adjacent nodes in sorted list of cluster's nodes
- * @nsub: list of "node down" subscriptions monitoring node
  * @active_links: pointers to active links to node
  * @links: pointers to all links to node
+ * @flags: bit mask of conditions preventing link establishment to node
+ * @bclink: broadcast-related info
+ * @list: links to adjacent nodes in sorted list of cluster's nodes
  * @working_links: number of working links to node (both active and standby)
- * @block_setup: bit mask of conditions preventing link establishment to node
  * @link_cnt: number of links to node
  * @signature: node instance identifier
- * @bclink: broadcast-related info
+ * @nsub: list of "node down" subscriptions monitoring node
  * @rcu: rcu struct for tipc_node
- *    @acked: sequence # of last outbound b'cast message acknowledged by node
- *    @last_in: sequence # of last in-sequence b'cast message received from node
- *    @last_sent: sequence # of last b'cast message sent by node
- *    @oos_state: state tracker for handling OOS b'cast messages
- *    @deferred_size: number of OOS b'cast messages in deferred queue
- *    @deferred_head: oldest OOS b'cast message received from node
- *    @deferred_tail: newest OOS b'cast message received from node
- *    @reasm_head: broadcast reassembly queue head from node
- *    @reasm_tail: last broadcast fragment received from node
- *    @recv_permitted: true if node is allowed to receive b'cast messages
  */
 struct tipc_node {
        u32 addr;
        spinlock_t lock;
        struct hlist_node hash;
-       struct list_head list;
-       struct list_head nsub;
        struct tipc_link *active_links[2];
        struct tipc_link *links[MAX_BEARERS];
+       unsigned int flags;
+       struct tipc_node_bclink bclink;
+       struct list_head list;
        int link_cnt;
        int working_links;
-       int block_setup;
        u32 signature;
+       struct list_head nsub;
        struct rcu_head rcu;
-       struct {
-               u32 acked;
-               u32 last_in;
-               u32 last_sent;
-               u32 oos_state;
-               u32 deferred_size;
-               struct sk_buff *deferred_head;
-               struct sk_buff *deferred_tail;
-               struct sk_buff *reasm_head;
-               struct sk_buff *reasm_tail;
-               bool recv_permitted;
-       } bclink;
 };
 
 extern struct list_head tipc_node_list;
@@ -118,15 +134,18 @@ int tipc_node_active_links(struct tipc_node *n_ptr);
 int tipc_node_is_up(struct tipc_node *n_ptr);
 struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space);
 struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
+int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);
+void tipc_node_unlock(struct tipc_node *node);
 
-static inline void tipc_node_lock(struct tipc_node *n_ptr)
+static inline void tipc_node_lock(struct tipc_node *node)
 {
-       spin_lock_bh(&n_ptr->lock);
+       spin_lock_bh(&node->lock);
 }
 
-static inline void tipc_node_unlock(struct tipc_node *n_ptr)
+static inline bool tipc_node_blocked(struct tipc_node *node)
 {
-       spin_unlock_bh(&n_ptr->lock);
+       return (node->flags & (TIPC_NODE_DOWN | TIPC_NODE_LOST |
+               TIPC_NODE_RESET));
 }
 
 #endif
index 8a7384c04add4bdc6db6ae4451ebb2232e4b338b..7c59ab1d6ecb3dc26c4efb77cd243a00341c7b5b 100644 (file)
@@ -81,14 +81,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub)
  *
  * Note: node is locked by caller
  */
-void tipc_nodesub_notify(struct tipc_node *node)
+void tipc_nodesub_notify(struct list_head *nsub_list)
 {
-       struct tipc_node_subscr *ns;
+       struct tipc_node_subscr *ns, *safe;
 
-       list_for_each_entry(ns, &node->nsub, nodesub_list) {
+       list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) {
                if (ns->handle_node_down) {
-                       tipc_k_signal((Handler)ns->handle_node_down,
-                                     (unsigned long)ns->usr_handle);
+                       ns->handle_node_down(ns->usr_handle);
                        ns->handle_node_down = NULL;
                }
        }
index c95d20727ded3ea70cf9532a82cd8ff20fde415d..d91b8cc81e3d786948bd4ed9ac622689c4218ea1 100644 (file)
@@ -58,6 +58,6 @@ struct tipc_node_subscr {
 void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
                            void *usr_handle, net_ev_handler handle_down);
 void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub);
-void tipc_nodesub_notify(struct tipc_node *node);
+void tipc_nodesub_notify(struct list_head *nsub_list);
 
 #endif
index 3c0256962f7dafa4ee3b11d69aed963822c888c2..3f9912f87d0d1744a14ac3dbd9dd61cf9aa545c1 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "core.h"
 #include "port.h"
+#include "node.h"
 
 #include <linux/export.h>
 
@@ -1905,6 +1906,28 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
        return put_user(sizeof(value), ol);
 }
 
+int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg)
+{
+       struct tipc_sioc_ln_req lnr;
+       void __user *argp = (void __user *)arg;
+
+       switch (cmd) {
+       case SIOCGETLINKNAME:
+               if (copy_from_user(&lnr, argp, sizeof(lnr)))
+                       return -EFAULT;
+               if (!tipc_node_get_linkname(lnr.bearer_id, lnr.peer,
+                                           lnr.linkname, TIPC_MAX_LINK_NAME)) {
+                       if (copy_to_user(argp, &lnr, sizeof(lnr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               return -EADDRNOTAVAIL;
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
 /* Protocol switches for the various types of TIPC sockets */
 
 static const struct proto_ops msg_ops = {
@@ -1917,7 +1940,7 @@ static const struct proto_ops msg_ops = {
        .accept         = sock_no_accept,
        .getname        = tipc_getname,
        .poll           = tipc_poll,
-       .ioctl          = sock_no_ioctl,
+       .ioctl          = tipc_ioctl,
        .listen         = sock_no_listen,
        .shutdown       = tipc_shutdown,
        .setsockopt     = tipc_setsockopt,
@@ -1938,7 +1961,7 @@ static const struct proto_ops packet_ops = {
        .accept         = tipc_accept,
        .getname        = tipc_getname,
        .poll           = tipc_poll,
-       .ioctl          = sock_no_ioctl,
+       .ioctl          = tipc_ioctl,
        .listen         = tipc_listen,
        .shutdown       = tipc_shutdown,
        .setsockopt     = tipc_setsockopt,
@@ -1959,7 +1982,7 @@ static const struct proto_ops stream_ops = {
        .accept         = tipc_accept,
        .getname        = tipc_getname,
        .poll           = tipc_poll,
-       .ioctl          = sock_no_ioctl,
+       .ioctl          = tipc_ioctl,
        .listen         = tipc_listen,
        .shutdown       = tipc_shutdown,
        .setsockopt     = tipc_setsockopt,
index 5adfd94c5b85d3d48a6d48d3a4c7c2fa98526d8b..85d232bed87d21f3c23cd695b83defef5a6f22c1 100644 (file)
@@ -1925,9 +1925,23 @@ static struct miscdevice vsock_device = {
        .fops           = &vsock_device_ops,
 };
 
-static int __vsock_core_init(void)
+int __vsock_core_init(const struct vsock_transport *t, struct module *owner)
 {
-       int err;
+       int err = mutex_lock_interruptible(&vsock_register_mutex);
+
+       if (err)
+               return err;
+
+       if (transport) {
+               err = -EBUSY;
+               goto err_busy;
+       }
+
+       /* Transport must be the owner of the protocol so that it can't
+        * unload while there are open sockets.
+        */
+       vsock_proto.owner = owner;
+       transport = t;
 
        vsock_init_tables();
 
@@ -1951,36 +1965,19 @@ static int __vsock_core_init(void)
                goto err_unregister_proto;
        }
 
+       mutex_unlock(&vsock_register_mutex);
        return 0;
 
 err_unregister_proto:
        proto_unregister(&vsock_proto);
 err_misc_deregister:
        misc_deregister(&vsock_device);
-       return err;
-}
-
-int vsock_core_init(const struct vsock_transport *t)
-{
-       int retval = mutex_lock_interruptible(&vsock_register_mutex);
-       if (retval)
-               return retval;
-
-       if (transport) {
-               retval = -EBUSY;
-               goto out;
-       }
-
-       transport = t;
-       retval = __vsock_core_init();
-       if (retval)
-               transport = NULL;
-
-out:
+       transport = NULL;
+err_busy:
        mutex_unlock(&vsock_register_mutex);
-       return retval;
+       return err;
 }
-EXPORT_SYMBOL_GPL(vsock_core_init);
+EXPORT_SYMBOL_GPL(__vsock_core_init);
 
 void vsock_core_exit(void)
 {
@@ -2000,5 +1997,5 @@ EXPORT_SYMBOL_GPL(vsock_core_exit);
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Socket Family");
-MODULE_VERSION("1.0.0.0-k");
+MODULE_VERSION("1.0.1.0-k");
 MODULE_LICENSE("GPL v2");
index 16d08b39921071479456e2033c5e371d381175b7..405f3c4cf70ca3617a4101e1bad278b93d7ae1b7 100644 (file)
@@ -95,6 +95,43 @@ config CFG80211_CERTIFICATION_ONUS
          you are a wireless researcher and are working in a controlled
          and approved environment by your local regulatory agency.
 
+config CFG80211_REG_CELLULAR_HINTS
+       bool "cfg80211 regulatory support for cellular base station hints"
+       depends on CFG80211_CERTIFICATION_ONUS
+       ---help---
+         This option enables support for parsing regulatory hints
+         from cellular base stations. If enabled and at least one driver
+         claims support for parsing cellular base station hints the
+         regulatory core will allow and parse these regulatory hints.
+         The regulatory core will only apply these regulatory hints on
+         drivers that support this feature. You should only enable this
+         feature if you have tested and validated this feature on your
+         systems.
+
+config CFG80211_REG_RELAX_NO_IR
+       bool "cfg80211 support for NO_IR relaxation"
+       depends on CFG80211_CERTIFICATION_ONUS
+       ---help---
+        This option enables support for relaxation of the NO_IR flag for
+        situations that certain regulatory bodies have provided clarifications
+        on how relaxation can occur. This feature has an inherent dependency on
+        userspace features which must have been properly tested and as such is
+        not enabled by default.
+
+        A relaxation feature example is allowing the operation of a P2P group
+        owner (GO) on channels marked with NO_IR if there is an additional BSS
+        interface which associated to an AP which userspace assumes or confirms
+        to be an authorized master, i.e., with radar detection support and DFS
+        capabilities. However, note that in order to not create daisy chain
+        scenarios, this relaxation is not allowed in cases that the BSS client
+        is associated to P2P GO and in addition the P2P GO instantiated on
+        a channel due to this relaxation should not allow connection from
+        non P2P clients.
+
+        The regulatory core will apply these relaxations only for drivers that
+        support this feature by declaring the appropriate channel flags and
+        capabilities in their registration flow.
+
 config CFG80211_DEFAULT_PS
        bool "enable powersave by default"
        depends on CFG80211
index 9c9501a35fb5c6a43a142132306998405e086774..84d686e2dbd04a0402a652995ec468ba6df06795 100644 (file)
@@ -326,28 +326,57 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
 
 
 int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-                                 const struct cfg80211_chan_def *chandef)
+                                 const struct cfg80211_chan_def *chandef,
+                                 enum nl80211_iftype iftype)
 {
        int width;
-       int r;
+       int ret;
 
        if (WARN_ON(!cfg80211_chandef_valid(chandef)))
                return -EINVAL;
 
-       width = cfg80211_chandef_get_width(chandef);
-       if (width < 0)
-               return -EINVAL;
+       switch (iftype) {
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_MESH_POINT:
+               width = cfg80211_chandef_get_width(chandef);
+               if (width < 0)
+                       return -EINVAL;
 
-       r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
-                                           width);
-       if (r)
-               return r;
+               ret = cfg80211_get_chans_dfs_required(wiphy,
+                                                     chandef->center_freq1,
+                                                     width);
+               if (ret < 0)
+                       return ret;
+               else if (ret > 0)
+                       return BIT(chandef->width);
 
-       if (!chandef->center_freq2)
-               return 0;
+               if (!chandef->center_freq2)
+                       return 0;
+
+               ret = cfg80211_get_chans_dfs_required(wiphy,
+                                                     chandef->center_freq2,
+                                                     width);
+               if (ret < 0)
+                       return ret;
+               else if (ret > 0)
+                       return BIT(chandef->width);
 
-       return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
-                                              width);
+               break;
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_WDS:
+       case NL80211_IFTYPE_P2P_DEVICE:
+       case NL80211_IFTYPE_UNSPECIFIED:
+               break;
+       case NUM_NL80211_IFTYPES:
+               WARN_ON(1);
+       }
+
+       return 0;
 }
 EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
@@ -587,12 +616,14 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                width = 5;
                break;
        case NL80211_CHAN_WIDTH_10:
+               prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
                width = 10;
                break;
        case NL80211_CHAN_WIDTH_20:
                if (!ht_cap->ht_supported)
                        return false;
        case NL80211_CHAN_WIDTH_20_NOHT:
+               prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
                width = 20;
                break;
        case NL80211_CHAN_WIDTH_40:
@@ -661,17 +692,112 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_chandef_usable);
 
+/*
+ * For GO only, check if the channel can be used under permissive conditions
+ * mandated by the some regulatory bodies, i.e., the channel is marked with
+ * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
+ * associated to an AP on the same channel or on the same UNII band
+ * (assuming that the AP is an authorized master).
+ * In addition allow the GO to operate on a channel on which indoor operation is
+ * allowed, iff we are currently operating in an indoor environment.
+ */
+static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
+                                       struct ieee80211_channel *chan)
+{
+       struct wireless_dev *wdev_iter;
+       struct wiphy *wiphy = wiphy_idx_to_wiphy(rdev->wiphy_idx);
+
+       ASSERT_RTNL();
+
+       if (!config_enabled(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
+           !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
+               return false;
+
+       if (regulatory_indoor_allowed() &&
+           (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
+               return true;
+
+       if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
+               return false;
+
+       /*
+        * Generally, it is possible to rely on another device/driver to allow
+        * the GO concurrent relaxation, however, since the device can further
+        * enforce the relaxation (by doing a similar verifications as this),
+        * and thus fail the GO instantiation, consider only the interfaces of
+        * the current registered device.
+        */
+       list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+               struct ieee80211_channel *other_chan = NULL;
+               int r1, r2;
+
+               if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
+                   !netif_running(wdev_iter->netdev))
+                       continue;
+
+               wdev_lock(wdev_iter);
+               if (wdev_iter->current_bss)
+                       other_chan = wdev_iter->current_bss->pub.channel;
+               wdev_unlock(wdev_iter);
+
+               if (!other_chan)
+                       continue;
+
+               if (chan == other_chan)
+                       return true;
+
+               if (chan->band != IEEE80211_BAND_5GHZ)
+                       continue;
+
+               r1 = cfg80211_get_unii(chan->center_freq);
+               r2 = cfg80211_get_unii(other_chan->center_freq);
+
+               if (r1 != -EINVAL && r1 == r2) {
+                       /*
+                        * At some locations channels 149-165 are considered a
+                        * bundle, but at other locations, e.g., Indonesia,
+                        * channels 149-161 are considered a bundle while
+                        * channel 165 is left out and considered to be in a
+                        * different bundle. Thus, in case that there is a
+                        * station interface connected to an AP on channel 165,
+                        * it is assumed that channels 149-161 are allowed for
+                        * GO operations. However, having a station interface
+                        * connected to an AP on channels 149-161, does not
+                        * allow GO operation on channel 165.
+                        */
+                       if (chan->center_freq == 5825 &&
+                           other_chan->center_freq != 5825)
+                               continue;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
-                            struct cfg80211_chan_def *chandef)
+                            struct cfg80211_chan_def *chandef,
+                            enum nl80211_iftype iftype)
 {
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        bool res;
        u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
-                              IEEE80211_CHAN_NO_IR |
                               IEEE80211_CHAN_RADAR;
 
-       trace_cfg80211_reg_can_beacon(wiphy, chandef);
+       trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
 
-       if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
+       /*
+        * Under certain conditions suggested by the some regulatory bodies
+        * a GO can operate on channels marked with IEEE80211_NO_IR
+        * so set this flag only if such relaxations are not enabled and
+        * the conditions are not met.
+        */
+       if (iftype != NL80211_IFTYPE_P2P_GO ||
+           !cfg80211_go_permissive_chan(rdev, chandef->chan))
+               prohibited_flags |= IEEE80211_CHAN_NO_IR;
+
+       if (cfg80211_chandef_dfs_required(wiphy, chandef,
+                                         NL80211_IFTYPE_UNSPECIFIED) > 0 &&
            cfg80211_chandef_dfs_available(wiphy, chandef)) {
                /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
                prohibited_flags = IEEE80211_CHAN_DISABLED;
@@ -701,6 +827,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                        enum cfg80211_chan_mode *chanmode,
                        u8 *radar_detect)
 {
+       int ret;
+
        *chan = NULL;
        *chanmode = CHAN_MODE_UNDEFINED;
 
@@ -743,8 +871,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                        *chan = wdev->chandef.chan;
                        *chanmode = CHAN_MODE_SHARED;
 
-                       if (cfg80211_chandef_dfs_required(wdev->wiphy,
-                                                         &wdev->chandef))
+                       ret = cfg80211_chandef_dfs_required(wdev->wiphy,
+                                                           &wdev->chandef,
+                                                           wdev->iftype);
+                       WARN_ON(ret < 0);
+                       if (ret > 0)
                                *radar_detect |= BIT(wdev->chandef.width);
                }
                return;
@@ -753,8 +884,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                        *chan = wdev->chandef.chan;
                        *chanmode = CHAN_MODE_SHARED;
 
-                       if (cfg80211_chandef_dfs_required(wdev->wiphy,
-                                                         &wdev->chandef))
+                       ret = cfg80211_chandef_dfs_required(wdev->wiphy,
+                                                           &wdev->chandef,
+                                                           wdev->iftype);
+                       WARN_ON(ret < 0);
+                       if (ret > 0)
                                *radar_detect |= BIT(wdev->chandef.width);
                }
                return;
index 086cddd03ba6edd79d1609ecf713146bc756c1ff..b3ff3697239a47b02d4008911c4c12bf7651b769 100644 (file)
@@ -69,7 +69,7 @@ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 
 int get_wiphy_idx(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        return rdev->wiphy_idx;
 }
@@ -260,6 +260,45 @@ static void cfg80211_event_work(struct work_struct *work)
        rtnl_unlock();
 }
 
+void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
+{
+       struct cfg80211_iface_destroy *item;
+
+       ASSERT_RTNL();
+
+       spin_lock_irq(&rdev->destroy_list_lock);
+       while ((item = list_first_entry_or_null(&rdev->destroy_list,
+                                               struct cfg80211_iface_destroy,
+                                               list))) {
+               struct wireless_dev *wdev, *tmp;
+               u32 nlportid = item->nlportid;
+
+               list_del(&item->list);
+               kfree(item);
+               spin_unlock_irq(&rdev->destroy_list_lock);
+
+               list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) {
+                       if (nlportid == wdev->owner_nlportid)
+                               rdev_del_virtual_intf(rdev, wdev);
+               }
+
+               spin_lock_irq(&rdev->destroy_list_lock);
+       }
+       spin_unlock_irq(&rdev->destroy_list_lock);
+}
+
+static void cfg80211_destroy_iface_wk(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev;
+
+       rdev = container_of(work, struct cfg80211_registered_device,
+                           destroy_work);
+
+       rtnl_lock();
+       cfg80211_destroy_ifaces(rdev);
+       rtnl_unlock();
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
@@ -318,6 +357,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy.dev.class = &ieee80211_class;
        rdev->wiphy.dev.platform_data = rdev;
 
+       INIT_LIST_HEAD(&rdev->destroy_list);
+       spin_lock_init(&rdev->destroy_list_lock);
+       INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
+
 #ifdef CONFIG_CFG80211_DEFAULT_PS
        rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
 #endif
@@ -396,10 +439,7 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
                for (j = 0; j < c->n_limits; j++) {
                        u16 types = c->limits[j].types;
 
-                       /*
-                        * interface types shouldn't overlap, this is
-                        * used in cfg80211_can_change_interface()
-                        */
+                       /* interface types shouldn't overlap */
                        if (WARN_ON(types & all_iftypes))
                                return -EINVAL;
                        all_iftypes |= types;
@@ -435,7 +475,7 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
 
 int wiphy_register(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        int res;
        enum ieee80211_band band;
        struct ieee80211_supported_band *sband;
@@ -616,7 +656,7 @@ EXPORT_SYMBOL(wiphy_register);
 
 void wiphy_rfkill_start_polling(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        if (!rdev->ops->rfkill_poll)
                return;
@@ -627,7 +667,7 @@ EXPORT_SYMBOL(wiphy_rfkill_start_polling);
 
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        rfkill_pause_polling(rdev->rfkill);
 }
@@ -635,7 +675,7 @@ EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
 
 void wiphy_unregister(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        wait_event(rdev->dev_wait, ({
                int __count;
@@ -675,6 +715,7 @@ void wiphy_unregister(struct wiphy *wiphy)
        cancel_work_sync(&rdev->conn_work);
        flush_work(&rdev->event_work);
        cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
+       flush_work(&rdev->destroy_work);
 
 #ifdef CONFIG_PM
        if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@@ -707,7 +748,7 @@ EXPORT_SYMBOL(wiphy_free);
 
 void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        if (rfkill_set_hw_state(rdev->rfkill, blocked))
                schedule_work(&rdev->rfkill_sync);
@@ -716,7 +757,7 @@ EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        ASSERT_RTNL();
 
@@ -796,12 +837,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev;
-       int ret;
 
        if (!wdev)
                return NOTIFY_DONE;
 
-       rdev = wiphy_to_dev(wdev->wiphy);
+       rdev = wiphy_to_rdev(wdev->wiphy);
 
        WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
 
@@ -959,13 +999,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
        case NETDEV_PRE_UP:
                if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
                        return notifier_from_errno(-EOPNOTSUPP);
-               ret = cfg80211_can_add_interface(rdev, wdev->iftype);
-               if (ret)
-                       return notifier_from_errno(ret);
+               if (rfkill_blocked(rdev->rfkill))
+                       return notifier_from_errno(-ERFKILL);
                break;
+       default:
+               return NOTIFY_DONE;
        }
 
-       return NOTIFY_DONE;
+       return NOTIFY_OK;
 }
 
 static struct notifier_block cfg80211_netdev_notifier = {
index 5b1fdcadd46985548f4a04f4f64ddaccbc935661..681b8fa4355b09bdc78796388986deeb9022ea89 100644 (file)
@@ -80,13 +80,17 @@ struct cfg80211_registered_device {
 
        struct cfg80211_coalesce *coalesce;
 
+       spinlock_t destroy_list_lock;
+       struct list_head destroy_list;
+       struct work_struct destroy_work;
+
        /* must be last because of the way we do wiphy_priv(),
         * and it should at least be aligned to NETDEV_ALIGN */
        struct wiphy wiphy __aligned(NETDEV_ALIGN);
 };
 
 static inline
-struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
+struct cfg80211_registered_device *wiphy_to_rdev(struct wiphy *wiphy)
 {
        BUG_ON(!wiphy);
        return container_of(wiphy, struct cfg80211_registered_device, wiphy);
@@ -232,6 +236,13 @@ struct cfg80211_beacon_registration {
        u32 nlportid;
 };
 
+struct cfg80211_iface_destroy {
+       struct list_head list;
+       u32 nlportid;
+};
+
+void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
+
 /* free object */
 void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
 
@@ -240,8 +251,8 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 
 void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
 
-void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
-void cfg80211_bss_age(struct cfg80211_registered_device *dev,
+void cfg80211_bss_expire(struct cfg80211_registered_device *rdev);
+void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
                       unsigned long age_secs);
 
 /* IBSS */
@@ -401,35 +412,6 @@ unsigned int
 cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
                              const struct cfg80211_chan_def *chandef);
 
-static inline int
-cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
-                             struct wireless_dev *wdev,
-                             enum nl80211_iftype iftype)
-{
-       return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
-                                           CHAN_MODE_UNDEFINED, 0);
-}
-
-static inline int
-cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
-                          enum nl80211_iftype iftype)
-{
-       if (rfkill_blocked(rdev->rfkill))
-               return -ERFKILL;
-
-       return cfg80211_can_change_interface(rdev, NULL, iftype);
-}
-
-static inline int
-cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
-                     struct wireless_dev *wdev,
-                     struct ieee80211_channel *chan,
-                     enum cfg80211_chan_mode chanmode)
-{
-       return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-                                           chan, chanmode, 0);
-}
-
 static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
 {
        unsigned long end = jiffies;
index e37862f1b1270d8e2056fb6289f01bf69b583720..d4860bfc020e5a1c43758e8cca6e9508908344be 100644 (file)
@@ -43,7 +43,7 @@ static void cfg80211_get_ringparam(struct net_device *dev,
                                   struct ethtool_ringparam *rp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        memset(rp, 0, sizeof(*rp));
 
@@ -56,7 +56,7 @@ static int cfg80211_set_ringparam(struct net_device *dev,
                                  struct ethtool_ringparam *rp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0)
                return -EINVAL;
@@ -70,7 +70,7 @@ static int cfg80211_set_ringparam(struct net_device *dev,
 static int cfg80211_get_sset_count(struct net_device *dev, int sset)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        if (rdev->ops->get_et_sset_count)
                return rdev_get_et_sset_count(rdev, dev, sset);
        return -EOPNOTSUPP;
@@ -80,7 +80,7 @@ static void cfg80211_get_stats(struct net_device *dev,
                               struct ethtool_stats *stats, u64 *data)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        if (rdev->ops->get_et_stats)
                rdev_get_et_stats(rdev, dev, stats, data);
 }
@@ -88,7 +88,7 @@ static void cfg80211_get_stats(struct net_device *dev,
 static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        if (rdev->ops->get_et_strings)
                rdev_get_et_strings(rdev, dev, sset, data);
 }
index a6b5bdad039c7450f276d1e56994661e2e41952c..6b50588b709f18658d6207f0df69b672f0e9a887 100644 (file)
@@ -45,7 +45,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
 
        cfg80211_upload_connect_keys(wdev);
 
-       nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
+       nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid,
                                GFP_KERNEL);
 #ifdef CONFIG_CFG80211_WEXT
        memset(&wrqu, 0, sizeof(wrqu));
@@ -58,7 +58,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
                          struct ieee80211_channel *channel, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
@@ -88,8 +88,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                                struct cfg80211_cached_keys *connkeys)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct ieee80211_channel *check_chan;
-       u8 radar_detect_width = 0;
        int err;
 
        ASSERT_WDEV_LOCK(wdev);
@@ -126,28 +124,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 #ifdef CONFIG_CFG80211_WEXT
        wdev->wext.ibss.chandef = params->chandef;
 #endif
-       check_chan = params->chandef.chan;
-       if (params->userspace_handles_dfs) {
-               /* Check for radar even if the current channel is not
-                * a radar channel - it might decide to change to DFS
-                * channel later.
-                */
-               radar_detect_width = BIT(params->chandef.width);
-       }
-
-       err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-                                          check_chan,
-                                          (params->channel_fixed &&
-                                           !radar_detect_width)
-                                          ? CHAN_MODE_SHARED
-                                          : CHAN_MODE_EXCLUSIVE,
-                                          radar_detect_width);
-
-       if (err) {
-               wdev->connect_keys = NULL;
-               return err;
-       }
-
        err = rdev_join_ibss(rdev, dev, params);
        if (err) {
                wdev->connect_keys = NULL;
@@ -180,7 +156,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        int i;
 
        ASSERT_WDEV_LOCK(wdev);
@@ -335,7 +311,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                               struct iw_freq *wextfreq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct ieee80211_channel *chan = NULL;
        int err, freq;
 
@@ -346,7 +322,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
        if (!rdev->ops->join_ibss)
                return -EOPNOTSUPP;
 
-       freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+       freq = cfg80211_wext_freq(wextfreq);
        if (freq < 0)
                return freq;
 
@@ -420,7 +396,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
                                struct iw_point *data, char *ssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        size_t len = data->length;
        int err;
 
@@ -487,7 +463,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
                             struct sockaddr *ap_addr, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        u8 *bssid = ap_addr->sa_data;
        int err;
 
@@ -505,6 +481,9 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
        if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
                bssid = NULL;
 
+       if (bssid && !is_valid_ether_addr(bssid))
+               return -EINVAL;
+
        /* both automatic */
        if (!bssid && !wdev->wext.ibss.bssid)
                return 0;
index 5af5cc6b2c4c2406475a3063a69eef80cc14691f..3ddfb7cd335e6a8740109e51355070310db6ecb3 100644 (file)
@@ -99,7 +99,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                         const struct mesh_config *conf)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       u8 radar_detect_width = 0;
        int err;
 
        BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
@@ -175,22 +174,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                                                               scan_width);
        }
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
+                                    NL80211_IFTYPE_MESH_POINT))
                return -EINVAL;
 
-       err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef);
-       if (err < 0)
-               return err;
-       if (err)
-               radar_detect_width = BIT(setup->chandef.width);
-
-       err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-                                          setup->chandef.chan,
-                                          CHAN_MODE_SHARED,
-                                          radar_detect_width);
-       if (err)
-               return err;
-
        err = rdev_join_mesh(rdev, dev, conf, setup);
        if (!err) {
                memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -236,17 +223,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
                if (!netif_running(wdev->netdev))
                        return -ENETDOWN;
 
-               /* cfg80211_can_use_chan() calls
-                * cfg80211_can_use_iftype_chan() with no radar
-                * detection, so if we're trying to use a radar
-                * channel here, something is wrong.
-                */
-               WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR);
-               err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
-                                           CHAN_MODE_SHARED);
-               if (err)
-                       return err;
-
                err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
                                                     chandef->chan);
                if (!err)
index c52ff59a3e96d7cabb892bff220b86c580069a43..266766b8d80b61455565cc43779a6e229ed7710d 100644 (file)
@@ -23,7 +23,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        u8 *ie = mgmt->u.assoc_resp.variable;
        int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
@@ -54,7 +54,7 @@ EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
 static void cfg80211_process_auth(struct wireless_dev *wdev,
                                  const u8 *buf, size_t len)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
        cfg80211_sme_rx_auth(wdev, buf, len);
@@ -63,7 +63,7 @@ static void cfg80211_process_auth(struct wireless_dev *wdev,
 static void cfg80211_process_deauth(struct wireless_dev *wdev,
                                    const u8 *buf, size_t len)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        const u8 *bssid = mgmt->bssid;
        u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
@@ -82,7 +82,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev,
 static void cfg80211_process_disassoc(struct wireless_dev *wdev,
                                      const u8 *buf, size_t len)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        const u8 *bssid = mgmt->bssid;
        u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
@@ -123,7 +123,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_send_auth_timeout(dev, addr);
 
@@ -136,7 +136,7 @@ void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_send_assoc_timeout(dev, bss->bssid);
 
@@ -172,7 +172,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
                                  const u8 *tsc, gfp_t gfp)
 {
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 #ifdef CONFIG_CFG80211_WEXT
        union iwreq_data wrqu;
        char *buf = kmalloc(128, gfp);
@@ -233,14 +233,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        if (!req.bss)
                return -ENOENT;
 
-       err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
-                                   CHAN_MODE_SHARED);
-       if (err)
-               goto out;
-
        err = rdev_auth(rdev, dev, &req);
 
-out:
        cfg80211_put_bss(&rdev->wiphy, req.bss);
        return err;
 }
@@ -306,16 +300,10 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        if (!req->bss)
                return -ENOENT;
 
-       err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
-       if (err)
-               goto out;
-
        err = rdev_assoc(rdev, dev, req);
        if (!err)
                cfg80211_hold_bss(bss_from_pub(req->bss));
-
-out:
-       if (err)
+       else
                cfg80211_put_bss(&rdev->wiphy, req->bss);
 
        return err;
@@ -414,7 +402,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
                                int match_len)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_mgmt_registration *reg, *nreg;
        int err = 0;
        u16 mgmt_type;
@@ -473,7 +461,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
 void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_mgmt_registration *reg, *tmp;
 
        spin_lock_bh(&wdev->mgmt_registrations_lock);
@@ -620,7 +608,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
                      const u8 *buf, size_t len, u32 flags, gfp_t gfp)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_mgmt_registration *reg;
        const struct ieee80211_txrx_stypes *stypes =
                &wiphy->mgmt_stypes[wdev->iftype];
@@ -739,7 +727,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
                          struct cfg80211_chan_def *chandef,
                          gfp_t gfp)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        unsigned long timeout;
 
        trace_cfg80211_radar_event(wiphy, chandef);
@@ -764,7 +752,7 @@ void cfg80211_cac_event(struct net_device *netdev,
 {
        struct wireless_dev *wdev = netdev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        unsigned long timeout;
 
        trace_cfg80211_cac_event(netdev, event);
index 052c1bf8ffaceb92d3f117231a46fca78ed30216..0f1b18f209d6254800ac50f28b4d454017fe7e62 100644 (file)
@@ -168,8 +168,8 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
                netdev = __dev_get_by_index(netns, ifindex);
                if (netdev) {
                        if (netdev->ieee80211_ptr)
-                               tmp = wiphy_to_dev(
-                                               netdev->ieee80211_ptr->wiphy);
+                               tmp = wiphy_to_rdev(
+                                       netdev->ieee80211_ptr->wiphy);
                        else
                                tmp = NULL;
 
@@ -385,6 +385,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
        [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
        [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
+       [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -484,7 +485,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
                        err = PTR_ERR(*wdev);
                        goto out_unlock;
                }
-               *rdev = wiphy_to_dev((*wdev)->wiphy);
+               *rdev = wiphy_to_rdev((*wdev)->wiphy);
                /* 0 is the first index - add 1 to parse only once */
                cb->args[0] = (*rdev)->wiphy_idx + 1;
                cb->args[1] = (*wdev)->identifier;
@@ -497,7 +498,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
                        err = -ENODEV;
                        goto out_unlock;
                }
-               *rdev = wiphy_to_dev(wiphy);
+               *rdev = wiphy_to_rdev(wiphy);
                *wdev = NULL;
 
                list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
@@ -566,6 +567,13 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
                                   struct ieee80211_channel *chan,
                                   bool large)
 {
+       /* Some channels must be completely excluded from the
+        * list to protect old user-space tools from breaking
+        */
+       if (!large && chan->flags &
+           (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
+               return 0;
+
        if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
                        chan->center_freq))
                goto nla_put_failure;
@@ -613,6 +621,18 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
                if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
                    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
                        goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
+                       goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT))
+                       goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
+                       goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
+                       goto nla_put_failure;
        }
 
        if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
@@ -1006,42 +1026,42 @@ static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
 }
 
 static int nl80211_send_wowlan(struct sk_buff *msg,
-                              struct cfg80211_registered_device *dev,
+                              struct cfg80211_registered_device *rdev,
                               bool large)
 {
        struct nlattr *nl_wowlan;
 
-       if (!dev->wiphy.wowlan)
+       if (!rdev->wiphy.wowlan)
                return 0;
 
        nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
        if (!nl_wowlan)
                return -ENOBUFS;
 
-       if (((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
+       if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
-           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
+           ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
                return -ENOBUFS;
 
-       if (dev->wiphy.wowlan->n_patterns) {
+       if (rdev->wiphy.wowlan->n_patterns) {
                struct nl80211_pattern_support pat = {
-                       .max_patterns = dev->wiphy.wowlan->n_patterns,
-                       .min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
-                       .max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
-                       .max_pkt_offset = dev->wiphy.wowlan->max_pkt_offset,
+                       .max_patterns = rdev->wiphy.wowlan->n_patterns,
+                       .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
+                       .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
+                       .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
                };
 
                if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
@@ -1049,7 +1069,7 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
                        return -ENOBUFS;
        }
 
-       if (large && nl80211_send_wowlan_tcp_caps(dev, msg))
+       if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
                return -ENOBUFS;
 
        nla_nest_end(msg, nl_wowlan);
@@ -1059,19 +1079,19 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
 #endif
 
 static int nl80211_send_coalesce(struct sk_buff *msg,
-                                struct cfg80211_registered_device *dev)
+                                struct cfg80211_registered_device *rdev)
 {
        struct nl80211_coalesce_rule_support rule;
 
-       if (!dev->wiphy.coalesce)
+       if (!rdev->wiphy.coalesce)
                return 0;
 
-       rule.max_rules = dev->wiphy.coalesce->n_rules;
-       rule.max_delay = dev->wiphy.coalesce->max_delay;
-       rule.pat.max_patterns = dev->wiphy.coalesce->n_patterns;
-       rule.pat.min_pattern_len = dev->wiphy.coalesce->pattern_min_len;
-       rule.pat.max_pattern_len = dev->wiphy.coalesce->pattern_max_len;
-       rule.pat.max_pkt_offset = dev->wiphy.coalesce->max_pkt_offset;
+       rule.max_rules = rdev->wiphy.coalesce->n_rules;
+       rule.max_delay = rdev->wiphy.coalesce->max_delay;
+       rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
+       rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
+       rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
+       rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;
 
        if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
                return -ENOBUFS;
@@ -1202,7 +1222,7 @@ struct nl80211_dump_wiphy_state {
        bool split;
 };
 
-static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
+static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                              struct sk_buff *msg, u32 portid, u32 seq,
                              int flags, struct nl80211_dump_wiphy_state *state)
 {
@@ -1214,7 +1234,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
        struct ieee80211_channel *chan;
        int i;
        const struct ieee80211_txrx_stypes *mgmt_stypes =
-                               dev->wiphy.mgmt_stypes;
+                               rdev->wiphy.mgmt_stypes;
        u32 features;
 
        hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
@@ -1224,9 +1244,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
        if (WARN_ON(!state))
                return -EINVAL;
 
-       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
            nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
-                          wiphy_name(&dev->wiphy)) ||
+                          wiphy_name(&rdev->wiphy)) ||
            nla_put_u32(msg, NL80211_ATTR_GENERATION,
                        cfg80211_rdev_list_generation))
                goto nla_put_failure;
@@ -1234,43 +1254,43 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
        switch (state->split_start) {
        case 0:
                if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
-                              dev->wiphy.retry_short) ||
+                              rdev->wiphy.retry_short) ||
                    nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
-                              dev->wiphy.retry_long) ||
+                              rdev->wiphy.retry_long) ||
                    nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
-                               dev->wiphy.frag_threshold) ||
+                               rdev->wiphy.frag_threshold) ||
                    nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
-                               dev->wiphy.rts_threshold) ||
+                               rdev->wiphy.rts_threshold) ||
                    nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
-                              dev->wiphy.coverage_class) ||
+                              rdev->wiphy.coverage_class) ||
                    nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
-                              dev->wiphy.max_scan_ssids) ||
+                              rdev->wiphy.max_scan_ssids) ||
                    nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
-                              dev->wiphy.max_sched_scan_ssids) ||
+                              rdev->wiphy.max_sched_scan_ssids) ||
                    nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
-                               dev->wiphy.max_scan_ie_len) ||
+                               rdev->wiphy.max_scan_ie_len) ||
                    nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
-                               dev->wiphy.max_sched_scan_ie_len) ||
+                               rdev->wiphy.max_sched_scan_ie_len) ||
                    nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
-                              dev->wiphy.max_match_sets))
+                              rdev->wiphy.max_match_sets))
                        goto nla_put_failure;
 
-               if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
                    nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
                    nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
                    nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
                    nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
                    nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
                    nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
                        goto nla_put_failure;
                state->split_start++;
@@ -1278,35 +1298,35 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        break;
        case 1:
                if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
-                           sizeof(u32) * dev->wiphy.n_cipher_suites,
-                           dev->wiphy.cipher_suites))
+                           sizeof(u32) * rdev->wiphy.n_cipher_suites,
+                           rdev->wiphy.cipher_suites))
                        goto nla_put_failure;
 
                if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
-                              dev->wiphy.max_num_pmkids))
+                              rdev->wiphy.max_num_pmkids))
                        goto nla_put_failure;
 
-               if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
                    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
                        goto nla_put_failure;
 
                if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
-                               dev->wiphy.available_antennas_tx) ||
+                               rdev->wiphy.available_antennas_tx) ||
                    nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
-                               dev->wiphy.available_antennas_rx))
+                               rdev->wiphy.available_antennas_rx))
                        goto nla_put_failure;
 
-               if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
                    nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
-                               dev->wiphy.probe_resp_offload))
+                               rdev->wiphy.probe_resp_offload))
                        goto nla_put_failure;
 
-               if ((dev->wiphy.available_antennas_tx ||
-                    dev->wiphy.available_antennas_rx) &&
-                   dev->ops->get_antenna) {
+               if ((rdev->wiphy.available_antennas_tx ||
+                    rdev->wiphy.available_antennas_rx) &&
+                   rdev->ops->get_antenna) {
                        u32 tx_ant = 0, rx_ant = 0;
                        int res;
-                       res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
+                       res = rdev_get_antenna(rdev, &tx_ant, &rx_ant);
                        if (!res) {
                                if (nla_put_u32(msg,
                                                NL80211_ATTR_WIPHY_ANTENNA_TX,
@@ -1323,7 +1343,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        break;
        case 2:
                if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
-                                       dev->wiphy.interface_modes))
+                                       rdev->wiphy.interface_modes))
                                goto nla_put_failure;
                state->split_start++;
                if (state->split)
@@ -1337,7 +1357,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                     band < IEEE80211_NUM_BANDS; band++) {
                        struct ieee80211_supported_band *sband;
 
-                       sband = dev->wiphy.bands[band];
+                       sband = rdev->wiphy.bands[band];
 
                        if (!sband)
                                continue;
@@ -1414,7 +1434,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                i = 0;
 #define CMD(op, n)                                                     \
                 do {                                                   \
-                       if (dev->ops->op) {                             \
+                       if (rdev->ops->op) {                            \
                                i++;                                    \
                                if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
                                        goto nla_put_failure;           \
@@ -1438,32 +1458,32 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                CMD(set_pmksa, SET_PMKSA);
                CMD(del_pmksa, DEL_PMKSA);
                CMD(flush_pmksa, FLUSH_PMKSA);
-               if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
+               if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
                        CMD(remain_on_channel, REMAIN_ON_CHANNEL);
                CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
                CMD(mgmt_tx, FRAME);
                CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
-               if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
+               if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
                        i++;
                        if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
                                goto nla_put_failure;
                }
-               if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
-                   dev->ops->join_mesh) {
+               if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
+                   rdev->ops->join_mesh) {
                        i++;
                        if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
                                goto nla_put_failure;
                }
                CMD(set_wds_peer, SET_WDS_PEER);
-               if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+               if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
                        CMD(tdls_mgmt, TDLS_MGMT);
                        CMD(tdls_oper, TDLS_OPER);
                }
-               if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+               if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                        CMD(sched_scan_start, START_SCHED_SCAN);
                CMD(probe_client, PROBE_CLIENT);
                CMD(set_noack_map, SET_NOACK_MAP);
-               if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
+               if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
                        i++;
                        if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
                                goto nla_put_failure;
@@ -1473,7 +1493,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if (state->split) {
                        CMD(crit_proto_start, CRIT_PROTOCOL_START);
                        CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
-                       if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
+                       if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
                                CMD(channel_switch, CHANNEL_SWITCH);
                }
                CMD(set_qos_map, SET_QOS_MAP);
@@ -1484,13 +1504,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 
 #undef CMD
 
-               if (dev->ops->connect || dev->ops->auth) {
+               if (rdev->ops->connect || rdev->ops->auth) {
                        i++;
                        if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
                                goto nla_put_failure;
                }
 
-               if (dev->ops->disconnect || dev->ops->deauth) {
+               if (rdev->ops->disconnect || rdev->ops->deauth) {
                        i++;
                        if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
                                goto nla_put_failure;
@@ -1501,14 +1521,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if (state->split)
                        break;
        case 5:
-               if (dev->ops->remain_on_channel &&
-                   (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
+               if (rdev->ops->remain_on_channel &&
+                   (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
                    nla_put_u32(msg,
                                NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
-                               dev->wiphy.max_remain_on_channel_duration))
+                               rdev->wiphy.max_remain_on_channel_duration))
                        goto nla_put_failure;
 
-               if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
                    nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
                        goto nla_put_failure;
 
@@ -1519,7 +1539,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        break;
        case 6:
 #ifdef CONFIG_PM
-               if (nl80211_send_wowlan(msg, dev, state->split))
+               if (nl80211_send_wowlan(msg, rdev, state->split))
                        goto nla_put_failure;
                state->split_start++;
                if (state->split)
@@ -1529,10 +1549,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 #endif
        case 7:
                if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
-                                       dev->wiphy.software_iftypes))
+                                       rdev->wiphy.software_iftypes))
                        goto nla_put_failure;
 
-               if (nl80211_put_iface_combinations(&dev->wiphy, msg,
+               if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
                                                   state->split))
                        goto nla_put_failure;
 
@@ -1540,12 +1560,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if (state->split)
                        break;
        case 8:
-               if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
                    nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
-                               dev->wiphy.ap_sme_capa))
+                               rdev->wiphy.ap_sme_capa))
                        goto nla_put_failure;
 
-               features = dev->wiphy.features;
+               features = rdev->wiphy.features;
                /*
                 * We can only add the per-channel limit information if the
                 * dump is split, otherwise it makes it too big. Therefore
@@ -1556,16 +1576,16 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
                        goto nla_put_failure;
 
-               if (dev->wiphy.ht_capa_mod_mask &&
+               if (rdev->wiphy.ht_capa_mod_mask &&
                    nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
-                           sizeof(*dev->wiphy.ht_capa_mod_mask),
-                           dev->wiphy.ht_capa_mod_mask))
+                           sizeof(*rdev->wiphy.ht_capa_mod_mask),
+                           rdev->wiphy.ht_capa_mod_mask))
                        goto nla_put_failure;
 
-               if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
-                   dev->wiphy.max_acl_mac_addrs &&
+               if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+                   rdev->wiphy.max_acl_mac_addrs &&
                    nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
-                               dev->wiphy.max_acl_mac_addrs))
+                               rdev->wiphy.max_acl_mac_addrs))
                        goto nla_put_failure;
 
                /*
@@ -1581,41 +1601,41 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                state->split_start++;
                break;
        case 9:
-               if (dev->wiphy.extended_capabilities &&
+               if (rdev->wiphy.extended_capabilities &&
                    (nla_put(msg, NL80211_ATTR_EXT_CAPA,
-                            dev->wiphy.extended_capabilities_len,
-                            dev->wiphy.extended_capabilities) ||
+                            rdev->wiphy.extended_capabilities_len,
+                            rdev->wiphy.extended_capabilities) ||
                     nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
-                            dev->wiphy.extended_capabilities_len,
-                            dev->wiphy.extended_capabilities_mask)))
+                            rdev->wiphy.extended_capabilities_len,
+                            rdev->wiphy.extended_capabilities_mask)))
                        goto nla_put_failure;
 
-               if (dev->wiphy.vht_capa_mod_mask &&
+               if (rdev->wiphy.vht_capa_mod_mask &&
                    nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
-                           sizeof(*dev->wiphy.vht_capa_mod_mask),
-                           dev->wiphy.vht_capa_mod_mask))
+                           sizeof(*rdev->wiphy.vht_capa_mod_mask),
+                           rdev->wiphy.vht_capa_mod_mask))
                        goto nla_put_failure;
 
                state->split_start++;
                break;
        case 10:
-               if (nl80211_send_coalesce(msg, dev))
+               if (nl80211_send_coalesce(msg, rdev))
                        goto nla_put_failure;
 
-               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
+               if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
                    (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
                     nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
                        goto nla_put_failure;
 
-               if (dev->wiphy.max_ap_assoc_sta &&
+               if (rdev->wiphy.max_ap_assoc_sta &&
                    nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
-                               dev->wiphy.max_ap_assoc_sta))
+                               rdev->wiphy.max_ap_assoc_sta))
                        goto nla_put_failure;
 
                state->split_start++;
                break;
        case 11:
-               if (dev->wiphy.n_vendor_commands) {
+               if (rdev->wiphy.n_vendor_commands) {
                        const struct nl80211_vendor_cmd_info *info;
                        struct nlattr *nested;
 
@@ -1623,15 +1643,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        if (!nested)
                                goto nla_put_failure;
 
-                       for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
-                               info = &dev->wiphy.vendor_commands[i].info;
+                       for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
+                               info = &rdev->wiphy.vendor_commands[i].info;
                                if (nla_put(msg, i + 1, sizeof(*info), info))
                                        goto nla_put_failure;
                        }
                        nla_nest_end(msg, nested);
                }
 
-               if (dev->wiphy.n_vendor_events) {
+               if (rdev->wiphy.n_vendor_events) {
                        const struct nl80211_vendor_cmd_info *info;
                        struct nlattr *nested;
 
@@ -1640,8 +1660,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        if (!nested)
                                goto nla_put_failure;
 
-                       for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
-                               info = &dev->wiphy.vendor_events[i];
+                       for (i = 0; i < rdev->wiphy.n_vendor_events; i++) {
+                               info = &rdev->wiphy.vendor_events[i];
                                if (nla_put(msg, i + 1, sizeof(*info), info))
                                        goto nla_put_failure;
                        }
@@ -1684,7 +1704,7 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
                if (!netdev)
                        return -ENODEV;
                if (netdev->ieee80211_ptr) {
-                       rdev = wiphy_to_dev(
+                       rdev = wiphy_to_rdev(
                                netdev->ieee80211_ptr->wiphy);
                        state->filter_wiphy = rdev->wiphy_idx;
                }
@@ -1697,7 +1717,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 {
        int idx = 0, ret;
        struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
-       struct cfg80211_registered_device *dev;
+       struct cfg80211_registered_device *rdev;
 
        rtnl_lock();
        if (!state) {
@@ -1716,17 +1736,17 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                cb->args[0] = (long)state;
        }
 
-       list_for_each_entry(dev, &cfg80211_rdev_list, list) {
-               if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk)))
                        continue;
                if (++idx <= state->start)
                        continue;
                if (state->filter_wiphy != -1 &&
-                   state->filter_wiphy != dev->wiphy_idx)
+                   state->filter_wiphy != rdev->wiphy_idx)
                        continue;
                /* attempt to fit multiple wiphy data chunks into the skb */
                do {
-                       ret = nl80211_send_wiphy(dev, skb,
+                       ret = nl80211_send_wiphy(rdev, skb,
                                                 NETLINK_CB(cb->skb).portid,
                                                 cb->nlh->nlmsg_seq,
                                                 NLM_F_MULTI, state);
@@ -1774,14 +1794,14 @@ static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       struct cfg80211_registered_device *dev = info->user_ptr[0];
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct nl80211_dump_wiphy_state state = {};
 
        msg = nlmsg_new(4096, GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
 
-       if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0,
+       if (nl80211_send_wiphy(rdev, msg, info->snd_portid, info->snd_seq, 0,
                               &state) < 0) {
                nlmsg_free(msg);
                return -ENOBUFS;
@@ -1908,18 +1928,20 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
 }
 
 static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
-                                struct wireless_dev *wdev,
+                                struct net_device *dev,
                                 struct genl_info *info)
 {
        struct cfg80211_chan_def chandef;
        int result;
        enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+       struct wireless_dev *wdev = NULL;
 
-       if (wdev)
-               iftype = wdev->iftype;
-
+       if (dev)
+               wdev = dev->ieee80211_ptr;
        if (!nl80211_can_set_dev_channel(wdev))
                return -EOPNOTSUPP;
+       if (wdev)
+               iftype = wdev->iftype;
 
        result = nl80211_parse_chandef(rdev, info, &chandef);
        if (result)
@@ -1928,14 +1950,27 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        switch (iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
-               if (wdev->beacon_interval) {
-                       result = -EBUSY;
-                       break;
-               }
-               if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) {
+               if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
                        result = -EINVAL;
                        break;
                }
+               if (wdev->beacon_interval) {
+                       if (!dev || !rdev->ops->set_ap_chanwidth ||
+                           !(rdev->wiphy.features &
+                             NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
+                               result = -EBUSY;
+                               break;
+                       }
+
+                       /* Only allow dynamic channel width changes */
+                       if (chandef.chan != wdev->preset_chandef.chan) {
+                               result = -EBUSY;
+                               break;
+                       }
+                       result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
+                       if (result)
+                               break;
+               }
                wdev->preset_chandef = chandef;
                result = 0;
                break;
@@ -1957,7 +1992,7 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *netdev = info->user_ptr[1];
 
-       return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+       return __nl80211_set_channel(rdev, netdev, info);
 }
 
 static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
@@ -2013,7 +2048,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
                netdev = __dev_get_by_index(genl_info_net(info), ifindex);
                if (netdev && netdev->ieee80211_ptr)
-                       rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
+                       rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy);
                else
                        netdev = NULL;
        }
@@ -2079,9 +2114,10 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               result = __nl80211_set_channel(rdev,
-                               nl80211_can_set_dev_channel(wdev) ? wdev : NULL,
-                               info);
+               result = __nl80211_set_channel(
+                       rdev,
+                       nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
+                       info);
                if (result)
                        return result;
        }
@@ -2229,7 +2265,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 static inline u64 wdev_id(struct wireless_dev *wdev)
 {
        return (u64)wdev->identifier |
-              ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32);
+              ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
 }
 
 static int nl80211_send_chandef(struct sk_buff *msg,
@@ -2355,7 +2391,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       struct cfg80211_registered_device *dev = info->user_ptr[0];
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev = info->user_ptr[1];
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -2363,7 +2399,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
                return -ENOMEM;
 
        if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
-                              dev, wdev) < 0) {
+                              rdev, wdev) < 0) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
@@ -2514,6 +2550,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
        u32 flags;
 
+       /* to avoid failing a new interface creation due to pending removal */
+       cfg80211_destroy_ifaces(rdev);
+
        memset(&params, 0, sizeof(params));
 
        if (!info->attrs[NL80211_ATTR_IFNAME])
@@ -2563,6 +2602,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                return PTR_ERR(wdev);
        }
 
+       if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
+               wdev->owner_nlportid = info->snd_portid;
+
        switch (type) {
        case NL80211_IFTYPE_MESH_POINT:
                if (!info->attrs[NL80211_ATTR_MESH_ID])
@@ -3142,7 +3184,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_ap_settings params;
        int err;
-       u8 radar_detect_width = 0;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
@@ -3258,24 +3299,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        } else if (!nl80211_get_ap_channel(rdev, &params))
                return -EINVAL;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+                                    wdev->iftype))
                return -EINVAL;
 
-       err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
-       if (err < 0)
-               return err;
-       if (err) {
-               radar_detect_width = BIT(params.chandef.width);
-               params.radar_required = true;
-       }
-
-       err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-                                          params.chandef.chan,
-                                          CHAN_MODE_SHARED,
-                                          radar_detect_width);
-       if (err)
-               return err;
-
        if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
                params.acl = parse_acl_data(&rdev->wiphy, info);
                if (IS_ERR(params.acl))
@@ -3675,13 +3702,13 @@ static int nl80211_dump_station(struct sk_buff *skb,
                                struct netlink_callback *cb)
 {
        struct station_info sinfo;
-       struct cfg80211_registered_device *dev;
+       struct cfg80211_registered_device *rdev;
        struct wireless_dev *wdev;
        u8 mac_addr[ETH_ALEN];
        int sta_idx = cb->args[2];
        int err;
 
-       err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
        if (err)
                return err;
 
@@ -3690,14 +3717,14 @@ static int nl80211_dump_station(struct sk_buff *skb,
                goto out_err;
        }
 
-       if (!dev->ops->dump_station) {
+       if (!rdev->ops->dump_station) {
                err = -EOPNOTSUPP;
                goto out_err;
        }
 
        while (1) {
                memset(&sinfo, 0, sizeof(sinfo));
-               err = rdev_dump_station(dev, wdev->netdev, sta_idx,
+               err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
                                        mac_addr, &sinfo);
                if (err == -ENOENT)
                        break;
@@ -3707,7 +3734,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
                if (nl80211_send_station(skb,
                                NETLINK_CB(cb->skb).portid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                               dev, wdev->netdev, mac_addr,
+                               rdev, wdev->netdev, mac_addr,
                                &sinfo) < 0)
                        goto out;
 
@@ -3719,7 +3746,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
        cb->args[2] = sta_idx;
        err = skb->len;
  out_err:
-       nl80211_finish_wdev_dump(dev);
+       nl80211_finish_wdev_dump(rdev);
 
        return err;
 }
@@ -4380,18 +4407,18 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
                              struct netlink_callback *cb)
 {
        struct mpath_info pinfo;
-       struct cfg80211_registered_device *dev;
+       struct cfg80211_registered_device *rdev;
        struct wireless_dev *wdev;
        u8 dst[ETH_ALEN];
        u8 next_hop[ETH_ALEN];
        int path_idx = cb->args[2];
        int err;
 
-       err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
        if (err)
                return err;
 
-       if (!dev->ops->dump_mpath) {
+       if (!rdev->ops->dump_mpath) {
                err = -EOPNOTSUPP;
                goto out_err;
        }
@@ -4402,7 +4429,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        }
 
        while (1) {
-               err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst,
+               err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst,
                                      next_hop, &pinfo);
                if (err == -ENOENT)
                        break;
@@ -4423,7 +4450,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        cb->args[2] = path_idx;
        err = skb->len;
  out_err:
-       nl80211_finish_wdev_dump(dev);
+       nl80211_finish_wdev_dump(rdev);
        return err;
 }
 
@@ -4663,7 +4690,6 @@ static int parse_reg_rule(struct nlattr *tb[],
 
 static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
-       int r;
        char *data = NULL;
        enum nl80211_user_reg_hint_type user_reg_hint_type;
 
@@ -4676,11 +4702,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
        if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
                return -EINPROGRESS;
 
-       if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
-               return -EINVAL;
-
-       data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
-
        if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
                user_reg_hint_type =
                  nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
@@ -4690,14 +4711,16 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
        switch (user_reg_hint_type) {
        case NL80211_USER_REG_HINT_USER:
        case NL80211_USER_REG_HINT_CELL_BASE:
-               break;
+               if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+                       return -EINVAL;
+
+               data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+               return regulatory_hint_user(data, user_reg_hint_type);
+       case NL80211_USER_REG_HINT_INDOOR:
+               return regulatory_hint_indoor_user();
        default:
                return -EINVAL;
        }
-
-       r = regulatory_hint_user(data, user_reg_hint_type);
-
-       return r;
 }
 
 static int nl80211_get_mesh_config(struct sk_buff *skb,
@@ -5796,7 +5819,8 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        if (wdev->cac_started)
                return -EBUSY;
 
-       err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef);
+       err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
+                                           NL80211_IFTYPE_UNSPECIFIED);
        if (err < 0)
                return err;
 
@@ -5809,12 +5833,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        if (!rdev->ops->start_radar_detection)
                return -EOPNOTSUPP;
 
-       err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-                                          chandef.chan, CHAN_MODE_SHARED,
-                                          BIT(chandef.width));
-       if (err)
-               return err;
-
        cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
        if (WARN_ON(!cac_time_ms))
                cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
@@ -5928,27 +5946,25 @@ skip_beacons:
        if (err)
                return err;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+                                    wdev->iftype))
                return -EINVAL;
 
-       switch (dev->ieee80211_ptr->iftype) {
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_P2P_GO:
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_MESH_POINT:
-               err = cfg80211_chandef_dfs_required(wdev->wiphy,
-                                                   &params.chandef);
-               if (err < 0)
-                       return err;
-               if (err) {
-                       radar_detect_width = BIT(params.chandef.width);
-                       params.radar_required = true;
-               }
-               break;
-       default:
-               break;
+       err = cfg80211_chandef_dfs_required(wdev->wiphy,
+                                           &params.chandef,
+                                           wdev->iftype);
+       if (err < 0)
+               return err;
+
+       if (err > 0) {
+               radar_detect_width = BIT(params.chandef.width);
+               params.radar_required = true;
        }
 
+       /* TODO: I left this here for now.  With channel switch, the
+        * verification is a bit more complicated, because we only do
+        * it later when the channel switch really happens.
+        */
        err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
                                           params.chandef.chan,
                                           CHAN_MODE_SHARED,
@@ -6175,12 +6191,12 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                        struct netlink_callback *cb)
 {
        struct survey_info survey;
-       struct cfg80211_registered_device *dev;
+       struct cfg80211_registered_device *rdev;
        struct wireless_dev *wdev;
        int survey_idx = cb->args[2];
        int res;
 
-       res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
+       res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
        if (res)
                return res;
 
@@ -6189,7 +6205,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                goto out_err;
        }
 
-       if (!dev->ops->dump_survey) {
+       if (!rdev->ops->dump_survey) {
                res = -EOPNOTSUPP;
                goto out_err;
        }
@@ -6197,7 +6213,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        while (1) {
                struct ieee80211_channel *chan;
 
-               res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey);
+               res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
                if (res == -ENOENT)
                        break;
                if (res)
@@ -6209,7 +6225,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                        goto out;
                }
 
-               chan = ieee80211_get_channel(&dev->wiphy,
+               chan = ieee80211_get_channel(&rdev->wiphy,
                                             survey.channel->center_freq);
                if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
                        survey_idx++;
@@ -6228,7 +6244,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        cb->args[2] = survey_idx;
        res = skb->len;
  out_err:
-       nl80211_finish_wdev_dump(dev);
+       nl80211_finish_wdev_dump(rdev);
        return res;
 }
 
@@ -6704,7 +6720,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
+                                    NL80211_IFTYPE_ADHOC))
                return -EINVAL;
 
        switch (ibss.chandef.width) {
@@ -6879,7 +6896,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
                                           int vendor_event_idx,
                                           int approxlen, gfp_t gfp)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        const struct nl80211_vendor_cmd_info *info;
 
        switch (cmd) {
@@ -8981,9 +8998,8 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
        if (wdev->p2p_started)
                return 0;
 
-       err = cfg80211_can_add_interface(rdev, wdev->iftype);
-       if (err)
-               return err;
+       if (rfkill_blocked(rdev->rfkill))
+               return -ERFKILL;
 
        err = rdev_start_p2p_device(rdev, wdev);
        if (err)
@@ -9192,7 +9208,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
                                           enum nl80211_attrs attr,
                                           int approxlen)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        if (WARN_ON(!rdev->cur_cmd_info))
                return NULL;
@@ -9316,7 +9332,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
                }
 
                dev = wdev->netdev;
-               rdev = wiphy_to_dev(wdev->wiphy);
+               rdev = wiphy_to_rdev(wdev->wiphy);
 
                if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
                        if (!dev) {
@@ -10345,7 +10361,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        const struct ieee80211_mgmt *mgmt = (void *)buf;
        u32 cmd;
 
@@ -10567,7 +10583,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
                                        const u8* ie, u8 ie_len, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -10747,7 +10763,7 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
                               unsigned int duration, gfp_t gfp)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
        nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
@@ -10761,7 +10777,7 @@ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
                                        gfp_t gfp)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
        nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
@@ -10773,7 +10789,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
                      struct station_info *sinfo, gfp_t gfp)
 {
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
 
        trace_cfg80211_new_sta(dev, mac_addr, sinfo);
@@ -10796,7 +10812,7 @@ EXPORT_SYMBOL(cfg80211_new_sta);
 void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
 {
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -10833,7 +10849,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
                          gfp_t gfp)
 {
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -10868,7 +10884,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
                                       const u8 *addr, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
        u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
@@ -10988,7 +11004,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
                             const u8 *buf, size_t len, bool ack, gfp_t gfp)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct net_device *netdev = wdev->netdev;
        struct sk_buff *msg;
        void *hdr;
@@ -11032,7 +11048,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        struct nlattr *pinfoattr;
        void *hdr;
@@ -11124,7 +11140,7 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_gtk_rekey_notify(dev, bssid);
        nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
@@ -11182,7 +11198,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
        nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
@@ -11229,7 +11245,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        ASSERT_WDEV_LOCK(wdev);
 
@@ -11253,7 +11269,7 @@ void cfg80211_cqm_txe_notify(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        struct nlattr *pinfoattr;
        void *hdr;
@@ -11353,7 +11369,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        struct nlattr *pinfoattr;
        void *hdr;
@@ -11400,7 +11416,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
                           u64 cookie, bool acked, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -11440,7 +11456,7 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
                                 int freq, int sig_dbm)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        void *hdr;
        struct cfg80211_beacon_registration *reg;
@@ -11487,7 +11503,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
                                   struct cfg80211_wowlan_wakeup *wakeup,
                                   gfp_t gfp)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
        int size = 200;
@@ -11597,7 +11613,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
                                u16 reason_code, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -11649,9 +11665,15 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
        rcu_read_lock();
 
        list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
-               list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
+               bool schedule_destroy_work = false;
+
+               list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
                        cfg80211_mlme_unregister_socket(wdev, notify->portid);
 
+                       if (wdev->owner_nlportid == notify->portid)
+                               schedule_destroy_work = true;
+               }
+
                spin_lock_bh(&rdev->beacon_registrations_lock);
                list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
                                         list) {
@@ -11662,11 +11684,24 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
                        }
                }
                spin_unlock_bh(&rdev->beacon_registrations_lock);
+
+               if (schedule_destroy_work) {
+                       struct cfg80211_iface_destroy *destroy;
+
+                       destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
+                       if (destroy) {
+                               destroy->nlportid = notify->portid;
+                               spin_lock(&rdev->destroy_list_lock);
+                               list_add(&destroy->list, &rdev->destroy_list);
+                               spin_unlock(&rdev->destroy_list_lock);
+                               schedule_work(&rdev->destroy_work);
+                       }
+               }
        }
 
        rcu_read_unlock();
 
-       return NOTIFY_DONE;
+       return NOTIFY_OK;
 }
 
 static struct notifier_block nl80211_netlink_notifier = {
@@ -11677,7 +11712,7 @@ void cfg80211_ft_event(struct net_device *netdev,
                       struct cfg80211_ft_event_params *ft_event)
 {
        struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -11724,7 +11759,7 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
        void *hdr;
        u32 nlportid;
 
-       rdev = wiphy_to_dev(wdev->wiphy);
+       rdev = wiphy_to_rdev(wdev->wiphy);
        if (!rdev->crit_proto_nlportid)
                return;
 
@@ -11759,7 +11794,7 @@ EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
 void nl80211_send_ap_stopped(struct wireless_dev *wdev)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
        void *hdr;
 
index 74d97d33c938e8250ef300c2c3fb82d2a39b63b6..00cdf73ba6c468093df5b6c4a8567bf160f1c1e4 100644 (file)
@@ -950,4 +950,17 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static inline int
+rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev, struct cfg80211_chan_def *chandef)
+{
+       int ret;
+
+       trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, chandef);
+       ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, chandef);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+
+       return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
index f59aaac586f8cf10905135324c3913646910a662..e78f532aaa5b386f862f2679c006382f983e4fe0 100644 (file)
 #define REG_DBG_PRINT(args...)
 #endif
 
+/**
+ * enum reg_request_treatment - regulatory request treatment
+ *
+ * @REG_REQ_OK: continue processing the regulatory request
+ * @REG_REQ_IGNORE: ignore the regulatory request
+ * @REG_REQ_INTERSECT: the regulatory domain resulting from this request should
+ *     be intersected with the current one.
+ * @REG_REQ_ALREADY_SET: the regulatory request will not change the current
+ *     regulatory settings, and no further processing is required.
+ * @REG_REQ_USER_HINT_HANDLED: a non alpha2  user hint was handled and no
+ *     further processing is required, i.e., not need to update last_request
+ *     etc. This should be used for user hints that do not provide an alpha2
+ *     but some other type of regulatory hint, i.e., indoor operation.
+ */
 enum reg_request_treatment {
        REG_REQ_OK,
        REG_REQ_IGNORE,
        REG_REQ_INTERSECT,
        REG_REQ_ALREADY_SET,
+       REG_REQ_USER_HINT_HANDLED,
 };
 
 static struct regulatory_request core_request_world = {
@@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
  */
 static int reg_num_devs_support_basehint;
 
+/*
+ * State variable indicating if the platform on which the devices
+ * are attached is operating in an indoor environment. The state variable
+ * is relevant for all registered devices.
+ * (protected by RTNL)
+ */
+static bool reg_is_indoor;
+
 static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
 {
        return rtnl_dereference(cfg80211_regdomain);
@@ -240,8 +263,16 @@ static char user_alpha2[2];
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-static void reg_free_request(struct regulatory_request *lr)
+static void reg_free_request(struct regulatory_request *request)
 {
+       if (request != get_last_request())
+               kfree(request);
+}
+
+static void reg_free_last_request(void)
+{
+       struct regulatory_request *lr = get_last_request();
+
        if (lr != &core_request_world && lr)
                kfree_rcu(lr, rcu_head);
 }
@@ -254,7 +285,7 @@ static void reg_update_last_request(struct regulatory_request *request)
        if (lr == request)
                return;
 
-       reg_free_request(lr);
+       reg_free_last_request();
        rcu_assign_pointer(last_request, request);
 }
 
@@ -873,6 +904,8 @@ static u32 map_regdom_flags(u32 rd_flags)
                channel_flags |= IEEE80211_CHAN_RADAR;
        if (rd_flags & NL80211_RRF_NO_OFDM)
                channel_flags |= IEEE80211_CHAN_NO_OFDM;
+       if (rd_flags & NL80211_RRF_NO_OUTDOOR)
+               channel_flags |= IEEE80211_CHAN_INDOOR_ONLY;
        return channel_flags;
 }
 
@@ -902,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
                if (!band_rule_found)
                        band_rule_found = freq_in_rule_band(fr, center_freq);
 
-               bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
+               bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5));
 
                if (band_rule_found && bw_fits)
                        return rr;
@@ -986,10 +1019,10 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
 }
 #endif
 
-/*
- * Note that right now we assume the desired channel bandwidth
- * is always 20 MHz for each individual channel (HT40 uses 20 MHz
- * per channel, the primary and the extension channel).
+/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency
+ * chan->center_freq fits there.
+ * If there is no such reg_rule, disable the channel, otherwise set the
+ * flags corresponding to the bandwidths allowed in the particular reg_rule
  */
 static void handle_channel(struct wiphy *wiphy,
                           enum nl80211_reg_initiator initiator,
@@ -1050,8 +1083,12 @@ static void handle_channel(struct wiphy *wiphy,
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
+       if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+               bw_flags = IEEE80211_CHAN_NO_10MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
-               bw_flags = IEEE80211_CHAN_NO_HT40;
+               bw_flags |= IEEE80211_CHAN_NO_HT40;
        if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@@ -1071,6 +1108,13 @@ static void handle_channel(struct wiphy *wiphy,
                        (int) MBI_TO_DBI(power_rule->max_antenna_gain);
                chan->max_reg_power = chan->max_power = chan->orig_mpwr =
                        (int) MBM_TO_DBM(power_rule->max_eirp);
+
+               if (chan->flags & IEEE80211_CHAN_RADAR) {
+                       chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+                       if (reg_rule->dfs_cac_ms)
+                               chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
+               }
+
                return;
        }
 
@@ -1126,12 +1170,19 @@ static bool reg_request_cell_base(struct regulatory_request *request)
        return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
 }
 
+static bool reg_request_indoor(struct regulatory_request *request)
+{
+       if (request->initiator != NL80211_REGDOM_SET_BY_USER)
+               return false;
+       return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
+}
+
 bool reg_last_request_cell_base(void)
 {
        return reg_request_cell_base(get_last_request());
 }
 
-#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
+#ifdef CONFIG_CFG80211_REG_CELLULAR_HINTS
 /* Core specific check */
 static enum reg_request_treatment
 reg_ignore_cell_hint(struct regulatory_request *pending_request)
@@ -1471,8 +1522,12 @@ static void handle_channel_custom(struct wiphy *wiphy,
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
+       if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+               bw_flags = IEEE80211_CHAN_NO_10MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
-               bw_flags = IEEE80211_CHAN_NO_HT40;
+               bw_flags |= IEEE80211_CHAN_NO_HT40;
        if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@@ -1568,6 +1623,11 @@ __reg_process_hint_user(struct regulatory_request *user_request)
 {
        struct regulatory_request *lr = get_last_request();
 
+       if (reg_request_indoor(user_request)) {
+               reg_is_indoor = true;
+               return REG_REQ_USER_HINT_HANDLED;
+       }
+
        if (reg_request_cell_base(user_request))
                return reg_ignore_cell_hint(user_request);
 
@@ -1615,8 +1675,9 @@ reg_process_hint_user(struct regulatory_request *user_request)
 
        treatment = __reg_process_hint_user(user_request);
        if (treatment == REG_REQ_IGNORE ||
-           treatment == REG_REQ_ALREADY_SET) {
-               kfree(user_request);
+           treatment == REG_REQ_ALREADY_SET ||
+           treatment == REG_REQ_USER_HINT_HANDLED) {
+               reg_free_request(user_request);
                return treatment;
        }
 
@@ -1676,14 +1737,15 @@ reg_process_hint_driver(struct wiphy *wiphy,
        case REG_REQ_OK:
                break;
        case REG_REQ_IGNORE:
-               kfree(driver_request);
+       case REG_REQ_USER_HINT_HANDLED:
+               reg_free_request(driver_request);
                return treatment;
        case REG_REQ_INTERSECT:
                /* fall through */
        case REG_REQ_ALREADY_SET:
                regd = reg_copy_regd(get_cfg80211_regdom());
                if (IS_ERR(regd)) {
-                       kfree(driver_request);
+                       reg_free_request(driver_request);
                        return REG_REQ_IGNORE;
                }
                rcu_assign_pointer(wiphy->regd, regd);
@@ -1775,12 +1837,13 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
        case REG_REQ_OK:
                break;
        case REG_REQ_IGNORE:
+       case REG_REQ_USER_HINT_HANDLED:
                /* fall through */
        case REG_REQ_ALREADY_SET:
-               kfree(country_ie_request);
+               reg_free_request(country_ie_request);
                return treatment;
        case REG_REQ_INTERSECT:
-               kfree(country_ie_request);
+               reg_free_request(country_ie_request);
                /*
                 * This doesn't happen yet, not sure we
                 * ever want to support it for this case.
@@ -1841,7 +1904,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
        return;
 
 out_free:
-       kfree(reg_request);
+       reg_free_request(reg_request);
 }
 
 /*
@@ -1857,7 +1920,7 @@ static void reg_process_pending_hints(void)
 
        /* When last_request->processed becomes true this will be rescheduled */
        if (lr && !lr->processed) {
-               REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n");
+               reg_process_hint(lr);
                return;
        }
 
@@ -1967,6 +2030,22 @@ int regulatory_hint_user(const char *alpha2,
        return 0;
 }
 
+int regulatory_hint_indoor_user(void)
+{
+       struct regulatory_request *request;
+
+       request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+
+       request->wiphy_idx = WIPHY_IDX_INVALID;
+       request->initiator = NL80211_REGDOM_SET_BY_USER;
+       request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
+       queue_regulatory_request(request);
+
+       return 0;
+}
+
 /* Driver hints */
 int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
 {
@@ -2134,6 +2213,8 @@ static void restore_regulatory_settings(bool reset_user)
 
        ASSERT_RTNL();
 
+       reg_is_indoor = false;
+
        reset_regdomains(true, &world_regdom);
        restore_alpha2(alpha2, reset_user);
 
@@ -2594,7 +2675,7 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
                reg_num_devs_support_basehint--;
 
        rcu_free_regdom(get_wiphy_regdom(wiphy));
-       rcu_assign_pointer(wiphy->regd, NULL);
+       RCU_INIT_POINTER(wiphy->regd, NULL);
 
        if (lr)
                request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
@@ -2614,6 +2695,40 @@ static void reg_timeout_work(struct work_struct *work)
        rtnl_unlock();
 }
 
+/*
+ * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for
+ * UNII band definitions
+ */
+int cfg80211_get_unii(int freq)
+{
+       /* UNII-1 */
+       if (freq >= 5150 && freq <= 5250)
+               return 0;
+
+       /* UNII-2A */
+       if (freq > 5250 && freq <= 5350)
+               return 1;
+
+       /* UNII-2B */
+       if (freq > 5350 && freq <= 5470)
+               return 2;
+
+       /* UNII-2C */
+       if (freq > 5470 && freq <= 5725)
+               return 3;
+
+       /* UNII-3 */
+       if (freq > 5725 && freq <= 5825)
+               return 4;
+
+       return -EINVAL;
+}
+
+bool regulatory_indoor_allowed(void)
+{
+       return reg_is_indoor;
+}
+
 int __init regulatory_init(void)
 {
        int err = 0;
index 37c180df34b72a1195aacb6d72b7b07ddc44a9ef..5e48031ccb9afc33a41c36221e3bef924625ebe8 100644 (file)
@@ -25,6 +25,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
 
 int regulatory_hint_user(const char *alpha2,
                         enum nl80211_user_reg_hint_type user_reg_hint_type);
+int regulatory_hint_indoor_user(void);
 
 void wiphy_regulatory_register(struct wiphy *wiphy);
 void wiphy_regulatory_deregister(struct wiphy *wiphy);
@@ -104,4 +105,21 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
  */
 void regulatory_hint_disconnect(void);
 
+/**
+ * cfg80211_get_unii - get the U-NII band for the frequency
+ * @freq: the frequency for which we want to get the UNII band.
+
+ * Get a value specifying the U-NII band frequency belongs to.
+ * U-NII bands are defined by the FCC in C.F.R 47 part 15.
+ *
+ * Returns -EINVAL if freq is invalid, 0 for UNII-1, 1 for UNII-2A,
+ * 2 for UNII-2B, 3 for UNII-2C and 4 for UNII-3.
+ */
+int cfg80211_get_unii(int freq);
+
+/**
+ * regulatory_indoor_allowed - is indoor operation allowed
+ */
+bool regulatory_indoor_allowed(void);
+
 #endif  /* __NET_WIRELESS_REG_H */
index 7d09a712cb1f1353f13310f5c68b38e750d199a6..0f5da18cc6193b648a4a05f19aa6fe7627f5adbf 100644 (file)
@@ -81,10 +81,10 @@ static void bss_free(struct cfg80211_internal_bss *bss)
        kfree(bss);
 }
 
-static inline void bss_ref_get(struct cfg80211_registered_device *dev,
+static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
                               struct cfg80211_internal_bss *bss)
 {
-       lockdep_assert_held(&dev->bss_lock);
+       lockdep_assert_held(&rdev->bss_lock);
 
        bss->refcount++;
        if (bss->pub.hidden_beacon_bss) {
@@ -95,10 +95,10 @@ static inline void bss_ref_get(struct cfg80211_registered_device *dev,
        }
 }
 
-static inline void bss_ref_put(struct cfg80211_registered_device *dev,
+static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
                               struct cfg80211_internal_bss *bss)
 {
-       lockdep_assert_held(&dev->bss_lock);
+       lockdep_assert_held(&rdev->bss_lock);
 
        if (bss->pub.hidden_beacon_bss) {
                struct cfg80211_internal_bss *hbss;
@@ -114,10 +114,10 @@ static inline void bss_ref_put(struct cfg80211_registered_device *dev,
                bss_free(bss);
 }
 
-static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
+static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
                                  struct cfg80211_internal_bss *bss)
 {
-       lockdep_assert_held(&dev->bss_lock);
+       lockdep_assert_held(&rdev->bss_lock);
 
        if (!list_empty(&bss->hidden_list)) {
                /*
@@ -134,31 +134,31 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
        }
 
        list_del_init(&bss->list);
-       rb_erase(&bss->rbn, &dev->bss_tree);
-       bss_ref_put(dev, bss);
+       rb_erase(&bss->rbn, &rdev->bss_tree);
+       bss_ref_put(rdev, bss);
        return true;
 }
 
-static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
+static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
                                  unsigned long expire_time)
 {
        struct cfg80211_internal_bss *bss, *tmp;
        bool expired = false;
 
-       lockdep_assert_held(&dev->bss_lock);
+       lockdep_assert_held(&rdev->bss_lock);
 
-       list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
+       list_for_each_entry_safe(bss, tmp, &rdev->bss_list, list) {
                if (atomic_read(&bss->hold))
                        continue;
                if (!time_after(expire_time, bss->ts))
                        continue;
 
-               if (__cfg80211_unlink_bss(dev, bss))
+               if (__cfg80211_unlink_bss(rdev, bss))
                        expired = true;
        }
 
        if (expired)
-               dev->bss_generation++;
+               rdev->bss_generation++;
 }
 
 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
@@ -238,11 +238,11 @@ void __cfg80211_scan_done(struct work_struct *wk)
 void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
 {
        trace_cfg80211_scan_done(request, aborted);
-       WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+       WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
 
        request->aborted = aborted;
        request->notified = true;
-       queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
+       queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
 }
 EXPORT_SYMBOL(cfg80211_scan_done);
 
@@ -278,15 +278,15 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
 {
        trace_cfg80211_sched_scan_results(wiphy);
        /* ignore if we're not scanning */
-       if (wiphy_to_dev(wiphy)->sched_scan_req)
+       if (wiphy_to_rdev(wiphy)->sched_scan_req)
                queue_work(cfg80211_wq,
-                          &wiphy_to_dev(wiphy)->sched_scan_results_wk);
+                          &wiphy_to_rdev(wiphy)->sched_scan_results_wk);
 }
 EXPORT_SYMBOL(cfg80211_sched_scan_results);
 
 void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        trace_cfg80211_sched_scan_stopped(wiphy);
 
@@ -322,21 +322,21 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
        return 0;
 }
 
-void cfg80211_bss_age(struct cfg80211_registered_device *dev,
+void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
                       unsigned long age_secs)
 {
        struct cfg80211_internal_bss *bss;
        unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
 
-       spin_lock_bh(&dev->bss_lock);
-       list_for_each_entry(bss, &dev->bss_list, list)
+       spin_lock_bh(&rdev->bss_lock);
+       list_for_each_entry(bss, &rdev->bss_list, list)
                bss->ts -= age_jiffies;
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
 }
 
-void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
+void cfg80211_bss_expire(struct cfg80211_registered_device *rdev)
 {
-       __cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
+       __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
 }
 
 const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@@ -526,32 +526,34 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      const u8 *ssid, size_t ssid_len,
                                      u16 capa_mask, u16 capa_val)
 {
-       struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_internal_bss *bss, *res = NULL;
        unsigned long now = jiffies;
 
        trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
                               capa_val);
 
-       spin_lock_bh(&dev->bss_lock);
+       spin_lock_bh(&rdev->bss_lock);
 
-       list_for_each_entry(bss, &dev->bss_list, list) {
+       list_for_each_entry(bss, &rdev->bss_list, list) {
                if ((bss->pub.capability & capa_mask) != capa_val)
                        continue;
                if (channel && bss->pub.channel != channel)
                        continue;
+               if (!is_valid_ether_addr(bss->pub.bssid))
+                       continue;
                /* Don't get expired BSS structs */
                if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
                    !atomic_read(&bss->hold))
                        continue;
                if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
                        res = bss;
-                       bss_ref_get(dev, res);
+                       bss_ref_get(rdev, res);
                        break;
                }
        }
 
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
        if (!res)
                return NULL;
        trace_cfg80211_return_bss(&res->pub);
@@ -559,10 +561,10 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_get_bss);
 
-static void rb_insert_bss(struct cfg80211_registered_device *dev,
+static void rb_insert_bss(struct cfg80211_registered_device *rdev,
                          struct cfg80211_internal_bss *bss)
 {
-       struct rb_node **p = &dev->bss_tree.rb_node;
+       struct rb_node **p = &rdev->bss_tree.rb_node;
        struct rb_node *parent = NULL;
        struct cfg80211_internal_bss *tbss;
        int cmp;
@@ -585,15 +587,15 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev,
        }
 
        rb_link_node(&bss->rbn, parent, p);
-       rb_insert_color(&bss->rbn, &dev->bss_tree);
+       rb_insert_color(&bss->rbn, &rdev->bss_tree);
 }
 
 static struct cfg80211_internal_bss *
-rb_find_bss(struct cfg80211_registered_device *dev,
+rb_find_bss(struct cfg80211_registered_device *rdev,
            struct cfg80211_internal_bss *res,
            enum bss_compare_mode mode)
 {
-       struct rb_node *n = dev->bss_tree.rb_node;
+       struct rb_node *n = rdev->bss_tree.rb_node;
        struct cfg80211_internal_bss *bss;
        int r;
 
@@ -612,7 +614,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
        return NULL;
 }
 
-static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
+static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
                                   struct cfg80211_internal_bss *new)
 {
        const struct cfg80211_bss_ies *ies;
@@ -642,7 +644,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
 
        /* This is the bad part ... */
 
-       list_for_each_entry(bss, &dev->bss_list, list) {
+       list_for_each_entry(bss, &rdev->bss_list, list) {
                if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
                        continue;
                if (bss->pub.channel != new->pub.channel)
@@ -676,7 +678,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
 
 /* Returned bss is reference counted and must be cleaned up appropriately. */
 static struct cfg80211_internal_bss *
-cfg80211_bss_update(struct cfg80211_registered_device *dev,
+cfg80211_bss_update(struct cfg80211_registered_device *rdev,
                    struct cfg80211_internal_bss *tmp,
                    bool signal_valid)
 {
@@ -687,14 +689,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
        tmp->ts = jiffies;
 
-       spin_lock_bh(&dev->bss_lock);
+       spin_lock_bh(&rdev->bss_lock);
 
        if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) {
-               spin_unlock_bh(&dev->bss_lock);
+               spin_unlock_bh(&rdev->bss_lock);
                return NULL;
        }
 
-       found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);
+       found = rb_find_bss(rdev, tmp, BSS_CMP_REGULAR);
 
        if (found) {
                /* Update IEs */
@@ -781,7 +783,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                 * is allocated on the stack since it's not needed in the
                 * more common case of an update
                 */
-               new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size,
+               new = kzalloc(sizeof(*new) + rdev->wiphy.bss_priv_size,
                              GFP_ATOMIC);
                if (!new) {
                        ies = (void *)rcu_dereference(tmp->pub.beacon_ies);
@@ -797,9 +799,9 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                INIT_LIST_HEAD(&new->hidden_list);
 
                if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
-                       hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN);
+                       hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
                        if (!hidden)
-                               hidden = rb_find_bss(dev, tmp,
+                               hidden = rb_find_bss(rdev, tmp,
                                                     BSS_CMP_HIDE_NUL);
                        if (hidden) {
                                new->pub.hidden_beacon_bss = &hidden->pub;
@@ -816,24 +818,24 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                         * expensive search for any probe responses that should
                         * be grouped with this beacon for updates ...
                         */
-                       if (!cfg80211_combine_bsses(dev, new)) {
+                       if (!cfg80211_combine_bsses(rdev, new)) {
                                kfree(new);
                                goto drop;
                        }
                }
 
-               list_add_tail(&new->list, &dev->bss_list);
-               rb_insert_bss(dev, new);
+               list_add_tail(&new->list, &rdev->bss_list);
+               rb_insert_bss(rdev, new);
                found = new;
        }
 
-       dev->bss_generation++;
-       bss_ref_get(dev, found);
-       spin_unlock_bh(&dev->bss_lock);
+       rdev->bss_generation++;
+       bss_ref_get(rdev, found);
+       spin_unlock_bh(&rdev->bss_lock);
 
        return found;
  drop:
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
        return NULL;
 }
 
@@ -917,7 +919,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
        rcu_assign_pointer(tmp.pub.beacon_ies, ies);
        rcu_assign_pointer(tmp.pub.ies, ies);
 
-       res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
+       res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp,
                                  rx_channel == channel);
        if (!res)
                return NULL;
@@ -989,7 +991,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
        tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
        tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
 
-       res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
+       res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp,
                                  rx_channel == channel);
        if (!res)
                return NULL;
@@ -1005,7 +1007,7 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width_frame);
 
 void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 {
-       struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_internal_bss *bss;
 
        if (!pub)
@@ -1013,15 +1015,15 @@ void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 
        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 
-       spin_lock_bh(&dev->bss_lock);
-       bss_ref_get(dev, bss);
-       spin_unlock_bh(&dev->bss_lock);
+       spin_lock_bh(&rdev->bss_lock);
+       bss_ref_get(rdev, bss);
+       spin_unlock_bh(&rdev->bss_lock);
 }
 EXPORT_SYMBOL(cfg80211_ref_bss);
 
 void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 {
-       struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_internal_bss *bss;
 
        if (!pub)
@@ -1029,15 +1031,15 @@ void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 
        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 
-       spin_lock_bh(&dev->bss_lock);
-       bss_ref_put(dev, bss);
-       spin_unlock_bh(&dev->bss_lock);
+       spin_lock_bh(&rdev->bss_lock);
+       bss_ref_put(rdev, bss);
+       spin_unlock_bh(&rdev->bss_lock);
 }
 EXPORT_SYMBOL(cfg80211_put_bss);
 
 void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 {
-       struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_internal_bss *bss;
 
        if (WARN_ON(!pub))
@@ -1045,12 +1047,12 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 
        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 
-       spin_lock_bh(&dev->bss_lock);
+       spin_lock_bh(&rdev->bss_lock);
        if (!list_empty(&bss->list)) {
-               if (__cfg80211_unlink_bss(dev, bss))
-                       dev->bss_generation++;
+               if (__cfg80211_unlink_bss(rdev, bss))
+                       rdev->bss_generation++;
        }
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
 }
 EXPORT_SYMBOL(cfg80211_unlink_bss);
 
@@ -1067,7 +1069,7 @@ cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
        if (!dev)
                return ERR_PTR(-ENODEV);
        if (dev->ieee80211_ptr)
-               rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+               rdev = wiphy_to_rdev(dev->ieee80211_ptr->wiphy);
        else
                rdev = ERR_PTR(-ENODEV);
        dev_put(dev);
@@ -1147,7 +1149,11 @@ int cfg80211_wext_siwscan(struct net_device *dev,
                                int k;
                                int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
                                for (k = 0; k < wreq->num_channels; k++) {
-                                       int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]);
+                                       struct iw_freq *freq =
+                                               &wreq->channel_list[k];
+                                       int wext_freq =
+                                               cfg80211_wext_freq(freq);
+
                                        if (wext_freq == wiphy_freq)
                                                goto wext_freq_found;
                                }
@@ -1459,7 +1465,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
 }
 
 
-static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
+static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
                                  struct iw_request_info *info,
                                  char *buf, size_t len)
 {
@@ -1467,18 +1473,18 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
        char *end_buf = buf + len;
        struct cfg80211_internal_bss *bss;
 
-       spin_lock_bh(&dev->bss_lock);
-       cfg80211_bss_expire(dev);
+       spin_lock_bh(&rdev->bss_lock);
+       cfg80211_bss_expire(rdev);
 
-       list_for_each_entry(bss, &dev->bss_list, list) {
+       list_for_each_entry(bss, &rdev->bss_list, list) {
                if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
-                       spin_unlock_bh(&dev->bss_lock);
+                       spin_unlock_bh(&rdev->bss_lock);
                        return -E2BIG;
                }
-               current_ev = ieee80211_bss(&dev->wiphy, info, bss,
+               current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
                                           current_ev, end_buf);
        }
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
        return current_ev - buf;
 }
 
index acdcb4a81817b7c78e8e721ff632284b9b806fa9..e2923a3f2e5c633aedc44c97e450dc1f0a8eb5bd 100644 (file)
@@ -59,7 +59,7 @@ static void cfg80211_sme_free(struct wireless_dev *wdev)
 
 static int cfg80211_conn_scan(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_scan_request *request;
        int n_channels, err;
 
@@ -130,7 +130,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
 
 static int cfg80211_conn_do_work(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_connect_params *params;
        struct cfg80211_assoc_request req = {};
        int err;
@@ -245,7 +245,7 @@ void cfg80211_conn_work(struct work_struct *work)
 /* Returned bss is reference counted and must be cleaned up appropriately. */
 static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_bss *bss;
        u16 capa = WLAN_CAPABILITY_ESS;
 
@@ -275,7 +275,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
 static void __cfg80211_sme_scan_done(struct net_device *dev)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_bss *bss;
 
        ASSERT_WDEV_LOCK(wdev);
@@ -306,7 +306,7 @@ void cfg80211_sme_scan_done(struct net_device *dev)
 void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
 {
        struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
@@ -352,7 +352,7 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
 
 bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        if (!wdev->conn)
                return false;
@@ -386,7 +386,7 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev)
 
 void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        if (!wdev->conn)
                return;
@@ -397,7 +397,7 @@ void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 
 void cfg80211_sme_disassoc(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        if (!wdev->conn)
                return;
@@ -408,7 +408,7 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev)
 
 void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 
        if (!wdev->conn)
                return;
@@ -421,7 +421,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
                                struct cfg80211_connect_params *connect,
                                const u8 *prev_bssid)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_bss *bss;
        int err;
 
@@ -468,7 +468,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
        }
 
        wdev->conn->params.ssid = wdev->ssid;
-       wdev->conn->params.ssid_len = connect->ssid_len;
+       wdev->conn->params.ssid_len = wdev->ssid_len;
 
        /* see if we have the bss already */
        bss = cfg80211_get_conn_bss(wdev);
@@ -480,7 +480,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
 
        /* we're good if we have a matching bss struct */
        if (bss) {
-               wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
                err = cfg80211_conn_do_work(wdev);
                cfg80211_put_bss(wdev->wiphy, bss);
        } else {
@@ -506,7 +505,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
 
 static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        int err;
 
        if (!wdev->conn)
@@ -594,7 +593,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                return;
        }
 
-       nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
+       nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
                                    bssid, req_ie, req_ie_len,
                                    resp_ie, resp_ie_len,
                                    status, GFP_KERNEL);
@@ -625,7 +624,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 #endif
 
        if (!bss && (status == WLAN_STATUS_SUCCESS)) {
-               WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect);
+               WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
                bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
                                       wdev->ssid, wdev->ssid_len,
                                       WLAN_CAPABILITY_ESS,
@@ -687,7 +686,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                             u16 status, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
@@ -742,7 +741,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
        cfg80211_hold_bss(bss_from_pub(bss));
        wdev->current_bss = bss_from_pub(bss);
 
-       nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bss->bssid,
+       nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
+                           wdev->netdev, bss->bssid,
                            req_ie, req_ie_len, resp_ie, resp_ie_len,
                            GFP_KERNEL);
 
@@ -801,7 +801,7 @@ void cfg80211_roamed_bss(struct net_device *dev,
                         size_t resp_ie_len, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
@@ -834,7 +834,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                             size_t ie_len, u16 reason, bool from_ap)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        int i;
 #ifdef CONFIG_CFG80211_WEXT
        union iwreq_data wrqu;
@@ -880,7 +880,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
                           u8 *ie, size_t ie_len, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
index aabccf13e07b6860ef92ddc637a7879a8f961aab..f3c13ff4d04c8742c028126970938233da10b1d2 100644 (file)
@@ -1919,6 +1919,24 @@ TRACE_EVENT(rdev_set_qos_map,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des)
 );
 
+TRACE_EVENT(rdev_set_ap_chanwidth,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_chan_def *chandef),
+       TP_ARGS(wiphy, netdev, chandef),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               CHAN_DEF_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               CHAN_DEF_ASSIGN(chandef);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
+);
+
 /*************************************************************
  *          cfg80211 exported functions traces              *
  *************************************************************/
@@ -2193,18 +2211,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
 );
 
 TRACE_EVENT(cfg80211_reg_can_beacon,
-       TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
-       TP_ARGS(wiphy, chandef),
+       TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
+                enum nl80211_iftype iftype),
+       TP_ARGS(wiphy, chandef, iftype),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                CHAN_DEF_ENTRY
+               __field(enum nl80211_iftype, iftype)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                CHAN_DEF_ASSIGN(chandef);
+               __entry->iftype = iftype;
        ),
-       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
-                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
+                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
 );
 
 TRACE_EVENT(cfg80211_chandef_dfs_required,
index e5872ff2c27ca8989ca6da7cfdf4d7041c29a72e..7c47fa07b276f90ad870cb9789aa8c5b8fb63521 100644 (file)
@@ -770,7 +770,7 @@ EXPORT_SYMBOL(ieee80211_bss_get_ie);
 
 void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct net_device *dev = wdev->netdev;
        int i;
 
@@ -888,11 +888,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                return -EBUSY;
 
        if (ntype != otype && netif_running(dev)) {
-               err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
-                                                   ntype);
-               if (err)
-                       return err;
-
                dev->ieee80211_ptr->use_4addr = false;
                dev->ieee80211_ptr->mesh_id_up_len = 0;
                wdev_lock(dev->ieee80211_ptr);
@@ -1268,6 +1263,106 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
        return res;
 }
 
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+                              const int num_different_channels,
+                              const u8 radar_detect,
+                              const int iftype_num[NUM_NL80211_IFTYPES],
+                              void (*iter)(const struct ieee80211_iface_combination *c,
+                                           void *data),
+                              void *data)
+{
+       int i, j, iftype;
+       int num_interfaces = 0;
+       u32 used_iftypes = 0;
+
+       for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+               num_interfaces += iftype_num[iftype];
+               if (iftype_num[iftype] > 0 &&
+                   !(wiphy->software_iftypes & BIT(iftype)))
+                       used_iftypes |= BIT(iftype);
+       }
+
+       for (i = 0; i < wiphy->n_iface_combinations; i++) {
+               const struct ieee80211_iface_combination *c;
+               struct ieee80211_iface_limit *limits;
+               u32 all_iftypes = 0;
+
+               c = &wiphy->iface_combinations[i];
+
+               if (num_interfaces > c->max_interfaces)
+                       continue;
+               if (num_different_channels > c->num_different_channels)
+                       continue;
+
+               limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
+                                GFP_KERNEL);
+               if (!limits)
+                       return -ENOMEM;
+
+               for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+                       if (wiphy->software_iftypes & BIT(iftype))
+                               continue;
+                       for (j = 0; j < c->n_limits; j++) {
+                               all_iftypes |= limits[j].types;
+                               if (!(limits[j].types & BIT(iftype)))
+                                       continue;
+                               if (limits[j].max < iftype_num[iftype])
+                                       goto cont;
+                               limits[j].max -= iftype_num[iftype];
+                       }
+               }
+
+               if (radar_detect != (c->radar_detect_widths & radar_detect))
+                       goto cont;
+
+               /* Finally check that all iftypes that we're currently
+                * using are actually part of this combination. If they
+                * aren't then we can't use this combination and have
+                * to continue to the next.
+                */
+               if ((all_iftypes & used_iftypes) != used_iftypes)
+                       goto cont;
+
+               /* This combination covered all interface types and
+                * supported the requested numbers, so we're good.
+                */
+
+               (*iter)(c, data);
+ cont:
+               kfree(limits);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+                         void *data)
+{
+       int *num = data;
+       (*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+                               const int num_different_channels,
+                               const u8 radar_detect,
+                               const int iftype_num[NUM_NL80211_IFTYPES])
+{
+       int err, num = 0;
+
+       err = cfg80211_iter_combinations(wiphy, num_different_channels,
+                                        radar_detect, iftype_num,
+                                        cfg80211_iter_sum_ifcombs, &num);
+       if (err)
+               return err;
+       if (num == 0)
+               return -EBUSY;
+
+       return 0;
+}
+EXPORT_SYMBOL(cfg80211_check_combinations);
+
 int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 enum nl80211_iftype iftype,
@@ -1276,7 +1371,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 u8 radar_detect)
 {
        struct wireless_dev *wdev_iter;
-       u32 used_iftypes = BIT(iftype);
        int num[NUM_NL80211_IFTYPES];
        struct ieee80211_channel
                        *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
@@ -1284,7 +1378,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        enum cfg80211_chan_mode chmode;
        int num_different_channels = 0;
        int total = 1;
-       int i, j;
+       int i;
 
        ASSERT_RTNL();
 
@@ -1306,6 +1400,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 
        num[iftype] = 1;
 
+       /* TODO: We'll probably not need this anymore, since this
+        * should only be called with CHAN_MODE_UNDEFINED. There are
+        * still a couple of pending calls where other chanmodes are
+        * used, but we should get rid of them.
+        */
        switch (chanmode) {
        case CHAN_MODE_UNDEFINED:
                break;
@@ -1369,65 +1468,13 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 
                num[wdev_iter->iftype]++;
                total++;
-               used_iftypes |= BIT(wdev_iter->iftype);
        }
 
        if (total == 1 && !radar_detect)
                return 0;
 
-       for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
-               const struct ieee80211_iface_combination *c;
-               struct ieee80211_iface_limit *limits;
-               u32 all_iftypes = 0;
-
-               c = &rdev->wiphy.iface_combinations[i];
-
-               if (total > c->max_interfaces)
-                       continue;
-               if (num_different_channels > c->num_different_channels)
-                       continue;
-
-               limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
-                                GFP_KERNEL);
-               if (!limits)
-                       return -ENOMEM;
-
-               for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
-                       if (rdev->wiphy.software_iftypes & BIT(iftype))
-                               continue;
-                       for (j = 0; j < c->n_limits; j++) {
-                               all_iftypes |= limits[j].types;
-                               if (!(limits[j].types & BIT(iftype)))
-                                       continue;
-                               if (limits[j].max < num[iftype])
-                                       goto cont;
-                               limits[j].max -= num[iftype];
-                       }
-               }
-
-               if (radar_detect && !(c->radar_detect_widths & radar_detect))
-                       goto cont;
-
-               /*
-                * Finally check that all iftypes that we're currently
-                * using are actually part of this combination. If they
-                * aren't then we can't use this combination and have
-                * to continue to the next.
-                */
-               if ((all_iftypes & used_iftypes) != used_iftypes)
-                       goto cont;
-
-               /*
-                * This combination covered all interface types and
-                * supported the requested numbers, so we're good.
-                */
-               kfree(limits);
-               return 0;
- cont:
-               kfree(limits);
-       }
-
-       return -EBUSY;
+       return cfg80211_check_combinations(&rdev->wiphy, num_different_channels,
+                                          radar_detect, num);
 }
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
index 5661a54ac7ee4ed1c1865d855e1b2681c67d07cc..11120bb14162505043579628bed2ad131ba41f7d 100644 (file)
@@ -73,7 +73,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
        struct vif_params vifparams;
        enum nl80211_iftype type;
 
-       rdev = wiphy_to_dev(wdev->wiphy);
+       rdev = wiphy_to_rdev(wdev->wiphy);
 
        switch (*mode) {
        case IW_MODE_INFRA:
@@ -253,12 +253,12 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
 
 /**
  * cfg80211_wext_freq - get wext frequency for non-"auto"
- * @wiphy: the wiphy
+ * @dev: the net device
  * @freq: the wext freq encoding
  *
  * Returns a frequency, or a negative error code, or 0 for auto.
  */
-int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
+int cfg80211_wext_freq(struct iw_freq *freq)
 {
        /*
         * Parse frequency - return 0 for auto and
@@ -286,7 +286,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
                         struct iw_param *rts, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        u32 orts = wdev->wiphy->rts_threshold;
        int err;
 
@@ -324,7 +324,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
                          struct iw_param *frag, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        u32 ofrag = wdev->wiphy->frag_threshold;
        int err;
 
@@ -364,7 +364,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev,
                                  struct iw_param *retry, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        u32 changed = 0;
        u8 olong = wdev->wiphy->retry_long;
        u8 oshort = wdev->wiphy->retry_short;
@@ -587,7 +587,7 @@ static int cfg80211_wext_siwencode(struct net_device *dev,
                                   struct iw_point *erq, char *keybuf)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        int idx, err;
        bool remove = false;
        struct key_params params;
@@ -647,7 +647,7 @@ static int cfg80211_wext_siwencodeext(struct net_device *dev,
                                      struct iw_point *erq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
        const u8 *addr;
        int idx;
@@ -775,7 +775,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
                                 struct iw_freq *wextfreq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_chan_def chandef = {
                .width = NL80211_CHAN_WIDTH_20_NOHT,
        };
@@ -787,7 +787,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
        case NL80211_IFTYPE_MONITOR:
-               freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+               freq = cfg80211_wext_freq(wextfreq);
                if (freq < 0)
                        return freq;
                if (freq == 0)
@@ -798,7 +798,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
                        return -EINVAL;
                return cfg80211_set_monitor_channel(rdev, &chandef);
        case NL80211_IFTYPE_MESH_POINT:
-               freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+               freq = cfg80211_wext_freq(wextfreq);
                if (freq < 0)
                        return freq;
                if (freq == 0)
@@ -818,7 +818,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                                 struct iw_freq *freq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_chan_def chandef;
        int ret;
 
@@ -847,7 +847,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
                                    union iwreq_data *data, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        enum nl80211_tx_power_setting type;
        int dbm = 0;
 
@@ -899,7 +899,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
                                    union iwreq_data *data, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        int err, val;
 
        if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
@@ -1119,7 +1119,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev,
                                  struct iw_param *wrq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        bool ps = wdev->ps;
        int timeout = wdev->ps_timeout;
        int err;
@@ -1177,7 +1177,7 @@ static int cfg80211_wds_wext_siwap(struct net_device *dev,
                                   struct sockaddr *addr, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        int err;
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
@@ -1221,7 +1221,7 @@ static int cfg80211_wext_siwrate(struct net_device *dev,
                                 struct iw_param *rate, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_bitrate_mask mask;
        u32 fixed, maxrate;
        struct ieee80211_supported_band *sband;
@@ -1272,7 +1272,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
                                 struct iw_param *rate, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        /* we are under RTNL - globally locked - so can use a static struct */
        static struct station_info sinfo;
        u8 addr[ETH_ALEN];
@@ -1310,7 +1310,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
 static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        /* we are under RTNL - globally locked - so can use static structs */
        static struct iw_statistics wstats;
        static struct station_info sinfo;
@@ -1449,7 +1449,7 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev,
                                  struct iw_point *data, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_pmksa cfg_pmksa;
        struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
 
index 5d766b0118e81969ff4f24c59b88bffdaa6496ff..ebcacca2f731941123efb22c8067a6c34aaa9ea1 100644 (file)
@@ -50,7 +50,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
                           struct iw_point *data, char *extra);
 
 
-int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq);
+int cfg80211_wext_freq(struct iw_freq *freq);
 
 
 extern const struct iw_handler_def cfg80211_wext_handler;
index 86c331a65664a77bfe6c083224b7eae2c91f5b9c..c7e5c8eb4f24708a27d90ae298a85c825ee81e38 100644 (file)
@@ -67,7 +67,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
                              struct iw_freq *wextfreq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct ieee80211_channel *chan = NULL;
        int err, freq;
 
@@ -75,7 +75,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
                return -EINVAL;
 
-       freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+       freq = cfg80211_wext_freq(wextfreq);
        if (freq < 0)
                return freq;
 
@@ -169,7 +169,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
                               struct iw_point *data, char *ssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        size_t len = data->length;
        int err;
 
@@ -260,7 +260,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
                            struct sockaddr *ap_addr, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        u8 *bssid = ap_addr->sa_data;
        int err;
 
@@ -333,7 +333,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
                           struct iw_point *data, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        u8 *ie = extra;
        int ie_len = data->length, err;
 
@@ -390,7 +390,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
        if (!wdev)
                return -EOPNOTSUPP;
 
-       rdev = wiphy_to_dev(wdev->wiphy);
+       rdev = wiphy_to_rdev(wdev->wiphy);
 
        if (wdev->iftype != NL80211_IFTYPE_STATION)
                return -EINVAL;
index c08fbd11ceff52ee145316a33758feb30667f02d..375267d15c8f2ad61b8bce3be7af8443a0788f08 100644 (file)
@@ -769,7 +769,7 @@ EXPORT_SYMBOL(xfrm_policy_byid);
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 static inline int
-xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info)
+xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
 {
        int dir, err = 0;
 
@@ -783,10 +783,7 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi
                                continue;
                        err = security_xfrm_policy_delete(pol->security);
                        if (err) {
-                               xfrm_audit_policy_delete(pol, 0,
-                                                        audit_info->loginuid,
-                                                        audit_info->sessionid,
-                                                        audit_info->secid);
+                               xfrm_audit_policy_delete(pol, 0, task_valid);
                                return err;
                        }
                }
@@ -800,9 +797,7 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi
                                                                pol->security);
                                if (err) {
                                        xfrm_audit_policy_delete(pol, 0,
-                                                       audit_info->loginuid,
-                                                       audit_info->sessionid,
-                                                       audit_info->secid);
+                                                                task_valid);
                                        return err;
                                }
                        }
@@ -812,19 +807,19 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi
 }
 #else
 static inline int
-xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info)
+xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
 {
        return 0;
 }
 #endif
 
-int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
+int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
 {
        int dir, err = 0, cnt = 0;
 
        write_lock_bh(&net->xfrm.xfrm_policy_lock);
 
-       err = xfrm_policy_flush_secctx_check(net, type, audit_info);
+       err = xfrm_policy_flush_secctx_check(net, type, task_valid);
        if (err)
                goto out;
 
@@ -841,9 +836,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                        write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                        cnt++;
 
-                       xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
-                                                audit_info->sessionid,
-                                                audit_info->secid);
+                       xfrm_audit_policy_delete(pol, 1, task_valid);
 
                        xfrm_policy_kill(pol);
 
@@ -862,10 +855,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                                write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                                cnt++;
 
-                               xfrm_audit_policy_delete(pol, 1,
-                                                        audit_info->loginuid,
-                                                        audit_info->sessionid,
-                                                        audit_info->secid);
+                               xfrm_audit_policy_delete(pol, 1, task_valid);
                                xfrm_policy_kill(pol);
 
                                write_lock_bh(&net->xfrm.xfrm_policy_lock);
@@ -2862,21 +2852,14 @@ out_byidx:
 
 static void xfrm_policy_fini(struct net *net)
 {
-       struct xfrm_audit audit_info;
        unsigned int sz;
        int dir;
 
        flush_work(&net->xfrm.policy_hash_work);
 #ifdef CONFIG_XFRM_SUB_POLICY
-       audit_info.loginuid = INVALID_UID;
-       audit_info.sessionid = (unsigned int)-1;
-       audit_info.secid = 0;
-       xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info);
+       xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false);
 #endif
-       audit_info.loginuid = INVALID_UID;
-       audit_info.sessionid = (unsigned int)-1;
-       audit_info.secid = 0;
-       xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
+       xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
 
        WARN_ON(!list_empty(&net->xfrm.policy_all));
 
@@ -2991,15 +2974,14 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
        }
 }
 
-void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
-                          kuid_t auid, unsigned int sessionid, u32 secid)
+void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid)
 {
        struct audit_buffer *audit_buf;
 
        audit_buf = xfrm_audit_start("SPD-add");
        if (audit_buf == NULL)
                return;
-       xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
+       xfrm_audit_helper_usrinfo(task_valid, audit_buf);
        audit_log_format(audit_buf, " res=%u", result);
        xfrm_audit_common_policyinfo(xp, audit_buf);
        audit_log_end(audit_buf);
@@ -3007,14 +2989,14 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
 EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
 
 void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
-                             kuid_t auid, unsigned int sessionid, u32 secid)
+                             bool task_valid)
 {
        struct audit_buffer *audit_buf;
 
        audit_buf = xfrm_audit_start("SPD-delete");
        if (audit_buf == NULL)
                return;
-       xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
+       xfrm_audit_helper_usrinfo(task_valid, audit_buf);
        audit_log_format(audit_buf, " res=%u", result);
        xfrm_audit_common_policyinfo(xp, audit_buf);
        audit_log_end(audit_buf);
index 8e9c781a6bbaaba83e4af4a31ac7a07a70dd6c71..0ab54134bb40b84cf825df6035a9acf7cb3cf760 100644 (file)
@@ -463,9 +463,7 @@ expired:
        if (!err)
                km_state_expired(x, 1, 0);
 
-       xfrm_audit_state_delete(x, err ? 0 : 1,
-                               audit_get_loginuid(current),
-                               audit_get_sessionid(current), 0);
+       xfrm_audit_state_delete(x, err ? 0 : 1, true);
 
 out:
        spin_unlock(&x->lock);
@@ -562,7 +560,7 @@ EXPORT_SYMBOL(xfrm_state_delete);
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 static inline int
-xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
+xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
 {
        int i, err = 0;
 
@@ -572,10 +570,7 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi
                hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
                        if (xfrm_id_proto_match(x->id.proto, proto) &&
                           (err = security_xfrm_state_delete(x)) != 0) {
-                               xfrm_audit_state_delete(x, 0,
-                                                       audit_info->loginuid,
-                                                       audit_info->sessionid,
-                                                       audit_info->secid);
+                               xfrm_audit_state_delete(x, 0, task_valid);
                                return err;
                        }
                }
@@ -585,18 +580,18 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi
 }
 #else
 static inline int
-xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
+xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
 {
        return 0;
 }
 #endif
 
-int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
+int xfrm_state_flush(struct net *net, u8 proto, bool task_valid)
 {
        int i, err = 0, cnt = 0;
 
        spin_lock_bh(&net->xfrm.xfrm_state_lock);
-       err = xfrm_state_flush_secctx_check(net, proto, audit_info);
+       err = xfrm_state_flush_secctx_check(net, proto, task_valid);
        if (err)
                goto out;
 
@@ -612,9 +607,7 @@ restart:
 
                                err = xfrm_state_delete(x);
                                xfrm_audit_state_delete(x, err ? 0 : 1,
-                                                       audit_info->loginuid,
-                                                       audit_info->sessionid,
-                                                       audit_info->secid);
+                                                       task_valid);
                                xfrm_state_put(x);
                                if (!err)
                                        cnt++;
@@ -2128,14 +2121,10 @@ out_bydst:
 
 void xfrm_state_fini(struct net *net)
 {
-       struct xfrm_audit audit_info;
        unsigned int sz;
 
        flush_work(&net->xfrm.state_hash_work);
-       audit_info.loginuid = INVALID_UID;
-       audit_info.sessionid = (unsigned int)-1;
-       audit_info.secid = 0;
-       xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info);
+       xfrm_state_flush(net, IPSEC_PROTO_ANY, false);
        flush_work(&net->xfrm.state_gc_work);
 
        WARN_ON(!list_empty(&net->xfrm.state_all));
@@ -2198,30 +2187,28 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
        }
 }
 
-void xfrm_audit_state_add(struct xfrm_state *x, int result,
-                         kuid_t auid, unsigned int sessionid, u32 secid)
+void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid)
 {
        struct audit_buffer *audit_buf;
 
        audit_buf = xfrm_audit_start("SAD-add");
        if (audit_buf == NULL)
                return;
-       xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
+       xfrm_audit_helper_usrinfo(task_valid, audit_buf);
        xfrm_audit_helper_sainfo(x, audit_buf);
        audit_log_format(audit_buf, " res=%u", result);
        audit_log_end(audit_buf);
 }
 EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
 
-void xfrm_audit_state_delete(struct xfrm_state *x, int result,
-                            kuid_t auid, unsigned int sessionid, u32 secid)
+void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid)
 {
        struct audit_buffer *audit_buf;
 
        audit_buf = xfrm_audit_start("SAD-delete");
        if (audit_buf == NULL)
                return;
-       xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
+       xfrm_audit_helper_usrinfo(task_valid, audit_buf);
        xfrm_audit_helper_sainfo(x, audit_buf);
        audit_log_format(audit_buf, " res=%u", result);
        audit_log_end(audit_buf);
index 8f131c10a6f3d6793c6d0a049108ab66ccaa8664..fd9a16a6d1de36faad11b3a8a4676cac61969f37 100644 (file)
@@ -597,9 +597,6 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct xfrm_state *x;
        int err;
        struct km_event c;
-       kuid_t loginuid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       u32 sid;
 
        err = verify_newsa_info(p, attrs);
        if (err)
@@ -615,8 +612,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
        else
                err = xfrm_state_update(x);
 
-       security_task_getsecid(current, &sid);
-       xfrm_audit_state_add(x, err ? 0 : 1, loginuid, sessionid, sid);
+       xfrm_audit_state_add(x, err ? 0 : 1, true);
 
        if (err < 0) {
                x->km.state = XFRM_STATE_DEAD;
@@ -676,9 +672,6 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
        int err = -ESRCH;
        struct km_event c;
        struct xfrm_usersa_id *p = nlmsg_data(nlh);
-       kuid_t loginuid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       u32 sid;
 
        x = xfrm_user_state_lookup(net, p, attrs, &err);
        if (x == NULL)
@@ -703,8 +696,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
        km_state_notify(x, &c);
 
 out:
-       security_task_getsecid(current, &sid);
-       xfrm_audit_state_delete(x, err ? 0 : 1, loginuid, sessionid, sid);
+       xfrm_audit_state_delete(x, err ? 0 : 1, true);
        xfrm_state_put(x);
        return err;
 }
@@ -1414,9 +1406,6 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct km_event c;
        int err;
        int excl;
-       kuid_t loginuid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       u32 sid;
 
        err = verify_newpolicy_info(p);
        if (err)
@@ -1435,8 +1424,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
         * a type XFRM_MSG_UPDPOLICY - JHS */
        excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
        err = xfrm_policy_insert(p->dir, xp, excl);
-       security_task_getsecid(current, &sid);
-       xfrm_audit_policy_add(xp, err ? 0 : 1, loginuid, sessionid, sid);
+       xfrm_audit_policy_add(xp, err ? 0 : 1, true);
 
        if (err) {
                security_xfrm_policy_free(xp->security);
@@ -1673,13 +1661,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
                                            NETLINK_CB(skb).portid);
                }
        } else {
-               kuid_t loginuid = audit_get_loginuid(current);
-               unsigned int sessionid = audit_get_sessionid(current);
-               u32 sid;
-
-               security_task_getsecid(current, &sid);
-               xfrm_audit_policy_delete(xp, err ? 0 : 1, loginuid, sessionid,
-                                        sid);
+               xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
 
                if (err != 0)
                        goto out;
@@ -1704,13 +1686,9 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct net *net = sock_net(skb->sk);
        struct km_event c;
        struct xfrm_usersa_flush *p = nlmsg_data(nlh);
-       struct xfrm_audit audit_info;
        int err;
 
-       audit_info.loginuid = audit_get_loginuid(current);
-       audit_info.sessionid = audit_get_sessionid(current);
-       security_task_getsecid(current, &audit_info.secid);
-       err = xfrm_state_flush(net, p->proto, &audit_info);
+       err = xfrm_state_flush(net, p->proto, true);
        if (err) {
                if (err == -ESRCH) /* empty table */
                        return 0;
@@ -1894,16 +1872,12 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct km_event c;
        u8 type = XFRM_POLICY_TYPE_MAIN;
        int err;
-       struct xfrm_audit audit_info;
 
        err = copy_from_user_policy_type(&type, attrs);
        if (err)
                return err;
 
-       audit_info.loginuid = audit_get_loginuid(current);
-       audit_info.sessionid = audit_get_sessionid(current);
-       security_task_getsecid(current, &audit_info.secid);
-       err = xfrm_policy_flush(net, type, &audit_info);
+       err = xfrm_policy_flush(net, type, true);
        if (err) {
                if (err == -ESRCH) /* empty table */
                        return 0;
@@ -1969,14 +1943,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        err = 0;
        if (up->hard) {
-               kuid_t loginuid = audit_get_loginuid(current);
-               unsigned int sessionid = audit_get_sessionid(current);
-               u32 sid;
-
-               security_task_getsecid(current, &sid);
                xfrm_policy_delete(xp, p->dir);
-               xfrm_audit_policy_delete(xp, 1, loginuid, sessionid, sid);
-
+               xfrm_audit_policy_delete(xp, 1, true);
        } else {
                // reset the timers here?
                WARN(1, "Dont know what to do with soft policy expire\n");
@@ -2012,13 +1980,8 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
        km_state_expired(x, ue->hard, nlh->nlmsg_pid);
 
        if (ue->hard) {
-               kuid_t loginuid = audit_get_loginuid(current);
-               unsigned int sessionid = audit_get_sessionid(current);
-               u32 sid;
-
-               security_task_getsecid(current, &sid);
                __xfrm_state_delete(x);
-               xfrm_audit_state_delete(x, 1, loginuid, sessionid, sid);
+               xfrm_audit_state_delete(x, 1, true);
        }
        err = 0;
 out:
@@ -2377,7 +2340,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        link = &xfrm_dispatch[type];
 
        /* All operations require privileges, even GET */
-       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+       if (!netlink_net_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
index 003bc263105ae3fc5a92e671faa8654ac6809fa5..bf3e6778cd71addc1884b895a65cde06af11525e 100644 (file)
@@ -50,67 +50,6 @@ ifeq ($(KBUILD_NOPEDANTIC),)
         endif
 endif
 
-#
-# make W=... settings
-#
-# W=1 - warnings that may be relevant and does not occur too often
-# W=2 - warnings that occur quite often but may still be relevant
-# W=3 - the more obscure warnings, can most likely be ignored
-#
-# $(call cc-option, -W...) handles gcc -W.. options which
-# are not supported by all versions of the compiler
-ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
-warning-  := $(empty)
-
-warning-1 := -Wextra -Wunused -Wno-unused-parameter
-warning-1 += -Wmissing-declarations
-warning-1 += -Wmissing-format-attribute
-warning-1 += $(call cc-option, -Wmissing-prototypes)
-warning-1 += -Wold-style-definition
-warning-1 += $(call cc-option, -Wmissing-include-dirs)
-warning-1 += $(call cc-option, -Wunused-but-set-variable)
-warning-1 += $(call cc-disable-warning, missing-field-initializers)
-
-# Clang
-warning-1 += $(call cc-disable-warning, initializer-overrides)
-warning-1 += $(call cc-disable-warning, unused-value)
-warning-1 += $(call cc-disable-warning, format)
-warning-1 += $(call cc-disable-warning, unknown-warning-option)
-warning-1 += $(call cc-disable-warning, sign-compare)
-warning-1 += $(call cc-disable-warning, format-zero-length)
-warning-1 += $(call cc-disable-warning, uninitialized)
-warning-1 += $(call cc-option, -fcatch-undefined-behavior)
-
-warning-2 := -Waggregate-return
-warning-2 += -Wcast-align
-warning-2 += -Wdisabled-optimization
-warning-2 += -Wnested-externs
-warning-2 += -Wshadow
-warning-2 += $(call cc-option, -Wlogical-op)
-warning-2 += $(call cc-option, -Wmissing-field-initializers)
-
-warning-3 := -Wbad-function-cast
-warning-3 += -Wcast-qual
-warning-3 += -Wconversion
-warning-3 += -Wpacked
-warning-3 += -Wpadded
-warning-3 += -Wpointer-arith
-warning-3 += -Wredundant-decls
-warning-3 += -Wswitch-default
-warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
-warning-3 += $(call cc-option, -Wvla)
-
-warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
-warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
-warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
-
-ifeq ("$(strip $(warning))","")
-        $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
-endif
-
-KBUILD_CFLAGS += $(warning)
-endif
-
 include scripts/Makefile.lib
 
 ifdef host-progs
@@ -342,7 +281,7 @@ $(real-objs-m)      : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
 $(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
 
 quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
-cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
+cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $<
 
 $(obj)/%.s: $(src)/%.S FORCE
        $(call if_changed_dep,as_s_S)
@@ -436,7 +375,7 @@ link_multi_deps =                     \
 $(filter $(addprefix $(obj)/,         \
 $($(subst $(obj)/,,$(@:.o=-objs)))    \
 $($(subst $(obj)/,,$(@:.o=-y)))), $^)
+
 quiet_cmd_link_multi-y = LD      $@
 cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
 
diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn
new file mode 100644 (file)
index 0000000..6564350
--- /dev/null
@@ -0,0 +1,67 @@
+# ==========================================================================
+#
+# make W=... settings
+#
+# W=1 - warnings that may be relevant and does not occur too often
+# W=2 - warnings that occur quite often but may still be relevant
+# W=3 - the more obscure warnings, can most likely be ignored
+#
+# $(call cc-option, -W...) handles gcc -W.. options which
+# are not supported by all versions of the compiler
+# ==========================================================================
+
+ifeq ("$(origin W)", "command line")
+  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
+endif
+
+ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
+warning-  := $(empty)
+
+warning-1 := -Wextra -Wunused -Wno-unused-parameter
+warning-1 += -Wmissing-declarations
+warning-1 += -Wmissing-format-attribute
+warning-1 += $(call cc-option, -Wmissing-prototypes)
+warning-1 += -Wold-style-definition
+warning-1 += $(call cc-option, -Wmissing-include-dirs)
+warning-1 += $(call cc-option, -Wunused-but-set-variable)
+warning-1 += $(call cc-disable-warning, missing-field-initializers)
+
+# Clang
+warning-1 += $(call cc-disable-warning, initializer-overrides)
+warning-1 += $(call cc-disable-warning, unused-value)
+warning-1 += $(call cc-disable-warning, format)
+warning-1 += $(call cc-disable-warning, unknown-warning-option)
+warning-1 += $(call cc-disable-warning, sign-compare)
+warning-1 += $(call cc-disable-warning, format-zero-length)
+warning-1 += $(call cc-disable-warning, uninitialized)
+warning-1 += $(call cc-option, -fcatch-undefined-behavior)
+
+warning-2 := -Waggregate-return
+warning-2 += -Wcast-align
+warning-2 += -Wdisabled-optimization
+warning-2 += -Wnested-externs
+warning-2 += -Wshadow
+warning-2 += $(call cc-option, -Wlogical-op)
+warning-2 += $(call cc-option, -Wmissing-field-initializers)
+
+warning-3 := -Wbad-function-cast
+warning-3 += -Wcast-qual
+warning-3 += -Wconversion
+warning-3 += -Wpacked
+warning-3 += -Wpadded
+warning-3 += -Wpointer-arith
+warning-3 += -Wredundant-decls
+warning-3 += -Wswitch-default
+warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
+warning-3 += $(call cc-option, -Wvla)
+
+warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+
+ifeq ("$(strip $(warning))","")
+        $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
+endif
+
+KBUILD_CFLAGS += $(warning)
+endif
index 4d908d16c035c4e6c582e254e531998e7f6156ae..2c1d69c4345caf67a14c2183772e88f913e5529d 100644 (file)
@@ -18,7 +18,7 @@ include $(srctree)/$(obj)/Makefile
 include scripts/Makefile.host
 
 mod-fw := $(fw-shipped-m)
-# If CONFIG_FIRMWARE_IN_KERNEL isn't set, then install the 
+# If CONFIG_FIRMWARE_IN_KERNEL isn't set, then install the
 # firmware for in-kernel drivers too.
 ifndef CONFIG_FIRMWARE_IN_KERNEL
 mod-fw += $(fw-shipped-y)
index 1ac414fd50300384663248c0ac651c9887bfe45d..0f0d6ba87e42f531aae18843d5b304aba2b2355e 100644 (file)
@@ -166,5 +166,5 @@ $(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
        $(call if_changed,host-cshlib)
 
 targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
-          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) 
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs)
 
index 6a5b0decb797227326acb4f8511256afb003b989..260bf8acfce96cfcbae0eb2c3c6754e96e649317 100644 (file)
@@ -27,7 +27,7 @@ lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
 # ---------------------------------------------------------------------------
 # o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o
 #   and add the directory to the list of dirs to descend into: $(subdir-y)
-# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) 
+# o if we encounter foo/ in $(obj-m), remove it from $(obj-m)
 #   and add the directory to the list of dirs to descend into: $(subdir-m)
 
 # Determine modorder.
@@ -46,7 +46,7 @@ obj-m         := $(filter-out %/, $(obj-m))
 
 subdir-ym      := $(sort $(subdir-y) $(subdir-m))
 
-# if $(foo-objs) exists, foo.o is a composite object 
+# if $(foo-objs) exists, foo.o is a composite object
 multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
 multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
 multi-used   := $(multi-used-y) $(multi-used-m)
@@ -91,7 +91,7 @@ obj-dirs      := $(addprefix $(obj)/,$(obj-dirs))
 
 # These flags are needed for modversions and compiling, so we define them here
 # already
-# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will 
+# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will
 # end up in (or would, if it gets compiled in)
 # Note: Files that end up in two or more modules are compiled without the
 #       KBUILD_MODNAME definition. The reason is that any made-up name would
@@ -212,7 +212,7 @@ $(obj)/%: $(src)/%_shipped
 
 # Commands useful for building a boot image
 # ===========================================================================
-# 
+#
 #      Use as following:
 #
 #      target: source(s) FORCE
@@ -226,7 +226,7 @@ $(obj)/%: $(src)/%_shipped
 
 quiet_cmd_ld = LD      $@
 cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \
-              $(filter-out FORCE,$^) -o $@ 
+              $(filter-out FORCE,$^) -o $@
 
 # Objcopy
 # ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.lto b/scripts/Makefile.lto
new file mode 100644 (file)
index 0000000..b8e9e48
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# Support for gcc link time optimization
+#
+
+DISABLE_LTO :=
+LTO_CFLAGS :=
+
+export DISABLE_LTO
+export LTO_CFLAGS
+
+ifdef CONFIG_LTO
+# 4.7 works mostly, but it sometimes loses symbols on large builds
+# This can be worked around by marking those symbols visible,
+# but that is fairly ugly and the problem is gone with 4.8
+# So only allow it with 4.8 for now.
+ifeq ($(call cc-ifversion, -ge, 0408,y),y)
+ifneq ($(call cc-option,${LTO_CFLAGS},n),n)
+# We need HJ Lu's Linux binutils because mainline binutils does not
+# support mixing assembler and LTO code in the same ld -r object.
+# XXX check if the gcc plugin ld is the expected one too
+# XXX some Fedora binutils should also support it. How to check for that?
+ifeq ($(call ld-ifversion,-ge,22710001,y),y)
+        LTO_CFLAGS := -flto -fno-toplevel-reorder
+       LTO_FINAL_CFLAGS := -fuse-linker-plugin
+
+# the -fno-toplevel-reorder is to preserve the order of initcalls
+# everything else should tolerate reordering
+        LTO_FINAL_CFLAGS +=-fno-toplevel-reorder
+
+# enable LTO and set the jobs used by the LTO phase
+# this should be -flto=jobserver to coordinate with the
+# parent make, but work around
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50639
+# use as many jobs as processors are online for now
+# this actually seems to be a kernel bug with the pipe code
+       LTO_FINAL_CFLAGS := -flto=$(shell getconf _NPROCESSORS_ONLN)
+       #LTO_FINAL_CFLAGS := -flto=jobserver
+
+       # requires plugin ar passed and very recent HJ binutils
+        LTO_CFLAGS += -fno-fat-lto-objects
+
+# Used to disable LTO for specific files (e.g. vdso)
+       DISABLE_LTO := -fno-lto
+
+       LTO_FINAL_CFLAGS += ${LTO_CFLAGS} -fwhole-program
+
+ifdef CONFIG_LTO_DEBUG
+       LTO_FINAL_CFLAGS += -dH -fdump-ipa-cgraph -fdump-ipa-inline-details
+       # -Wl,-plugin-save-temps -save-temps
+       LTO_CFLAGS +=
+endif
+ifdef CONFIG_LTO_CP_CLONE
+       LTO_FINAL_CFLAGS += -fipa-cp-clone
+       LTO_CFLAGS += -fipa-cp-clone
+endif
+
+       # In principle gcc should pass through options in the object files,
+       # but it doesn't always work. So do it here manually
+       # Note that special options for individual files does not
+       # work currently (except for some special cases that only
+       # affect the compiler frontend)
+       # The main offenders are FTRACE and GCOV -- we exclude
+       # those in the config.
+       LTO_FINAL_CFLAGS += $(filter -g%,${KBUILD_CFLAGS})
+       LTO_FINAL_CFLAGS += $(filter -O%,${KBUILD_CFLAGS})
+       LTO_FINAL_CFLAGS += $(filter -f%,${KBUILD_CFLAGS})
+       LTO_FINAL_CFLAGS += $(filter -m%,${KBUILD_CFLAGS})
+       LTO_FINAL_CFLAGS += $(filter -W%,${KBUILD_CFLAGS})
+
+       KBUILD_CFLAGS += ${LTO_CFLAGS}
+
+       LDFINAL := ${CONFIG_SHELL} ${srctree}/scripts/gcc-ld \
+                  ${LTO_FINAL_CFLAGS}
+
+else
+        $(warning "WARNING: Too old linker version $(call ld-version) for kernel LTO. You need Linux binutils. CONFIG_LTO disabled.")
+endif
+else
+        $(warning "WARNING: Compiler/Linker does not support LTO/WHOPR with linker plugin. CONFIG_LTO disabled.")
+endif
+else
+        $(warning "WARNING: GCC $(call cc-version) too old for LTO/WHOPR. CONFIG_LTO disabled")
+endif
+endif
index 69f0a1417e9a47669f5568af2097f031c247e607..9c40daea846cdbe932328d73b789f2a634c8f8c6 100644 (file)
@@ -77,7 +77,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
  $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S)      \
- $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
+ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
+ $(if $(CONFIG_LTO),-w)
 
 MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS)))
 
@@ -115,8 +116,8 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
 targets += $(modules:.ko=.mod.o)
 
 # Step 6), final link of the modules
-quiet_cmd_ld_ko_o = LD [M]  $@
-      cmd_ld_ko_o = $(LD) -r $(LDFLAGS)                                 \
+quiet_cmd_ld_ko_o = LDFINAL [M]  $@
+      cmd_ld_ko_o = $(LDFINAL) -r $(LDFLAGS)                            \
                              $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
                              -o $@ $(filter-out FORCE,$^)
 
index 263a44d57fa95dea88411e7df0527eb1528cb474..61bbda54cf13ead802ba096fe8dad55bd5241488 100644 (file)
@@ -104,7 +104,7 @@ int main(int argc, char *argv[])
        }
     }
 
-  /* For now we assume the default font is always 256 characters. */    
+  /* For now we assume the default font is always 256 characters. */
   fontlen = 256;
 
   /* Initialize table */
@@ -236,15 +236,15 @@ int main(int argc, char *argv[])
     }
 
   /* Okay, we hit EOF, now output hash table */
-  
+
   fclose(ctbl);
-  
+
 
   /* Compute total size of Unicode list */
   nuni = 0;
   for ( i = 0 ; i < fontlen ; i++ )
     nuni += unicount[i];
-  
+
   printf("\
 /*\n\
  * Do not edit this file; it was automatically generated by\n\
@@ -268,9 +268,9 @@ u8 dfont_unicount[%d] = \n\
       else
         printf(", ");
     }
-  
+
   printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni);
-  
+
   fp0 = 0;
   nent = 0;
   for ( i = 0 ; i < nuni ; i++ )
index 31331723e810746d08f46c01928c20b2555018a8..9cb8522d8d22a826caaec968e82c77516339ca01 100644 (file)
@@ -589,7 +589,7 @@ while ($repeat) {
 
     # Now we need to see if we have to check selects;
     loop_select;
-}          
+}
 
 my %setconfigs;
 
index 86a4fe75f453735936e3b218f885dcd887216659..ec9a8ae33f8f1b4266dd11c43ebe08d8b4296735 100644 (file)
@@ -53,7 +53,7 @@ vmlinux_link()
        local lds="${objtree}/${KBUILD_LDS}"
 
        if [ "${SRCARCH}" != "um" ]; then
-               ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}                  \
+               ${LDFINAL} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}                  \
                        -T ${lds} ${KBUILD_VMLINUX_INIT}                     \
                        --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
        else
index cfb8440cc0b2cf5611db59014d4b83fd27af2e9d..6fdc97ef6023da95f708dcbe9b1cc0634a99f0f2 100755 (executable)
@@ -68,7 +68,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
 
 ( echo /\* This file is auto generated, version $VERSION \*/
   if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
-  
+
   echo \#define UTS_MACHINE \"$ARCH\"
 
   echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
@@ -84,7 +84,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
 # recompilations.
 # We don't consider the file changed if only the date/time changed.
 # A kernel config change will increase the generation number, thus
-# causing compile.h to be updated (including date/time) due to the 
+# causing compile.h to be updated (including date/time) due to the
 # changed comment in the
 # first line.
 
index 0cc04426074403458583b73339754c2a588bfa13..84af27bf0f99fc8983564eebaf63aed7797e7a30 100644 (file)
@@ -42,18 +42,11 @@ MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$
 
 MAKEFLAGS += --no-print-directory
 
-.PHONY: all \$(MAKECMDGOALS)
+.PHONY: __sub-make \$(MAKECMDGOALS)
 
-all    := \$(filter-out all Makefile,\$(MAKECMDGOALS))
+__sub-make:
+       \$(Q)\$(MAKE) \$(MAKEARGS) \$(MAKECMDGOALS)
 
-all:
-       \$(Q)\$(MAKE) \$(MAKEARGS) \$(all)
-
-Makefile:;
-
-\$(all): all
-       @:
-
-%/: all
+\$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make
        @:
 EOF
index 066355673930342a1b5e839950cbd1186ed6c24b..ea3e2bdf1825dcdc88e2237842e2b5f5ca99decf 100644 (file)
@@ -2113,8 +2113,10 @@ static void read_dump(const char *fname, unsigned int kernel)
                s->preloaded = 1;
                sym_update_crc(symname, mod, crc, export_no(export));
        }
+       release_file(file, size);
        return;
 fail:
+       release_file(file, size);
        fatal("parse error in symbol dump file\n");
 }
 
index f46e4dd0558da4582b38c75d4342456cceefd920..fd683c540aa8a290717020fbb80a9bcba4e046cc 100644 (file)
@@ -42,6 +42,8 @@ create_package() {
                debarch=hppa ;;
        mips*)
                debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;;
+       arm64)
+               debarch=arm64 ;;
        arm*)
                debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;;
        *)
@@ -130,7 +132,7 @@ if [ "$ARCH" = "um" ] ; then
        cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
        cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config"
        gzip "$tmpdir/usr/share/doc/$packagename/config"
-else 
+else
        cp System.map "$tmpdir/boot/System.map-$version"
        cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version"
 fi
@@ -155,11 +157,11 @@ if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then
                        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
+                               $OBJCOPY --only-keep-debug $module $dbg_dir/usr/lib/debug/$module
                                # strip original module from debug symbols
-                               objcopy --strip-debug $module
+                               $OBJCOPY --strip-debug $module
                                # then add a link to those
-                               objcopy --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module
+                               $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module
                        done
                )
        fi
index d000ea3a41fdb7f202a34e439cf954bd5353b74f..49b4241e814a90c159cc272e655daa6294c7a2ea 100755 (executable)
@@ -27,7 +27,7 @@
 #       Nick Holloway <Nick.Holloway@alfie.demon.co.uk>, 2nd January 1995.
 #
 # Added support for handling multiple types of compression. What includes
-# gzip, bzip, bzip2, zip, compress, and plaintext. 
+# gzip, bzip, bzip2, zip, compress, and plaintext.
 #
 #       Adam Sulmicki <adam@cfar.umd.edu>, 1st January 1997.
 #
@@ -159,7 +159,7 @@ applyPatch () {
   fi
   # Remove backup files
   find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;
+
   return 0;
 }
 
index cc49062acdeecf85259f646df09abe22f1019a5d..1052d4834a44f502bda4f4f1ebe1202ace1608f5 100644 (file)
 #define EM_ARCOMPACT   93
 #endif
 
+#ifndef EM_XTENSA
+#define EM_XTENSA      94
+#endif
+
 #ifndef EM_AARCH64
 #define EM_AARCH64     183
 #endif
@@ -281,6 +285,7 @@ do_file(char const *const fname)
        case EM_AARCH64:
        case EM_MICROBLAZE:
        case EM_MIPS:
+       case EM_XTENSA:
                break;
        }  /* end switch */
 
index f2c5b006a3d73534d12fcb8c213ae140db4bae4e..6db551e07498b62c0f8a746c5868ff342d1da845 100755 (executable)
@@ -25,6 +25,9 @@ else
        tree=${srctree}/
 fi
 
+# ignore userspace tools
+ignore="$ignore ( -path ${tree}tools ) -prune -o"
+
 # Find all available archs
 find_all_archs()
 {
@@ -201,7 +204,8 @@ exuberant()
        --regex-c='/DECLARE_(TASKLET|WORK|DELAYED_WORK)\((\w*)/\2/v/'   \
        --regex-c='/DEFINE_PCI_DEVICE_TABLE\((\w*)/\1/v/'               \
        --regex-c='/(^\s)OFFSET\((\w*)/\2/v/'                           \
-       --regex-c='/(^\s)DEFINE\((\w*)/\2/v/'
+       --regex-c='/(^\s)DEFINE\((\w*)/\2/v/'                           \
+       --regex-c='/DEFINE_HASHTABLE\((\w*)/\1/v/'
 
        all_kconfigs | xargs $1 -a                              \
        --langdef=kconfig --language-force=kconfig              \
@@ -246,7 +250,8 @@ emacs()
        --regex='/__TESTCLEARFLAG_FALSE(\([^,)]*\).*/__TestClearPage\1/' \
        --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'           \
        --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \
-       --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'
+       --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\
+       --regex='/DEFINE_HASHTABLE\((\w*)/\1/v/'
 
        all_kconfigs | xargs $1 -a                              \
        --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
index 8fb1488a3cd4499ecf8e374dcd47f956945a0ef7..97130f88838bc2ad385b5ccd69bf0dfc51acae95 100644 (file)
@@ -66,7 +66,6 @@ extern int apparmor_initialized __initdata;
 char *aa_split_fqname(char *args, char **ns_name);
 void aa_info_message(const char *str);
 void *__aa_kvmalloc(size_t size, gfp_t flags);
-void kvfree(void *buffer);
 
 static inline void *kvmalloc(size_t size)
 {
index 69689922c491b8a4eeda5d96115df4a49e6a844f..c1827e068454cf992c510fd7f6bc9cbbda67a500 100644 (file)
@@ -104,17 +104,3 @@ void *__aa_kvmalloc(size_t size, gfp_t flags)
        }
        return buffer;
 }
-
-/**
- * kvfree - free an allocation do by kvmalloc
- * @buffer: buffer to free (MAYBE_NULL)
- *
- * Free a buffer allocated by kvmalloc
- */
-void kvfree(void *buffer)
-{
-       if (is_vmalloc_addr(buffer))
-               vfree(buffer);
-       else
-               kfree(buffer);
-}
index ad0d4de6994474aba384955e240c73b88a03398e..e76373de31298e0a3264920035374b849bc42fb1 100644 (file)
@@ -879,7 +879,7 @@ static void cap_key_free(struct key *key)
 }
 
 static int cap_key_permission(key_ref_t key_ref, const struct cred *cred,
-                             key_perm_t perm)
+                             unsigned perm)
 {
        return 0;
 }
index 80b2aac4f50ceda614d03c815f7638aa88a0c933..5f20da01fd8d317f835375de9654f42c1a1b4e8b 100644 (file)
@@ -176,20 +176,11 @@ extern int key_task_permission(const key_ref_t key_ref,
 /*
  * Check to see whether permission is granted to use a key in the desired way.
  */
-static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
+static inline int key_permission(const key_ref_t key_ref, unsigned perm)
 {
        return key_task_permission(key_ref, current_cred(), perm);
 }
 
-/* required permissions */
-#define        KEY_VIEW        0x01    /* require permission to view attributes */
-#define        KEY_READ        0x02    /* require permission to read content */
-#define        KEY_WRITE       0x04    /* require permission to update / modify */
-#define        KEY_SEARCH      0x08    /* require permission to search (keyring) or find (key) */
-#define        KEY_LINK        0x10    /* require permission to link */
-#define        KEY_SETATTR     0x20    /* require permission to change attributes */
-#define        KEY_ALL         0x3f    /* all the above permissions */
-
 /*
  * Authorisation record for request_key().
  */
index 6e21c11e48bc1cd434664d28f83084b54db50bd6..2048a110e7f18f0bd1e78006a88dc7bc675c9994 100644 (file)
@@ -714,7 +714,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
        int ret;
 
        /* need write permission on the key to update it */
-       ret = key_permission(key_ref, KEY_WRITE);
+       ret = key_permission(key_ref, KEY_NEED_WRITE);
        if (ret < 0)
                goto error;
 
@@ -838,7 +838,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
        /* if we're going to allocate a new key, we're going to have
         * to modify the keyring */
-       ret = key_permission(keyring_ref, KEY_WRITE);
+       ret = key_permission(keyring_ref, KEY_NEED_WRITE);
        if (ret < 0) {
                key_ref = ERR_PTR(ret);
                goto error_link_end;
@@ -928,7 +928,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
        key_check(key);
 
        /* the key must be writable */
-       ret = key_permission(key_ref, KEY_WRITE);
+       ret = key_permission(key_ref, KEY_NEED_WRITE);
        if (ret < 0)
                goto error;
 
index cee72ce642221e816968cb81069407fe01edb138..cd5bd0cef25df3fce5801e938567e156d47f275f 100644 (file)
@@ -111,7 +111,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
        }
 
        /* find the target keyring (which must be writable) */
-       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error3;
@@ -195,7 +195,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
        dest_ref = NULL;
        if (destringid) {
                dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
-                                          KEY_WRITE);
+                                          KEY_NEED_WRITE);
                if (IS_ERR(dest_ref)) {
                        ret = PTR_ERR(dest_ref);
                        goto error3;
@@ -253,7 +253,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
        long ret;
 
        lflags = create ? KEY_LOOKUP_CREATE : 0;
-       key_ref = lookup_user_key(id, lflags, KEY_SEARCH);
+       key_ref = lookup_user_key(id, lflags, KEY_NEED_SEARCH);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -334,7 +334,7 @@ long keyctl_update_key(key_serial_t id,
        }
 
        /* find the target key (which must be writable) */
-       key_ref = lookup_user_key(id, 0, KEY_WRITE);
+       key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error2;
@@ -365,12 +365,12 @@ long keyctl_revoke_key(key_serial_t id)
        key_ref_t key_ref;
        long ret;
 
-       key_ref = lookup_user_key(id, 0, KEY_WRITE);
+       key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                if (ret != -EACCES)
                        goto error;
-               key_ref = lookup_user_key(id, 0, KEY_SETATTR);
+               key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR);
                if (IS_ERR(key_ref)) {
                        ret = PTR_ERR(key_ref);
                        goto error;
@@ -401,7 +401,7 @@ long keyctl_invalidate_key(key_serial_t id)
 
        kenter("%d", id);
 
-       key_ref = lookup_user_key(id, 0, KEY_SEARCH);
+       key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -428,7 +428,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
        key_ref_t keyring_ref;
        long ret;
 
-       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
 
@@ -470,13 +470,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
        key_ref_t keyring_ref, key_ref;
        long ret;
 
-       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error;
        }
 
-       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK);
+       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error2;
@@ -505,7 +505,7 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
        key_ref_t keyring_ref, key_ref;
        long ret;
 
-       keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error;
@@ -548,7 +548,7 @@ long keyctl_describe_key(key_serial_t keyid,
        char *tmpbuf;
        long ret;
 
-       key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
+       key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
        if (IS_ERR(key_ref)) {
                /* viewing a key under construction is permitted if we have the
                 * authorisation token handy */
@@ -639,7 +639,7 @@ long keyctl_keyring_search(key_serial_t ringid,
        }
 
        /* get the keyring at which to begin the search */
-       keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH);
+       keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_SEARCH);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error2;
@@ -649,7 +649,7 @@ long keyctl_keyring_search(key_serial_t ringid,
        dest_ref = NULL;
        if (destringid) {
                dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
-                                          KEY_WRITE);
+                                          KEY_NEED_WRITE);
                if (IS_ERR(dest_ref)) {
                        ret = PTR_ERR(dest_ref);
                        goto error3;
@@ -676,7 +676,7 @@ long keyctl_keyring_search(key_serial_t ringid,
 
        /* link the resulting key to the destination keyring if we can */
        if (dest_ref) {
-               ret = key_permission(key_ref, KEY_LINK);
+               ret = key_permission(key_ref, KEY_NEED_LINK);
                if (ret < 0)
                        goto error6;
 
@@ -727,7 +727,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
        key = key_ref_to_ptr(key_ref);
 
        /* see if we can read it directly */
-       ret = key_permission(key_ref, KEY_READ);
+       ret = key_permission(key_ref, KEY_NEED_READ);
        if (ret == 0)
                goto can_read_key;
        if (ret != -EACCES)
@@ -799,7 +799,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
                goto error;
 
        key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
-                                 KEY_SETATTR);
+                                 KEY_NEED_SETATTR);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -905,7 +905,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
                goto error;
 
        key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
-                                 KEY_SETATTR);
+                                 KEY_NEED_SETATTR);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -947,7 +947,7 @@ static long get_instantiation_keyring(key_serial_t ringid,
 
        /* if a specific keyring is nominated by ID, then use that */
        if (ringid > 0) {
-               dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
+               dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
                if (IS_ERR(dkref))
                        return PTR_ERR(dkref);
                *_dest_keyring = key_ref_to_ptr(dkref);
@@ -1315,7 +1315,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
        long ret;
 
        key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
-                                 KEY_SETATTR);
+                                 KEY_NEED_SETATTR);
        if (IS_ERR(key_ref)) {
                /* setting the timeout on a key under construction is permitted
                 * if we have the authorisation token handy */
@@ -1418,7 +1418,7 @@ long keyctl_get_security(key_serial_t keyid,
        char *context;
        long ret;
 
-       key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
+       key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
        if (IS_ERR(key_ref)) {
                if (PTR_ERR(key_ref) != -EACCES)
                        return PTR_ERR(key_ref);
@@ -1482,7 +1482,7 @@ long keyctl_session_to_parent(void)
        struct cred *cred;
        int ret;
 
-       keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
+       keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK);
        if (IS_ERR(keyring_r))
                return PTR_ERR(keyring_r);
 
index 2fb2576dc6448b3c1020dc311e0d81bfe77fb768..9cf2575f0d97c8b237928f1e1ab46b4ad3895653 100644 (file)
@@ -541,7 +541,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
        /* key must have search permissions */
        if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
            key_task_permission(make_key_ref(key, ctx->possessed),
-                               ctx->cred, KEY_SEARCH) < 0) {
+                               ctx->cred, KEY_NEED_SEARCH) < 0) {
                ctx->result = ERR_PTR(-EACCES);
                kleave(" = %d [!perm]", ctx->skipped_ret);
                goto skipped;
@@ -721,7 +721,7 @@ ascend_to_node:
                /* Search a nested keyring */
                if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
                    key_task_permission(make_key_ref(key, ctx->possessed),
-                                       ctx->cred, KEY_SEARCH) < 0)
+                                       ctx->cred, KEY_NEED_SEARCH) < 0)
                        continue;
 
                /* stack the current position */
@@ -843,7 +843,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                return ERR_PTR(-ENOTDIR);
 
        if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) {
-               err = key_task_permission(keyring_ref, ctx->cred, KEY_SEARCH);
+               err = key_task_permission(keyring_ref, ctx->cred, KEY_NEED_SEARCH);
                if (err < 0)
                        return ERR_PTR(err);
        }
@@ -973,7 +973,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
 
                        if (!skip_perm_check &&
                            key_permission(make_key_ref(keyring, 0),
-                                          KEY_SEARCH) < 0)
+                                          KEY_NEED_SEARCH) < 0)
                                continue;
 
                        /* we've got a match but we might end up racing with
index efcc0c855a0db1284ee3debcb9be64823d9be3ed..732cc0beffdfc74b74eddbf173ee30bd9d0455db 100644 (file)
@@ -28,7 +28,7 @@
  * permissions bits or the LSM check.
  */
 int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
-                       key_perm_t perm)
+                       unsigned perm)
 {
        struct key *key;
        key_perm_t kperm;
@@ -68,7 +68,7 @@ use_these_perms:
        if (is_key_possessed(key_ref))
                kperm |= key->perm >> 24;
 
-       kperm = kperm & perm & KEY_ALL;
+       kperm = kperm & perm & KEY_NEED_ALL;
 
        if (kperm != perm)
                return -EACCES;
index 0ad3ee2837812344d9cf20153c6df49f4dff168e..c9fae5ea89fe68b2dcaeed5a30acc9f47c54c6ad 100644 (file)
@@ -108,7 +108,7 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
        return PTR_ERR(persistent_ref);
 
 found:
-       ret = key_task_permission(persistent_ref, current_cred(), KEY_LINK);
+       ret = key_task_permission(persistent_ref, current_cred(), KEY_NEED_LINK);
        if (ret == 0) {
                persistent = key_ref_to_ptr(persistent_ref);
                ret = key_link(key_ref_to_ptr(dest_ref), persistent);
@@ -151,7 +151,7 @@ long keyctl_get_persistent(uid_t _uid, key_serial_t destid)
        }
 
        /* There must be a destination keyring */
-       dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_WRITE);
+       dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
        if (IS_ERR(dest_ref))
                return PTR_ERR(dest_ref);
        if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) {
index 88e9a466940f642af60f61b407888155ba057be5..d3f6f2fd21db84bc197ed82b14808b6bc9bc4e87 100644 (file)
@@ -218,7 +218,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
         * - the caller holds a spinlock, and thus the RCU read lock, making our
         *   access to __current_cred() safe
         */
-       rc = key_task_permission(key_ref, ctx.cred, KEY_VIEW);
+       rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW);
        if (rc < 0)
                return 0;
 
index 8c0af08760c809b2923d04c5cc3b114c75e27b27..b68faa1a5cfdf2a97a65b73bfb2a8a33916db3f0 100644 (file)
@@ -15,7 +15,7 @@
 
 static const int zero, one = 1, max = INT_MAX;
 
-ctl_table key_sysctls[] = {
+struct ctl_table key_sysctls[] = {
        {
                .procname = "maxkeys",
                .data = &key_quota_maxkeys,
index 8b774f362a3d4ed252f626c8e6de5634a5820148..31614e9e96e556883aa947fc1360e9e03127883d 100644 (file)
@@ -1425,7 +1425,7 @@ void security_key_free(struct key *key)
 }
 
 int security_key_permission(key_ref_t key_ref,
-                           const struct cred *cred, key_perm_t perm)
+                           const struct cred *cred, unsigned perm)
 {
        return security_ops->key_permission(key_ref, cred, perm);
 }
index fc3e6628a8642e027c992cf500fd4c0a921c85fc..a18f1fa6440bb707e6b693c383c09c15b5dcaa3f 100644 (file)
@@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
        avc_dump_query(ab, ad->selinux_audit_data->ssid,
                           ad->selinux_audit_data->tsid,
                           ad->selinux_audit_data->tclass);
+       if (ad->selinux_audit_data->denied) {
+               audit_log_format(ab, " permissive=%u",
+                                ad->selinux_audit_data->result ? 0 : 1);
+       }
 }
 
 /* This is the slow part of avc audit with big stack footprint */
 noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
-               u32 requested, u32 audited, u32 denied,
+               u32 requested, u32 audited, u32 denied, int result,
                struct common_audit_data *a,
                unsigned flags)
 {
@@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
        sad.tsid = tsid;
        sad.audited = audited;
        sad.denied = denied;
+       sad.result = result;
 
        a->selinux_audit_data = &sad;
 
index 2c7341dbc5d68d1948ad0efa713ad3a85307608e..9cfd8a38c6e94d4e559f2ceff1101712704cc60e 100644 (file)
@@ -2770,6 +2770,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
 
 static noinline int audit_inode_permission(struct inode *inode,
                                           u32 perms, u32 audited, u32 denied,
+                                          int result,
                                           unsigned flags)
 {
        struct common_audit_data ad;
@@ -2780,7 +2781,7 @@ static noinline int audit_inode_permission(struct inode *inode,
        ad.u.inode = inode;
 
        rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
-                           audited, denied, &ad, flags);
+                           audited, denied, result, &ad, flags);
        if (rc)
                return rc;
        return 0;
@@ -2822,7 +2823,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (likely(!audited))
                return rc;
 
-       rc2 = audit_inode_permission(inode, perms, audited, denied, flags);
+       rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags);
        if (rc2)
                return rc2;
        return rc;
@@ -5722,7 +5723,7 @@ static void selinux_key_free(struct key *k)
 
 static int selinux_key_permission(key_ref_t key_ref,
                                  const struct cred *cred,
-                                 key_perm_t perm)
+                                 unsigned perm)
 {
        struct key *key;
        struct key_security_struct *ksec;
index f53ee3c58d0ffd5099879f2bcdc160c88c209c86..ddf8eec03f211757845de5378afd1c2d5ebfe774 100644 (file)
@@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested,
 }
 
 int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
-                  u32 requested, u32 audited, u32 denied,
+                  u32 requested, u32 audited, u32 denied, int result,
                   struct common_audit_data *a,
                   unsigned flags);
 
@@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
        if (likely(!audited))
                return 0;
        return slow_avc_audit(ssid, tsid, tclass,
-                             requested, audited, denied,
+                             requested, audited, denied, result,
                              a, 0);
 }
 
index 14d04e63b1f0e09ef15b4cf64057bd7cc861ed1d..be491a74c1edc4a279f76121dab615305c3a47f2 100644 (file)
@@ -147,7 +147,7 @@ struct security_class_mapping secclass_map[] = {
        { "peer", { "recv", NULL } },
        { "capability2",
          { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend",
-           NULL } },
+           "audit_read", NULL } },
        { "kernel_service", { "use_as_override", "create_files_as", NULL } },
        { "tun_socket",
          { COMMON_SOCK_PERMS, "attach_queue", NULL } },
index 14f52be78c75e279f2bad288c66513a016a1ec3c..8177e7df8c2da4ffa4854425b93d104dd31378fe 100644 (file)
@@ -3506,11 +3506,12 @@ static void smack_key_free(struct key *key)
  * an error code otherwise
  */
 static int smack_key_permission(key_ref_t key_ref,
-                               const struct cred *cred, key_perm_t perm)
+                               const struct cred *cred, unsigned perm)
 {
        struct key *keyp;
        struct smk_audit_info ad;
        struct smack_known *tkp = smk_of_task(cred->security);
+       int request = 0;
 
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
@@ -3531,7 +3532,11 @@ static int smack_key_permission(key_ref_t key_ref,
        ad.a.u.key_struct.key = keyp->serial;
        ad.a.u.key_struct.key_desc = keyp->description;
 #endif
-       return smk_access(tkp, keyp->security, MAY_READWRITE, &ad);
+       if (perm & KEY_NEED_READ)
+               request = MAY_READ;
+       if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
+               request = MAY_WRITE;
+       return smk_access(tkp, keyp->security, request, &ad);
 }
 #endif /* CONFIG_KEYS */
 
index 05ec049c9faf1edf799fd77f1ef606d18ee40c63..a04d23174dc2e3ef6418daf00a28370a8498b580 100644 (file)
@@ -1198,6 +1198,7 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver atmel_ac97c_driver = {
+       .probe          = atmel_ac97c_probe,
        .remove         = atmel_ac97c_remove,
        .driver         = {
                .name   = "atmel_ac97c",
@@ -1205,19 +1206,7 @@ static struct platform_driver atmel_ac97c_driver = {
                .pm     = ATMEL_AC97C_PM_OPS,
        },
 };
-
-static int __init atmel_ac97c_init(void)
-{
-       return platform_driver_probe(&atmel_ac97c_driver,
-                       atmel_ac97c_probe);
-}
-module_init(atmel_ac97c_init);
-
-static void __exit atmel_ac97c_exit(void)
-{
-       platform_driver_unregister(&atmel_ac97c_driver);
-}
-module_exit(atmel_ac97c_exit);
+module_platform_driver(atmel_ac97c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
index ce83def9f43bf9d30755e48f1129d25af81792a9..9acc77eae4872a5c3f1726e05737a381576a5151 100644 (file)
@@ -345,7 +345,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                        snd_pcm_debug_name(substream, name, sizeof(name));
                        xrun_log_show(substream);
                        pcm_err(substream->pcm,
-                               "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+                               "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
                                name, pos, runtime->buffer_size,
                                runtime->period_size);
                }
index 3e05c55a28801a423411cc5c61b7d9d57096ce29..a1fd77af60593e26de9cf4c560e8a3b80412d797 100644 (file)
@@ -362,13 +362,13 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
                if (! port->name[0]) {
                        if (info->name[0]) {
                                if (ports > 1)
-                                       snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p);
+                                       snprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
                                else
                                        snprintf(port->name, sizeof(port->name), "%s", info->name);
                        } else {
                                /* last resort */
                                if (ports > 1)
-                                       sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p);
+                                       sprintf(port->name, "MIDI %d-%d-%u", card->number, device, p);
                                else
                                        sprintf(port->name, "MIDI %d-%d", card->number, device);
                        }
index db18ccabadd6abb3914b9b1d70c314232fda92ac..e8910d02580b1b349fb32827b8dc0f632b334e2d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -34,8 +35,6 @@
 #include <sound/opl3.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
-
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 #include <media/tea575x.h>
 #endif
@@ -80,7 +79,10 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers");
  *  Direct registers
  */
 
-#define FM801_REG(chip, reg)   (chip->port + FM801_##reg)
+#define fm801_writew(chip,reg,value)   outw((value), chip->port + FM801_##reg)
+#define fm801_readw(chip,reg)          inw(chip->port + FM801_##reg)
+
+#define fm801_writel(chip,reg,value)   outl((value), chip->port + FM801_##reg)
 
 #define FM801_PCM_VOL          0x00    /* PCM Output Volume */
 #define FM801_FM_VOL           0x02    /* FM Output Volume */
@@ -222,6 +224,30 @@ MODULE_DEVICE_TABLE(pci, snd_fm801_ids);
  *  common I/O routines
  */
 
+static bool fm801_ac97_is_ready(struct fm801 *chip, unsigned int iterations)
+{
+       unsigned int idx;
+
+       for (idx = 0; idx < iterations; idx++) {
+               if (!(fm801_readw(chip, AC97_CMD) & FM801_AC97_BUSY))
+                       return true;
+               udelay(10);
+       }
+       return false;
+}
+
+static bool fm801_ac97_is_valid(struct fm801 *chip, unsigned int iterations)
+{
+       unsigned int idx;
+
+       for (idx = 0; idx < iterations; idx++) {
+               if (fm801_readw(chip, AC97_CMD) & FM801_AC97_VALID)
+                       return true;
+               udelay(10);
+       }
+       return false;
+}
+
 static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg,
                                 unsigned short mask, unsigned short value)
 {
@@ -244,73 +270,54 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97,
                                  unsigned short val)
 {
        struct fm801 *chip = ac97->private_data;
-       int idx;
 
        /*
         *  Wait until the codec interface is not ready..
         */
-       for (idx = 0; idx < 100; idx++) {
-               if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
-                       goto ok1;
-               udelay(10);
+       if (!fm801_ac97_is_ready(chip, 100)) {
+               dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
+               return;
        }
-       dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
-       return;
 
- ok1:
        /* write data and address */
-       outw(val, FM801_REG(chip, AC97_DATA));
-       outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD));
+       fm801_writew(chip, AC97_DATA, val);
+       fm801_writew(chip, AC97_CMD, reg | (ac97->addr << FM801_AC97_ADDR_SHIFT));
        /*
         *  Wait until the write command is not completed..
-         */
-       for (idx = 0; idx < 1000; idx++) {
-               if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
-                       return;
-               udelay(10);
-       }
-       dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
+        */
+       if (!fm801_ac97_is_ready(chip, 1000))
+               dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n",
+               ac97->num);
 }
 
 static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short reg)
 {
        struct fm801 *chip = ac97->private_data;
-       int idx;
 
        /*
         *  Wait until the codec interface is not ready..
         */
-       for (idx = 0; idx < 100; idx++) {
-               if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
-                       goto ok1;
-               udelay(10);
+       if (!fm801_ac97_is_ready(chip, 100)) {
+               dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
+               return 0;
        }
-       dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
-       return 0;
 
- ok1:
        /* read command */
-       outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ,
-            FM801_REG(chip, AC97_CMD));
-       for (idx = 0; idx < 100; idx++) {
-               if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
-                       goto ok2;
-               udelay(10);
+       fm801_writew(chip, AC97_CMD,
+                    reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ);
+       if (!fm801_ac97_is_ready(chip, 100)) {
+               dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n",
+                       ac97->num);
+               return 0;
        }
-       dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
-       return 0;
 
- ok2:
-       for (idx = 0; idx < 1000; idx++) {
-               if (inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_VALID)
-                       goto ok3;
-               udelay(10);
+       if (!fm801_ac97_is_valid(chip, 1000)) {
+               dev_err(chip->card->dev,
+                       "AC'97 interface #%d is not valid (2)\n", ac97->num);
+               return 0;
        }
-       dev_err(chip->card->dev, "AC'97 interface #%d is not valid (2)\n", ac97->num);
-       return 0;
 
- ok3:
-       return inw(FM801_REG(chip, AC97_DATA));
+       return fm801_readw(chip, AC97_DATA);
 }
 
 static unsigned int rates[] = {
@@ -384,7 +391,7 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream,
                snd_BUG();
                return -EINVAL;
        }
-       outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL));
+       fm801_writew(chip, PLY_CTRL, chip->ply_ctrl);
        spin_unlock(&chip->reg_lock);
        return 0;
 }
@@ -419,7 +426,7 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream,
                snd_BUG();
                return -EINVAL;
        }
-       outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL));
+       fm801_writew(chip, CAP_CTRL, chip->cap_ctrl);
        spin_unlock(&chip->reg_lock);
        return 0;
 }
@@ -457,12 +464,13 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream)
        }
        chip->ply_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT;
        chip->ply_buf = 0;
-       outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL));
-       outw(chip->ply_count - 1, FM801_REG(chip, PLY_COUNT));
+       fm801_writew(chip, PLY_CTRL, chip->ply_ctrl);
+       fm801_writew(chip, PLY_COUNT, chip->ply_count - 1);
        chip->ply_buffer = runtime->dma_addr;
        chip->ply_pos = 0;
-       outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1));
-       outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2));
+       fm801_writel(chip, PLY_BUF1, chip->ply_buffer);
+       fm801_writel(chip, PLY_BUF2,
+                    chip->ply_buffer + (chip->ply_count % chip->ply_size));
        spin_unlock_irq(&chip->reg_lock);
        return 0;
 }
@@ -483,12 +491,13 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream)
                chip->cap_ctrl |= FM801_STEREO;
        chip->cap_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT;
        chip->cap_buf = 0;
-       outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL));
-       outw(chip->cap_count - 1, FM801_REG(chip, CAP_COUNT));
+       fm801_writew(chip, CAP_CTRL, chip->cap_ctrl);
+       fm801_writew(chip, CAP_COUNT, chip->cap_count - 1);
        chip->cap_buffer = runtime->dma_addr;
        chip->cap_pos = 0;
-       outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1));
-       outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2));
+       fm801_writel(chip, CAP_BUF1, chip->cap_buffer);
+       fm801_writel(chip, CAP_BUF2,
+                    chip->cap_buffer + (chip->cap_count % chip->cap_size));
        spin_unlock_irq(&chip->reg_lock);
        return 0;
 }
@@ -501,8 +510,8 @@ static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *su
        if (!(chip->ply_ctrl & FM801_START))
                return 0;
        spin_lock(&chip->reg_lock);
-       ptr = chip->ply_pos + (chip->ply_count - 1) - inw(FM801_REG(chip, PLY_COUNT));
-       if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_PLAYBACK) {
+       ptr = chip->ply_pos + (chip->ply_count - 1) - fm801_readw(chip, PLY_COUNT);
+       if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_PLAYBACK) {
                ptr += chip->ply_count;
                ptr %= chip->ply_size;
        }
@@ -518,8 +527,8 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub
        if (!(chip->cap_ctrl & FM801_START))
                return 0;
        spin_lock(&chip->reg_lock);
-       ptr = chip->cap_pos + (chip->cap_count - 1) - inw(FM801_REG(chip, CAP_COUNT));
-       if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_CAPTURE) {
+       ptr = chip->cap_pos + (chip->cap_count - 1) - fm801_readw(chip, CAP_COUNT);
+       if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_CAPTURE) {
                ptr += chip->cap_count;
                ptr %= chip->cap_size;
        }
@@ -533,12 +542,12 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
        unsigned short status;
        unsigned int tmp;
 
-       status = inw(FM801_REG(chip, IRQ_STATUS));
+       status = fm801_readw(chip, IRQ_STATUS);
        status &= FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU|FM801_IRQ_VOLUME;
        if (! status)
                return IRQ_NONE;
        /* ack first */
-       outw(status, FM801_REG(chip, IRQ_STATUS));
+       fm801_writew(chip, IRQ_STATUS, status);
        if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) {
                spin_lock(&chip->reg_lock);
                chip->ply_buf++;
@@ -546,10 +555,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
                chip->ply_pos %= chip->ply_size;
                tmp = chip->ply_pos + chip->ply_count;
                tmp %= chip->ply_size;
-               outl(chip->ply_buffer + tmp,
-                               (chip->ply_buf & 1) ?
-                                       FM801_REG(chip, PLY_BUF1) :
-                                       FM801_REG(chip, PLY_BUF2));
+               if (chip->ply_buf & 1)
+                       fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp);
+               else
+                       fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp);
                spin_unlock(&chip->reg_lock);
                snd_pcm_period_elapsed(chip->playback_substream);
        }
@@ -560,10 +569,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
                chip->cap_pos %= chip->cap_size;
                tmp = chip->cap_pos + chip->cap_count;
                tmp %= chip->cap_size;
-               outl(chip->cap_buffer + tmp,
-                               (chip->cap_buf & 1) ?
-                                       FM801_REG(chip, CAP_BUF1) :
-                                       FM801_REG(chip, CAP_BUF2));
+               if (chip->cap_buf & 1)
+                       fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp);
+               else
+                       fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp);
                spin_unlock(&chip->reg_lock);
                snd_pcm_period_elapsed(chip->capture_substream);
        }
@@ -747,7 +756,7 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
 static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
        struct fm801 *chip = tea->private_data;
-       unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+       unsigned short reg = fm801_readw(chip, GPIO_CTRL);
        struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
 
        reg &= ~(FM801_GPIO_GP(gpio.data) |
@@ -759,13 +768,13 @@ static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
        /* WRITE_ENABLE is inverted */
        reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren);
 
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
+       fm801_writew(chip, GPIO_CTRL, reg);
 }
 
 static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
 {
        struct fm801 *chip = tea->private_data;
-       unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+       unsigned short reg = fm801_readw(chip, GPIO_CTRL);
        struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
        u8 ret;
 
@@ -780,7 +789,7 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
 static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
        struct fm801 *chip = tea->private_data;
-       unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+       unsigned short reg = fm801_readw(chip, GPIO_CTRL);
        struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
 
        /* use GPIO lines and set write enable bit */
@@ -811,7 +820,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output
                         FM801_GPIO_GP(gpio.clk));
        }
 
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
+       fm801_writew(chip, GPIO_CTRL, reg);
 }
 
 static struct snd_tea575x_ops snd_fm801_tea_ops = {
@@ -962,7 +971,7 @@ static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol,
        struct fm801 *chip = snd_kcontrol_chip(kcontrol);
         unsigned short val;
  
-       val = inw(FM801_REG(chip, REC_SRC)) & 7;
+       val = fm801_readw(chip, REC_SRC) & 7;
        if (val > 4)
                val = 4;
         ucontrol->value.enumerated.item[0] = val;
@@ -1073,12 +1082,12 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id,
 {
        unsigned long timeout = jiffies + waits;
 
-       outw(FM801_AC97_READ | (codec_id << FM801_AC97_ADDR_SHIFT) | reg,
-            FM801_REG(chip, AC97_CMD));
+       fm801_writew(chip, AC97_CMD,
+                    reg | (codec_id << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ);
        udelay(5);
        do {
-               if ((inw(FM801_REG(chip, AC97_CMD)) & (FM801_AC97_VALID|FM801_AC97_BUSY))
-                   == FM801_AC97_VALID)
+               if ((fm801_readw(chip, AC97_CMD) &
+                    (FM801_AC97_VALID | FM801_AC97_BUSY)) == FM801_AC97_VALID)
                        return 0;
                schedule_timeout_uninterruptible(1);
        } while (time_after(timeout, jiffies));
@@ -1093,10 +1102,10 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
                goto __ac97_ok;
 
        /* codec cold reset + AC'97 warm reset */
-       outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL));
-       inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
+       fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6));
+       fm801_readw(chip, CODEC_CTRL); /* flush posting data */
        udelay(100);
-       outw(0, FM801_REG(chip, CODEC_CTRL));
+       fm801_writew(chip, CODEC_CTRL, 0);
 
        if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
                if (!resume) {
@@ -1117,7 +1126,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
                        for (i = 3; i > 0; i--) {
                                if (!wait_for_codec(chip, i, AC97_VENDOR_ID1,
                                                     msecs_to_jiffies(50))) {
-                                       cmdw = inw(FM801_REG(chip, AC97_DATA));
+                                       cmdw = fm801_readw(chip, AC97_DATA);
                                        if (cmdw != 0xffff && cmdw != 0) {
                                                chip->secondary = 1;
                                                chip->secondary_addr = i;
@@ -1135,23 +1144,24 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
       __ac97_ok:
 
        /* init volume */
-       outw(0x0808, FM801_REG(chip, PCM_VOL));
-       outw(0x9f1f, FM801_REG(chip, FM_VOL));
-       outw(0x8808, FM801_REG(chip, I2S_VOL));
+       fm801_writew(chip, PCM_VOL, 0x0808);
+       fm801_writew(chip, FM_VOL, 0x9f1f);
+       fm801_writew(chip, I2S_VOL, 0x8808);
 
        /* I2S control - I2S mode */
-       outw(0x0003, FM801_REG(chip, I2S_MODE));
+       fm801_writew(chip, I2S_MODE, 0x0003);
 
        /* interrupt setup */
-       cmdw = inw(FM801_REG(chip, IRQ_MASK));
+       cmdw = fm801_readw(chip, IRQ_MASK);
        if (chip->irq < 0)
                cmdw |= 0x00c3;         /* mask everything, no PCM nor MPU */
        else
                cmdw &= ~0x0083;        /* unmask MPU, PLAYBACK & CAPTURE */
-       outw(cmdw, FM801_REG(chip, IRQ_MASK));
+       fm801_writew(chip, IRQ_MASK, cmdw);
 
        /* interrupt clear */
-       outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS));
+       fm801_writew(chip, IRQ_STATUS,
+                    FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU);
 
        return 0;
 }
@@ -1165,9 +1175,9 @@ static int snd_fm801_free(struct fm801 *chip)
                goto __end_hw;
 
        /* interrupt setup - mask everything */
-       cmdw = inw(FM801_REG(chip, IRQ_MASK));
+       cmdw = fm801_readw(chip, IRQ_MASK);
        cmdw |= 0x00c3;
-       outw(cmdw, FM801_REG(chip, IRQ_MASK));
+       fm801_writew(chip, IRQ_MASK, cmdw);
 
       __end_hw:
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
@@ -1339,15 +1349,15 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
                return err;
        }
        if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801,
-                                      FM801_REG(chip, MPU401_DATA),
+                                      chip->port + FM801_MPU401_DATA,
                                       MPU401_INFO_INTEGRATED |
                                       MPU401_INFO_IRQ_HOOK,
                                       -1, &chip->rmidi)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_opl3_create(card, FM801_REG(chip, OPL3_BANK0),
-                                  FM801_REG(chip, OPL3_BANK1),
+       if ((err = snd_opl3_create(card, chip->port + FM801_OPL3_BANK0,
+                                  chip->port + FM801_OPL3_BANK1,
                                   OPL3_HW_OPL3_FM801, 1, &opl3)) < 0) {
                snd_card_free(card);
                return err;
index 248b90abb8825a62e9530a0629cbf432898898d3..480bbddbd801bf002e4cc43fb8c7c0f762ec40c8 100644 (file)
@@ -1059,24 +1059,26 @@ static void azx_init_cmd_io(struct azx *chip)
 
        /* reset the corb hw read pointer */
        azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
-       for (timeout = 1000; timeout > 0; timeout--) {
-               if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
-                       break;
-               udelay(1);
-       }
-       if (timeout <= 0)
-               dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
-                       azx_readw(chip, CORBRP));
+       if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) {
+               for (timeout = 1000; timeout > 0; timeout--) {
+                       if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
+                               break;
+                       udelay(1);
+               }
+               if (timeout <= 0)
+                       dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
+                               azx_readw(chip, CORBRP));
 
-       azx_writew(chip, CORBRP, 0);
-       for (timeout = 1000; timeout > 0; timeout--) {
-               if (azx_readw(chip, CORBRP) == 0)
-                       break;
-               udelay(1);
+               azx_writew(chip, CORBRP, 0);
+               for (timeout = 1000; timeout > 0; timeout--) {
+                       if (azx_readw(chip, CORBRP) == 0)
+                               break;
+                       udelay(1);
+               }
+               if (timeout <= 0)
+                       dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
+                               azx_readw(chip, CORBRP));
        }
-       if (timeout <= 0)
-               dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
-                       azx_readw(chip, CORBRP));
 
        /* enable corb dma */
        azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
index d6bca62ef387b92b499dcf5954d5c783543055d1..b540ad71eb0d733ab217550a66ac40eb35e22da6 100644 (file)
@@ -249,7 +249,8 @@ enum {
 /* quirks for Nvidia */
 #define AZX_DCAPS_PRESET_NVIDIA \
        (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
-        AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT)
+        AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\
+        AZX_DCAPS_CORBRP_SELF_CLEAR)
 
 #define AZX_DCAPS_PRESET_CTHDA \
        (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
index ba38b819f9847de7522de9171c1a7794aecc7a8f..4a7cb01fa91226b2cfd3a4a582d02d9899ffa6e0 100644 (file)
@@ -189,6 +189,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
 #define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
 #define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
+#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)  /* CORBRP clears itself after reset */
 
 /* position fix mode */
 enum {
index 0cb5b89cd0c8b3e81dd57a0bcdaa471d67d018c1..016f785cdf4514ff96662e2f0042e6682f11c9a8 100644 (file)
@@ -1127,8 +1127,6 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                                            AMP_OUT_UNMUTE);
 
        eld = &per_pin->sink_eld;
-       if (!eld->monitor_present)
-               return;
 
        if (!non_pcm && per_pin->chmap_set)
                ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
index c643dfc0a82612c5a2672c5211e6e1d46c5102f3..b60de0dc40d38ef972c56966e7031065733221a1 100644 (file)
@@ -951,7 +951,9 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
        { 0x10ec0280, 0x1028, 0, "ALC3220" },
        { 0x10ec0282, 0x1028, 0, "ALC3221" },
        { 0x10ec0283, 0x1028, 0, "ALC3223" },
+       { 0x10ec0288, 0x1028, 0, "ALC3263" },
        { 0x10ec0292, 0x1028, 0, "ALC3226" },
+       { 0x10ec0293, 0x1028, 0, "ALC3235" },
        { 0x10ec0255, 0x1028, 0, "ALC3234" },
        { 0x10ec0668, 0x1028, 0, "ALC3661" },
        { } /* terminator */
@@ -3538,6 +3540,25 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0x18, 0x7308);
                alc_write_coef_idx(codec, 0x6b, 0xc429);
                break;
+       case 0x10ec0293:
+               /* SET Line1 JD to 0 */
+               val = alc_read_coef_idx(codec, 0x10);
+               alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8);
+               /* SET charge pump by verb */
+               val = alc_read_coefex_idx(codec, 0x57, 0x05);
+               alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0);
+               /* SET EN_OSW to 1 */
+               val = alc_read_coefex_idx(codec, 0x57, 0x03);
+               alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) );
+               /* Combo JD gating with LINE1-VREFO */
+               val = alc_read_coef_idx(codec, 0x1a);
+               alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3));
+               /* Set to TRS type */
+               alc_write_coef_idx(codec, 0x45, 0xc429);
+               /* Combo Jack auto detect */
+               val = alc_read_coef_idx(codec, 0x4a);
+               alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e);
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x15, 0x0d40);
                alc_write_coef_idx(codec, 0xb7, 0x802b);
@@ -3576,6 +3597,21 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                alc_write_coef_idx(codec, 0x19, 0xa208);
                alc_write_coef_idx(codec, 0x2e, 0xacf0);
                break;
+       case 0x10ec0293:
+               /* Set to TRS mode */
+               alc_write_coef_idx(codec, 0x45, 0xc429);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               /* SET charge pump by verb */
+               val = alc_read_coefex_idx(codec, 0x57, 0x05);
+               alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13));
+               /* SET EN_OSW to 0 */
+               val = alc_read_coefex_idx(codec, 0x57, 0x03);
+               alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0);
+               /* Combo JD gating without LINE1-VREFO */
+               val = alc_read_coef_idx(codec, 0x1a);
+               alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0001);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
@@ -3591,6 +3627,8 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
+       int val;
+
        switch (codec->vendor_id) {
        case 0x10ec0255:
                alc_write_coef_idx(codec, 0x45, 0xc089);
@@ -3608,6 +3646,16 @@ static void alc_headset_mode_default(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0x6b, 0xc429);
                alc_write_coef_idx(codec, 0x18, 0x7308);
                break;
+       case 0x10ec0293:
+               /* Combo Jack auto detect */
+               val = alc_read_coef_idx(codec, 0x4a);
+               alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e);
+               /* Set to TRS type */
+               alc_write_coef_idx(codec, 0x45, 0xC429);
+               /* Combo JD gating without LINE1-VREFO */
+               val = alc_read_coef_idx(codec, 0x1a);
+               alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0);
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0041);
                alc_write_coef_idx(codec, 0x15, 0x0d40);
@@ -3620,6 +3668,8 @@ static void alc_headset_mode_default(struct hda_codec *codec)
 /* Iphone type */
 static void alc_headset_mode_ctia(struct hda_codec *codec)
 {
+       int val;
+
        switch (codec->vendor_id) {
        case 0x10ec0255:
                /* Set to CTIA type */
@@ -3637,6 +3687,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0x76, 0x0008);
                alc_write_coef_idx(codec, 0x18, 0x7388);
                break;
+       case 0x10ec0293:
+               /* Set to ctia type */
+               alc_write_coef_idx(codec, 0x45, 0xd429);
+               /* SET Line1 JD to 1 */
+               val = alc_read_coef_idx(codec, 0x10);
+               alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8);
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0001);
                alc_write_coef_idx(codec, 0x15, 0x0d60);
@@ -3649,6 +3706,8 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
 /* Nokia type */
 static void alc_headset_mode_omtp(struct hda_codec *codec)
 {
+       int val;
+
        switch (codec->vendor_id) {
        case 0x10ec0255:
                /* Set to OMTP Type */
@@ -3666,6 +3725,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0x76, 0x0008);
                alc_write_coef_idx(codec, 0x18, 0x7388);
                break;
+       case 0x10ec0293:
+               /* Set to omtp type */
+               alc_write_coef_idx(codec, 0x45, 0xe429);
+               /* SET Line1 JD to 1 */
+               val = alc_read_coef_idx(codec, 0x10);
+               alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8);
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0001);
                alc_write_coef_idx(codec, 0x15, 0x0d50);
@@ -3703,6 +3769,16 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                val = alc_read_coef_idx(codec, 0x6c);
                is_ctia = (val & 0x001c) == 0x001c;
                break;
+       case 0x10ec0293:
+               /* Combo Jack auto detect */
+               val = alc_read_coef_idx(codec, 0x4a);
+               alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008);
+               /* Set to ctia type */
+               alc_write_coef_idx(codec, 0x45, 0xD429);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x0070) == 0x0070;
+               break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0001);
                alc_write_coef_idx(codec, 0xb7, 0x802b);
@@ -4159,6 +4235,7 @@ enum {
        ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
        ALC255_FIXUP_HEADSET_MODE,
        ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
+       ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4552,6 +4629,16 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_alc255_no_hp_mic,
        },
+       [ALC293_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4609,6 +4696,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -4621,9 +4710,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x067e, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        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(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
        SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
index 2d8e95e9fbe59c547ad0026a136788e8e4f1d411..e8f38e5df10abcae863756ac0134c0e5d2c1f1c1 100644 (file)
@@ -24,6 +24,7 @@
 
 /* #define RMH_DEBUG 1 */
 
+#include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -429,11 +430,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
        return ret;
 }
 
-#define CSES_TIMEOUT        100     /* microseconds */
-#define CSES_CE             0x0001
-#define CSES_BROADCAST      0x0002
-#define CSES_UPDATE_LDSV    0x0004
-
 #define PIPE_INFO_TO_CMD(capture, pipe)                                        \
        ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
 
@@ -519,7 +515,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
                                *r_needed += 1;
                }
 
-#if 0
                dev_dbg(chip->card->dev,
                        "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
                            *r_needed, *r_freed);
@@ -530,7 +525,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
                                            chip->rmh.stat[i],
                                            chip->rmh.stat[i] & MASK_DATA_SIZE);
                }
-#endif
        }
 
        spin_unlock_irqrestore(&chip->msg_lock, flags);
@@ -971,9 +965,9 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
 
 /* interrupt handling */
 #define PCX_IRQ_NONE 0
-#define IRQCS_ACTIVE_PCIDB  0x00002000L         /* Bit nÃ\83¸ 13 */
-#define IRQCS_ENABLE_PCIIRQ 0x00000100L         /* Bit nÃ\83¸ 08 */
-#define IRQCS_ENABLE_PCIDB  0x00000200L         /* Bit nÃ\83¸ 09 */
+#define IRQCS_ACTIVE_PCIDB     BIT(13)
+#define IRQCS_ENABLE_PCIIRQ    BIT(8)
+#define IRQCS_ENABLE_PCIDB     BIT(9)
 
 static u32 lx_interrupt_test_ack(struct lx6464es *chip)
 {
@@ -1030,25 +1024,21 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
        int err;
        u32 stat[9];            /* answer from CMD_04_GET_EVENT */
 
-       /* On peut optimiser pour ne pas lire les evenements vides
-        * les mots de rÃ\83©ponse sont dans l'ordre suivant :
-        * Stat[0]      mot de status gÃ\83©nÃ\83©ral
-        * Stat[1]      fin de buffer OUT pF
-        * Stat[2]      fin de buffer OUT pf
-        * Stat[3]      fin de buffer IN pF
-        * Stat[4]      fin de buffer IN pf
-        * Stat[5]      underrun poid fort
-        * Stat[6]      underrun poid faible
-        * Stat[7]      overrun poid fort
-        * Stat[8]      overrun poid faible
+       /* We can optimize this to not read dumb events.
+        * Answer words are in the following order:
+        * Stat[0]      general status
+        * Stat[1]      end of buffer OUT pF
+        * Stat[2]      end of buffer OUT pf
+        * Stat[3]      end of buffer IN pF
+        * Stat[4]      end of buffer IN pf
+        * Stat[5]      MSB underrun
+        * Stat[6]      LSB underrun
+        * Stat[7]      MSB overrun
+        * Stat[8]      LSB overrun
         * */
 
        u64 orun_mask;
        u64 urun_mask;
-#if 0
-       int has_underrun   = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0;
-       int has_overrun    = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0;
-#endif
        int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
        int eb_pending_in  = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
 
@@ -1199,9 +1189,8 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
        if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
                goto exit;
 
-#if 0
        if (irqsrc & MASK_SYS_STATUS_EOBI)
-               dev_dgg(chip->card->dev, "interrupt: EOBI\n");
+               dev_dbg(chip->card->dev, "interrupt: EOBI\n");
 
        if (irqsrc & MASK_SYS_STATUS_EOBO)
                dev_dbg(chip->card->dev, "interrupt: EOBO\n");
@@ -1211,7 +1200,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
 
        if (irqsrc & MASK_SYS_STATUS_ORUN)
                dev_dbg(chip->card->dev, "interrupt: ORUN\n");
-#endif
 
        if (async_pending) {
                u64 notified_in_pipe_mask = 0;
@@ -1238,7 +1226,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
        }
 
        if (async_escmd) {
-#if 0
                /* backdoor for ethersound commands
                 *
                 * for now, we do not need this
@@ -1246,7 +1233,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
                 * */
 
                dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
-#endif
        }
 
 exit:
index 4789619a52d86dc38b8da2222b11cbda50dd0a8c..27e3fc4a536b40595d774865c7f9b7013c01752a 100644 (file)
@@ -35,7 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
 
 config SND_ATMEL_SOC_WM8904
        tristate "Atmel ASoC driver for boards using WM8904 codec"
-       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && I2C
        select SND_ATMEL_SOC_SSC
        select SND_ATMEL_SOC_DMA
        select SND_SOC_WM8904
index b07e17160f94a0453cf080cc487da4874f930673..3c4b10ff48c1c94cc15432d8f945d8a486376a75 100644 (file)
@@ -276,7 +276,7 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        int val[2], val2[2], i;
@@ -300,7 +300,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        int err;
@@ -333,7 +333,7 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -353,7 +353,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -1327,10 +1327,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)
 
        pm860x->codec = codec;
 
-       ret = snd_soc_codec_set_cache_io(codec, pm860x->regmap);
-       if (ret)
-               return ret;
-
        for (i = 0; i < 4; i++) {
                ret = request_threaded_irq(pm860x->irq[i], NULL,
                                           pm860x_codec_handler, IRQF_ONESHOT,
@@ -1362,10 +1358,18 @@ static int pm860x_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static struct regmap *pm860x_get_regmap(struct device *dev)
+{
+       struct pm860x_priv *pm860x = dev_get_drvdata(dev);
+
+       return pm860x->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
        .probe          = pm860x_probe,
        .remove         = pm860x_remove,
        .set_bias_level = pm860x_set_bias_level,
+       .get_regmap     = pm860x_get_regmap,
 
        .controls = pm860x_snd_controls,
        .num_controls = ARRAY_SIZE(pm860x_snd_controls),
index f0e8401378873721f0e69e7fe338fe00afe29fb5..4711e507bfc3596bba5d53e7cb59d04bcee0c062 100644 (file)
@@ -39,8 +39,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_ALC5623 if I2C
        select SND_SOC_ALC5632 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
-       select SND_SOC_CS42L51 if I2C
-       select SND_SOC_CS42L52 if I2C
+       select SND_SOC_CS42L51_I2C if I2C
+       select SND_SOC_CS42L52 if I2C && INPUT
        select SND_SOC_CS42L73 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
@@ -71,6 +71,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_PCM512x_SPI if SPI_MASTER
        select SND_SOC_RT5631 if I2C
        select SND_SOC_RT5640 if I2C
+       select SND_SOC_RT5651 if I2C
        select SND_SOC_SGTL5000 if I2C
        select SND_SOC_SI476X if MFD_SI476X_CORE
        select SND_SOC_SIRF_AUDIO_CODEC
@@ -80,6 +81,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_SSM2602_SPI if SPI_MASTER
        select SND_SOC_SSM2602_I2C if I2C
        select SND_SOC_STA32X if I2C
+       select SND_SOC_STA350 if I2C
        select SND_SOC_STA529 if I2C
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
        select SND_SOC_TAS5086 if I2C
@@ -127,7 +129,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
        select SND_SOC_WM8961 if I2C
-       select SND_SOC_WM8962 if I2C
+       select SND_SOC_WM8962 if I2C && INPUT
        select SND_SOC_WM8971 if I2C
        select SND_SOC_WM8974 if I2C
        select SND_SOC_WM8978 if I2C
@@ -280,9 +282,13 @@ config SND_SOC_CQ0093VC
 config SND_SOC_CS42L51
        tristate
 
+config SND_SOC_CS42L51_I2C
+       tristate
+       select SND_SOC_CS42L51
+
 config SND_SOC_CS42L52
        tristate "Cirrus Logic CS42L52 CODEC"
-       depends on I2C
+       depends on I2C && INPUT
 
 config SND_SOC_CS42L73
        tristate "Cirrus Logic CS42L73 CODEC"
@@ -396,6 +402,9 @@ config SND_SOC_RT5631
 config SND_SOC_RT5640
        tristate
 
+config SND_SOC_RT5651
+       tristate
+
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
        tristate "Freescale SGTL5000 CODEC"
@@ -435,6 +444,10 @@ config SND_SOC_SSM2602_I2C
 config SND_SOC_STA32X
        tristate
 
+config SND_SOC_STA350
+       tristate "STA350 speaker amplifier"
+       depends on I2C
+
 config SND_SOC_STA529
        tristate
 
@@ -598,7 +611,7 @@ config SND_SOC_WM8961
 
 config SND_SOC_WM8962
        tristate "Wolfson Microelectronics WM8962 CODEC"
-       depends on I2C
+       depends on I2C && INPUT
 
 config SND_SOC_WM8971
        tristate
index 3c4d275d064bf8cc921c754a2dc577bdf72f4fe8..8d1930dd4f01284bfca1dd0088882086becc67bc 100644 (file)
@@ -26,6 +26,7 @@ snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
 snd-soc-cs42l52-objs := cs42l52.o
 snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4270-objs := cs4270.o
@@ -60,6 +61,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
+snd-soc-rt5651-objs := rt5651.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
@@ -74,6 +76,7 @@ snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-ssm2602-spi-objs := ssm2602-spi.o
 snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
 snd-soc-sta32x-objs := sta32x.o
+snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
@@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_ALC5632)       += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)  += snd-soc-arizona.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS42L51)  += snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L51_I2C)      += snd-soc-cs42l51-i2c.o
 obj-$(CONFIG_SND_SOC_CS42L52)  += snd-soc-cs42l52.o
 obj-$(CONFIG_SND_SOC_CS42L73)  += snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
@@ -211,6 +215,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C)   += snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)      += snd-soc-pcm512x-spi.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
+obj-$(CONFIG_SND_SOC_RT5651)   += snd-soc-rt5651.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SI476X)   += snd-soc-si476x.o
@@ -221,6 +226,7 @@ obj-$(CONFIG_SND_SOC_SSM2602)       += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_SSM2602_SPI)      += snd-soc-ssm2602-spi.o
 obj-$(CONFIG_SND_SOC_SSM2602_I2C)      += snd-soc-ssm2602-i2c.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
+obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
index 1ad92cbf0b24dfba1f97ecad1a8eca1b56940fad..1fb4402bf72d3047c38fdca362700d4c65739dd7 100644 (file)
@@ -1139,7 +1139,7 @@ static void anc_configure(struct snd_soc_codec *codec,
 static int sid_status_control_get(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 
        mutex_lock(&codec->mutex);
@@ -1153,7 +1153,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
 static int sid_status_control_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
        unsigned int param, sidconf, val;
        int status = 1;
@@ -1208,7 +1208,7 @@ out:
 static int anc_status_control_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 
        mutex_lock(&codec->mutex);
@@ -1221,7 +1221,7 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
 static int anc_status_control_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
        struct device *dev = codec->dev;
        bool apply_fir, apply_iir;
@@ -1306,7 +1306,7 @@ static int filter_control_info(struct snd_kcontrol *kcontrol,
 static int filter_control_get(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct filter_control *fc =
                        (struct filter_control *)kcontrol->private_value;
        unsigned int i;
@@ -1322,7 +1322,7 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
 static int filter_control_put(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct filter_control *fc =
                        (struct filter_control *)kcontrol->private_value;
        unsigned int i;
index 877f5737bb6b23bf924ab6b4a48c88f4498a950e..1ff7d4d027e932e9c20f8841bf09b89f210e6635 100644 (file)
@@ -519,8 +519,7 @@ static const struct snd_kcontrol_new adau1373_controls[] = {
        SOC_ENUM("HPF Channel", adau1373_hpf_channel_enum),
 
        SOC_ENUM("Bass HPF Cutoff", adau1373_bass_hpf_cutoff_enum),
-       SOC_VALUE_ENUM("Bass Clip Level Threshold",
-           adau1373_bass_clip_level_enum),
+       SOC_ENUM("Bass Clip Level Threshold", adau1373_bass_clip_level_enum),
        SOC_ENUM("Bass LPF Cutoff", adau1373_bass_lpf_cutoff_enum),
        SOC_DOUBLE("Bass Playback Switch", ADAU1373_BASS2, 0, 1, 1, 0),
        SOC_SINGLE_TLV("Bass Playback Volume", ADAU1373_BASS2, 2, 7, 0,
@@ -580,7 +579,7 @@ static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum,
        adau1373_decimator_text);
 
 static const struct snd_kcontrol_new adau1373_decimator_mux =
-       SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum);
+       SOC_DAPM_ENUM("Decimator Mux", adau1373_decimator_enum);
 
 static const struct snd_kcontrol_new adau1373_left_adc_mixer_controls[] = {
        SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_LADC_MIXER, 4, 1, 0),
@@ -694,7 +693,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1373_DIGMICCTRL, 0, 0),
        SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1373_DIGMICCTRL, 2, 0),
 
-       SND_SOC_DAPM_VIRT_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0,
+       SND_SOC_DAPM_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0,
                &adau1373_decimator_mux),
 
        SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0),
index 5062e34ee8dcbdec1849ce83c299409b4ee6d582..c43b93fdf0dfe466e3c72e97eec0c5da5da06ecb 100644 (file)
@@ -172,14 +172,14 @@ static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3);
 static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3);
 
 static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl =
-       SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum);
+       SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum);
 static const struct snd_kcontrol_new adav80x_capture_mux_ctrl =
-       SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum);
+       SOC_DAPM_ENUM("Route", adav80x_capture_enum);
 static const struct snd_kcontrol_new adav80x_dac_mux_ctrl =
-       SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum);
+       SOC_DAPM_ENUM("Route", adav80x_dac_enum);
 
 #define ADAV80X_MUX(name, ctrl) \
-       SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+       SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
 
 static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1),
@@ -315,7 +315,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec)
 static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
        unsigned int deemph = ucontrol->value.enumerated.item[0];
 
@@ -330,7 +330,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = adav80x->deemph;
index 10adf25d4c14f36e64d383d8be3a967387ce1726..1fd7f72b2a62a05f99567e02e634328f65bc5fce 100644 (file)
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
 #include <linux/spi/spi.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
 #include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
 
 /* AK4104 registers addresses */
 #define AK4104_REG_CONTROL1            0x00
@@ -47,6 +48,7 @@
 
 struct ak4104_private {
        struct regmap *regmap;
+       struct regulator *regulator;
 };
 
 static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
@@ -174,20 +176,30 @@ static int ak4104_probe(struct snd_soc_codec *codec)
        struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
+       ret = regulator_enable(ak4104->regulator);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unable to enable regulator: %d\n", ret);
+               return ret;
+       }
+
        /* set power-up and non-reset bits */
        ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
        if (ret < 0)
-               return ret;
+               goto exit_disable_regulator;
 
        /* enable transmitter */
        ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
                                 AK4104_TX_TXE, AK4104_TX_TXE);
        if (ret < 0)
-               return ret;
+               goto exit_disable_regulator;
 
        return 0;
+
+exit_disable_regulator:
+       regulator_disable(ak4104->regulator);
+       return ret;
 }
 
 static int ak4104_remove(struct snd_soc_codec *codec)
@@ -196,13 +208,42 @@ static int ak4104_remove(struct snd_soc_codec *codec)
 
        regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
                           AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
+       regulator_disable(ak4104->regulator);
 
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int ak4104_soc_suspend(struct snd_soc_codec *codec)
+{
+       struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       regulator_disable(priv->regulator);
+
+       return 0;
+}
+
+static int ak4104_soc_resume(struct snd_soc_codec *codec)
+{
+       struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = regulator_enable(priv->regulator);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+#else
+#define ak4104_soc_suspend     NULL
+#define ak4104_soc_resume      NULL
+#endif /* CONFIG_PM */
+
 static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
-       .probe =        ak4104_probe,
-       .remove =       ak4104_remove,
+       .probe = ak4104_probe,
+       .remove = ak4104_remove,
+       .suspend = ak4104_soc_suspend,
+       .resume = ak4104_soc_resume,
 
        .dapm_widgets = ak4104_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
@@ -239,6 +280,13 @@ static int ak4104_spi_probe(struct spi_device *spi)
        if (ak4104 == NULL)
                return -ENOMEM;
 
+       ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
+       if (IS_ERR(ak4104->regulator)) {
+               ret = PTR_ERR(ak4104->regulator);
+               dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
+               return ret;
+       }
+
        ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
        if (IS_ERR(ak4104->regmap)) {
                ret = PTR_ERR(ak4104->regmap);
index 868c0e2da1ece12102dc7f6a1ecc2aa6d50a66ab..7afe8f4820887b695cb20912f9f68e0c17de7de1 100644 (file)
@@ -74,7 +74,7 @@ static int ak4641_set_deemph(struct snd_soc_codec *codec)
 static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
 
@@ -89,7 +89,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = ak4641->deemph;
index f500905e9373510d2bcfdb583b0569cec5994708..2acf82f4a08a8bed4db26c6c444a0eabec688412 100644 (file)
@@ -1018,13 +1018,13 @@ static int alc5623_i2c_probe(struct i2c_client *client,
                dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret);
                return ret;
        }
-       vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8);
 
        ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2);
        if (ret < 0) {
                dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret);
                return ret;
        }
+       vid2 >>= 8;
 
        if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
                dev_err(&client->dev, "unknown or wrong codec\n");
index 16df0f9133537569c2a84f677e4fcb23d7af1b4e..05ae17f5bca30bd611d5514a5b6f850bce26906e 100644 (file)
@@ -107,7 +107,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 
 #define ARIZONA_MUX_CTL_DECL(name) \
        const struct snd_kcontrol_new name##_mux =      \
-               SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+               SOC_DAPM_ENUM("Route", name##_enum)
 
 #define ARIZONA_MUX_ENUMS(name, base_reg) \
        static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg);      \
@@ -128,7 +128,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40)
 
 #define ARIZONA_MUX(name, ctrl) \
-       SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+       SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
 
 #define ARIZONA_MUX_WIDGETS(name, name_str) \
        ARIZONA_MUX(name_str " Input", &name##_mux)
index 1e25c7af853bcdb7c40b7c94d4cb2ca6e878b8be..537327c7f7f13f364fa99d52e07848653fe3559e 100644 (file)
@@ -139,8 +139,6 @@ static int cq93vc_probe(struct snd_soc_codec *codec)
 
        davinci_vc->cq93vc.codec = codec;
 
-       snd_soc_codec_set_cache_io(codec, davinci_vc->regmap);
-
        /* Off, with power on */
        cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -154,11 +152,19 @@ static int cq93vc_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static struct regmap *cq93vc_get_regmap(struct device *dev)
+{
+       struct davinci_vc *davinci_vc = dev->platform_data;
+
+       return davinci_vc->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
        .set_bias_level = cq93vc_set_bias_level,
        .probe = cq93vc_probe,
        .remove = cq93vc_remove,
        .resume = cq93vc_resume,
+       .get_regmap = cq93vc_get_regmap,
        .controls = cq93vc_snd_controls,
        .num_controls = ARRAY_SIZE(cq93vc_snd_controls),
 };
index 3920e626494885947853fd856f9d5ed37bc443ed..9947a95836794f382b8bf60110c6dee857bde4e2 100644 (file)
@@ -438,7 +438,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
 static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int left = !ucontrol->value.integer.value[0];
        int right = !ucontrol->value.integer.value[1];
index aef4965750c780ec52bea5d0285fe1142e1ba83d..93cec52f473332fbd37cc28be97c03c4696d1780 100644 (file)
@@ -284,7 +284,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec)
 static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = cs4271->deemph;
@@ -294,7 +294,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
 static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
        cs4271->deemph = ucontrol->value.enumerated.item[0];
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
new file mode 100644 (file)
index 0000000..cee51ae
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * cs42l56.c -- CS42L51 ALSA SoC I2C audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.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/i2c.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "cs42l51.h"
+
+static struct i2c_device_id cs42l51_i2c_id[] = {
+       {"cs42l51", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct regmap_config config;
+
+       config = cs42l51_regmap;
+       config.val_bits = 8;
+       config.reg_bits = 8;
+
+       return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static struct i2c_driver cs42l51_i2c_driver = {
+       .driver = {
+               .name = "cs42l51",
+               .owner = THIS_MODULE,
+       },
+       .probe = cs42l51_i2c_probe,
+       .remove = cs42l51_i2c_remove,
+       .id_table = cs42l51_i2c_id,
+};
+
+module_i2c_driver(cs42l51_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
index 6c0da2baa154e2a79a1baaf4392efacf4a7694af..09488d97de60d040bbdb37edfa3a94a999930633 100644 (file)
@@ -29,7 +29,6 @@
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
 #include <sound/pcm.h>
-#include <linux/i2c.h>
 #include <linux/regmap.h>
 
 #include "cs42l51.h"
@@ -55,7 +54,7 @@ struct cs42l51_private {
 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
 
        switch (value) {
@@ -83,7 +82,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
 static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned char val;
 
        switch (ucontrol->value.integer.value[0]) {
@@ -483,7 +482,7 @@ static struct snd_soc_dai_driver cs42l51_dai = {
        .ops = &cs42l51_dai_ops,
 };
 
-static int cs42l51_probe(struct snd_soc_codec *codec)
+static int cs42l51_codec_probe(struct snd_soc_codec *codec)
 {
        int ret, reg;
 
@@ -504,7 +503,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
-       .probe = cs42l51_probe,
+       .probe = cs42l51_codec_probe,
 
        .controls = cs42l51_snd_controls,
        .num_controls = ARRAY_SIZE(cs42l51_snd_controls),
@@ -514,91 +513,56 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
        .num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
 };
 
-static const struct regmap_config cs42l51_regmap = {
-       .reg_bits = 8,
-       .val_bits = 8,
-
+const struct regmap_config cs42l51_regmap = {
        .max_register = CS42L51_CHARGE_FREQ,
        .cache_type = REGCACHE_RBTREE,
 };
+EXPORT_SYMBOL_GPL(cs42l51_regmap);
 
-static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
-       const struct i2c_device_id *id)
+int cs42l51_probe(struct device *dev, struct regmap *regmap)
 {
        struct cs42l51_private *cs42l51;
-       struct regmap *regmap;
        unsigned int val;
        int ret;
 
-       regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap);
-       if (IS_ERR(regmap)) {
-               ret = PTR_ERR(regmap);
-               dev_err(&i2c_client->dev, "Failed to create regmap: %d\n",
-                       ret);
-               return ret;
-       }
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
+                              GFP_KERNEL);
+       if (!cs42l51)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, cs42l51);
 
        /* Verify that we have a CS42L51 */
        ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to read I2C\n");
+               dev_err(dev, "failed to read I2C\n");
                goto error;
        }
 
        if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
            (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
-               dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val);
+               dev_err(dev, "Invalid chip id: %x\n", val);
                ret = -ENODEV;
                goto error;
        }
+       dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
+                val & CS42L51_CHIP_REV_MASK);
 
-       dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
-                val & 7);
-
-       cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private),
-                              GFP_KERNEL);
-       if (!cs42l51)
-               return -ENOMEM;
-
-       i2c_set_clientdata(i2c_client, cs42l51);
-
-       ret =  snd_soc_register_codec(&i2c_client->dev,
+       ret =  snd_soc_register_codec(dev,
                        &soc_codec_device_cs42l51, &cs42l51_dai, 1);
 error:
        return ret;
 }
-
-static int cs42l51_i2c_remove(struct i2c_client *client)
-{
-       snd_soc_unregister_codec(&client->dev);
-       return 0;
-}
-
-static const struct i2c_device_id cs42l51_id[] = {
-       {"cs42l51", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+EXPORT_SYMBOL_GPL(cs42l51_probe);
 
 static const struct of_device_id cs42l51_of_match[] = {
        { .compatible = "cirrus,cs42l51", },
        { }
 };
 MODULE_DEVICE_TABLE(of, cs42l51_of_match);
-
-static struct i2c_driver cs42l51_i2c_driver = {
-       .driver = {
-               .name = "cs42l51-codec",
-               .owner = THIS_MODULE,
-               .of_match_table = cs42l51_of_match,
-       },
-       .id_table = cs42l51_id,
-       .probe = cs42l51_i2c_probe,
-       .remove = cs42l51_i2c_remove,
-};
-
-module_i2c_driver(cs42l51_i2c_driver);
-
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
 MODULE_LICENSE("GPL");
index 2beeb171db4b99f8635b01304d97f7b0439e7fe0..8c55bf384bc65189545807d9ce9278d6c66670f2 100644 (file)
 #ifndef _CS42L51_H
 #define _CS42L51_H
 
+struct device;
+
+extern const struct regmap_config cs42l51_regmap;
+int cs42l51_probe(struct device *dev, struct regmap *regmap);
+
 #define CS42L51_CHIP_ID                        0x1B
 #define CS42L51_CHIP_REV_A             0x00
 #define CS42L51_CHIP_REV_B             0x01
+#define CS42L51_CHIP_REV_MASK          0x07
 
 #define CS42L51_CHIP_REV_ID            0x01
 #define CS42L51_MK_CHIP_REV(a, b)      ((a)<<3|(b))
index 460d35547a683d226521591333ce06fe1c5de634..071fc77f2f06c8fad7133d881f5e4b70631fd6b9 100644 (file)
@@ -50,11 +50,9 @@ struct  cs42l52_private {
        u8 mclksel;
        u32 mclk;
        u8 flags;
-#if IS_ENABLED(CONFIG_INPUT)
        struct input_dev *beep;
        struct work_struct beep_work;
        int beep_rate;
-#endif
 };
 
 static const struct reg_default cs42l52_reg_defaults[] = {
@@ -962,7 +960,6 @@ static int cs42l52_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_INPUT)
 static int beep_rates[] = {
        261, 522, 585, 667, 706, 774, 889, 1000,
        1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1096,15 +1093,6 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
                            CS42L52_BEEP_EN_MASK, 0);
 }
-#else
-static void cs42l52_init_beep(struct snd_soc_codec *codec)
-{
-}
-
-static void cs42l52_free_beep(struct snd_soc_codec *codec)
-{
-}
-#endif
 
 static int cs42l52_probe(struct snd_soc_codec *codec)
 {
@@ -1229,8 +1217,10 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
        }
 
        if (cs42l52->pdata.reset_gpio) {
-               ret = gpio_request_one(cs42l52->pdata.reset_gpio,
-                                      GPIOF_OUT_INIT_HIGH, "CS42L52 /RST");
+               ret = devm_gpio_request_one(&i2c_client->dev,
+                                           cs42l52->pdata.reset_gpio,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "CS42L52 /RST");
                if (ret < 0) {
                        dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
                                cs42l52->pdata.reset_gpio, ret);
index 0ee60a19a26334dcae0484244fcf9d374965fc88..ae3717992d568fb2ba533634a25e306a9e8fd05b 100644 (file)
@@ -1443,8 +1443,10 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
        i2c_set_clientdata(i2c_client, cs42l73);
 
        if (cs42l73->pdata.reset_gpio) {
-               ret = gpio_request_one(cs42l73->pdata.reset_gpio,
-                                      GPIOF_OUT_INIT_HIGH, "CS42L73 /RST");
+               ret = devm_gpio_request_one(&i2c_client->dev,
+                                           cs42l73->pdata.reset_gpio,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "CS42L73 /RST");
                if (ret < 0) {
                        dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
                                cs42l73->pdata.reset_gpio, ret);
index 137e8ebc092c5a9f2c1264723211ba7e8405871f..21810e5f3321c863c48ec00bab4f1bbfddc203d8 100644 (file)
@@ -335,7 +335,7 @@ static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
 static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 
        if (ucontrol->value.integer.value[0]) {
                /* Check if noise suppression is enabled */
@@ -358,7 +358,7 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
 static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        u8 val;
 
        if (ucontrol->value.integer.value[0]) {
index 738fa18a50d2a82c900c49fbc68f3c07c7dd2c07..9ec577f0edb4c061197e75b932f671c43577b208 100644 (file)
@@ -345,7 +345,7 @@ static void da7213_alc_calib(struct snd_soc_codec *codec)
 static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
@@ -361,7 +361,7 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
 static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
 
        /* Force ALC offset calibration if enabling ALC */
index 48f3fef6848451cecb80c586a742d4ccaa619dbd..2fae31cb006745587e0fb1a51491dd10e0facea5 100644 (file)
@@ -332,7 +332,7 @@ static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
 static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg = enum_ctrl->reg;
        unsigned int sel = ucontrol->value.integer.value[0];
@@ -360,7 +360,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
 static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg = enum_ctrl->reg;
        int val;
index 4ff06b50fbba78342b596058bfac5a9ce973d097..ad19cc56702b46fda1d98045730ae27bd3a2b633 100644 (file)
@@ -484,7 +484,7 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
 static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        u8 reg_val, adc_left, adc_right, mic_left, mic_right;
        int avg_left_data, avg_right_data, offset_l, offset_r;
 
index 9cb1c7d3e1dca6dafbeaf1247c2bccf073212061..1087fd5f9917b013e68e555607d3b6d811d42bd3 100644 (file)
@@ -20,6 +20,7 @@
  */
 #include <linux/module.h>
 #include <sound/soc.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
 
 #define DRV_NAME "hdmi-audio-codec"
index 4f048db9f55f1aa0953f4c971c0425a3178a159c..a924bb9d78860c11c84d7420f46c54929d3b7eb8 100644 (file)
@@ -49,7 +49,7 @@ static const struct reg_default lm4857_default_regs[] = {
 static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = lm4857->mode;
@@ -60,7 +60,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
 static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
        uint8_t value = ucontrol->value.integer.value[0];
 
index ec481fc428c7c9fcb7a963fbabd1e9f34c1ace7b..e1c196a4193033c2cb033c6116076c4269b7dd33 100644 (file)
@@ -43,7 +43,7 @@ static struct reg_default max9768_default_regs[] = {
 static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
        int val = gpio_get_value_cansleep(max9768->mute_gpio);
 
@@ -55,7 +55,7 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
 static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
 
        gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
index ef7cf89f562342307828eafbe0c7b9094b5546e1..9134982807b5dbab87a36581b10454b39f7ba791 100644 (file)
@@ -635,7 +635,7 @@ static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
 static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        unsigned int sel = ucontrol->value.integer.value[0];
 
@@ -649,7 +649,7 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
 static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = max98088->mic1pre;
@@ -659,7 +659,7 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
 static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        unsigned int sel = ucontrol->value.integer.value[0];
 
@@ -673,7 +673,7 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
 static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = max98088->mic2pre;
@@ -1750,7 +1750,7 @@ static void max98088_setup_eq2(struct snd_soc_codec *codec)
 static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        struct max98088_pdata *pdata = max98088->pdata;
        int channel = max98088_get_channel(codec, kcontrol->id.name);
@@ -1782,7 +1782,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
 static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        int channel = max98088_get_channel(codec, kcontrol->id.name);
        struct max98088_cdata *cdata;
index f7b0b37aa85827e7cd45a8afda039078c7079f0e..f3dd9791e73664474653e3c4c9f1dc07975a2072 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
@@ -426,7 +427,7 @@ static const unsigned int max98090_rcv_lout_tlv[] = {
 static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -466,7 +467,7 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
 static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -875,7 +876,7 @@ static const char *dmic_mux_text[] = { "ADC", "DMIC" };
 static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);
 
 static const struct snd_kcontrol_new max98090_dmic_mux =
-       SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum);
+       SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum);
 
 static const char *max98090_micpre_text[] = { "Off", "On" };
 
@@ -1175,8 +1176,7 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,
                0, 0, &max98090_mic2_mux),
 
-       SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM,
-               0, 0, &max98090_dmic_mux),
+       SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux),
 
        SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
                M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
index 03f0536e6f6185cf72178fad877484a4eb1dc679..d6c1e4c19a5ab7e17b5d56fb249689023c33e4e2 100644 (file)
@@ -612,7 +612,7 @@ static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
 static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        unsigned int sel = ucontrol->value.integer.value[0];
 
@@ -626,7 +626,7 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
 static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = max98095->mic1pre;
@@ -636,7 +636,7 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
 static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        unsigned int sel = ucontrol->value.integer.value[0];
 
@@ -650,7 +650,7 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
 static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = max98095->mic2pre;
@@ -1737,7 +1737,7 @@ static int max98095_get_eq_channel(const char *name)
 static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        struct max98095_pdata *pdata = max98095->pdata;
        int channel = max98095_get_eq_channel(kcontrol->id.name);
@@ -1801,7 +1801,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
 static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        int channel = max98095_get_eq_channel(kcontrol->id.name);
        struct max98095_cdata *cdata;
@@ -1891,7 +1891,7 @@ static int max98095_get_bq_channel(struct snd_soc_codec *codec,
 static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        struct max98095_pdata *pdata = max98095->pdata;
        int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
@@ -1952,7 +1952,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
 static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
        struct max98095_cdata *cdata;
@@ -2399,10 +2399,17 @@ static const struct i2c_device_id max98095_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
 
+static const struct of_device_id max98095_of_match[] = {
+       { .compatible = "maxim,max98095", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max98095_of_match);
+
 static struct i2c_driver max98095_i2c_driver = {
        .driver = {
                .name = "max98095",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(max98095_of_match),
        },
        .probe  = max98095_i2c_probe,
        .remove = max98095_i2c_remove,
index 2c59b1fb69dc98368035e2c4d05a4db9f1cc167b..9965277b595a33b552a65f3188e00a17b1077e1a 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mfd/mc13xxx.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -409,7 +410,7 @@ static const char * const adcl_enum_text[] = {
 static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);
 
 static const struct snd_kcontrol_new left_input_mux =
-       SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
+       SOC_DAPM_ENUM("Route", adcl_enum);
 
 static const char * const adcr_enum_text[] = {
        "MC1R", "MC2", "RXINR", "TXIN",
@@ -418,7 +419,7 @@ static const char * const adcr_enum_text[] = {
 static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);
 
 static const struct snd_kcontrol_new right_input_mux =
-       SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
+       SOC_DAPM_ENUM("Route", adcr_enum);
 
 static const struct snd_kcontrol_new samp_ctl =
        SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
@@ -478,9 +479,9 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
        SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),
        SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl),
 
-       SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
+       SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
                              &left_input_mux),
-       SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
+       SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
                              &right_input_mux),
 
        SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
@@ -608,14 +609,6 @@ static struct snd_kcontrol_new mc13783_control_list[] = {
 static int mc13783_probe(struct snd_soc_codec *codec)
 {
        struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec,
-                       dev_get_regmap(codec->dev->parent, NULL));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
 
        /* these are the reset values */
        mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
@@ -735,9 +728,15 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
        }
 };
 
+static struct regmap *mc13783_get_regmap(struct device *dev)
+{
+       return dev_get_regmap(dev->parent, NULL);
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
        .probe          = mc13783_probe,
        .remove         = mc13783_remove,
+       .get_regmap     = mc13783_get_regmap,
        .controls       = mc13783_control_list,
        .num_controls   = ARRAY_SIZE(mc13783_control_list),
        .dapm_widgets   = mc13783_dapm_widgets,
@@ -750,6 +749,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
 {
        struct mc13783_priv *priv;
        struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *np;
        int ret;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -760,7 +760,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
                priv->adc_ssi_port = pdata->adc_ssi_port;
                priv->dac_ssi_port = pdata->dac_ssi_port;
        } else {
-               return -ENOSYS;
+               np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
+               if (!np)
+                       return -ENOSYS;
+
+               ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
+               if (ret)
+                       return ret;
+
+               ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
+               if (ret)
+                       return ret;
        }
 
        dev_set_drvdata(&pdev->dev, priv);
index e427544183d7f2ee095913adc0a8ad7104f4ebd4..a722a023c26280a3c89f7a198e95c818f0c2fe6a 100644 (file)
@@ -115,7 +115,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)
 static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = priv->deemph;
@@ -126,7 +126,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
 static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
        priv->deemph = ucontrol->value.enumerated.item[0];
index 4b4c0c7bb918febbf405b1422a899a0367e63db6..163ec3855fd4027e01a1067fa6842688f0175f4b 100644 (file)
@@ -269,7 +269,7 @@ SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
           PCM512x_RQMR_SHIFT, 1, 1),
 
 SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
-SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program),
+SOC_ENUM("DSP Program", pcm512x_dsp_program),
 
 SOC_ENUM("Clock Missing Period", pcm512x_clk_missing),
 SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l),
@@ -517,6 +517,7 @@ void pcm512x_remove(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(pcm512x_remove);
 
+#ifdef CONFIG_PM_RUNTIME
 static int pcm512x_suspend(struct device *dev)
 {
        struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
@@ -578,6 +579,7 @@ static int pcm512x_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 const struct dev_pm_ops pcm512x_pm_ops = {
        SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
index d4c229f0233ff34c0e474a26b584606f414e6195..30e23470857949232092f3c6ef1c3e13abf46d25 100644 (file)
@@ -188,7 +188,7 @@ static unsigned int mic_bst_tlv[] = {
 static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = rt5631->dmic_used_flag;
@@ -199,7 +199,7 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
 static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
        rt5631->dmic_used_flag = ucontrol->value.integer.value[0];
index 68b4dd622b879364bc0ae26035695a8b7604d9fa..b0967df371e5872fad12492b3c6ceb5f2713eee6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * rt5640.c  --  RT5640 ALSA SoC audio codec driver
+ * rt5640.c  --  RT5640/RT5639 ALSA SoC audio codec driver
  *
  * Copyright 2011 Realtek Semiconductor Corp.
  * Author: Johnny Hsu <johnnyhsu@realtek.com>
@@ -18,6 +18,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
@@ -59,7 +60,7 @@ static struct reg_default init_list[] = {
 };
 #define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list)
 
-static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
+static const struct reg_default rt5640_reg[] = {
        { 0x00, 0x000e },
        { 0x01, 0xc8c8 },
        { 0x02, 0xc8c8 },
@@ -398,18 +399,13 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
                RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
        SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,
                RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
-       /* MONO Output Control */
-       SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT,
-                               RT5640_L_MUTE_SFT, 1, 1),
+
        /* DAC Digital Volume */
        SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,
                RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),
        SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
                        RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
                        175, 0, dac_vol_tlv),
-       SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
-                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
-                       175, 0, dac_vol_tlv),
        /* IN1/IN2 Control */
        SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,
                RT5640_BST_SFT1, 8, 0, bst_tlv),
@@ -441,6 +437,15 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
        SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),
 };
 
+static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
+       /* MONO Output Control */
+       SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT,
+               1, 1),
+
+       SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv),
+};
+
 /**
  * set_dmic_clk - Set parameter of dmic.
  *
@@ -480,14 +485,14 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        return idx;
 }
 
-static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
        unsigned int val;
 
        val = snd_soc_read(source->codec, RT5640_GLB_CLK);
        val &= RT5640_SCLK_SRC_MASK;
-       if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T)
+       if (val == RT5640_SCLK_SRC_PLL1)
                return 1;
        else
                return 0;
@@ -554,6 +559,20 @@ static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {
                        RT5640_M_ANC_DAC_R_SFT, 1, 1),
 };
 
+static const struct snd_kcontrol_new rt5639_sto_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_sto_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_R2_SFT, 1, 1),
+};
+
 static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {
        SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,
                        RT5640_M_DAC_L1_MONO_L_SFT, 1, 1),
@@ -676,6 +695,30 @@ static const struct snd_kcontrol_new rt5640_out_r_mix[] = {
                        RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
 };
 
+static const struct snd_kcontrol_new rt5639_out_l_mix[] = {
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_IN_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_RM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_out_r_mix[] = {
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_BST4_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_BST1_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_IN_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_RM_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
 static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {
        SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,
                        RT5640_M_DAC_R1_SPM_L_SFT, 1, 1),
@@ -707,6 +750,13 @@ static const struct snd_kcontrol_new rt5640_hpo_mix[] = {
                        RT5640_M_HPVOL_HM_SFT, 1, 1),
 };
 
+static const struct snd_kcontrol_new rt5639_hpo_mix[] = {
+       SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER,
+                       RT5640_M_DAC1_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER,
+                       RT5640_M_HPVOL_HM_SFT, 1, 1),
+};
+
 static const struct snd_kcontrol_new rt5640_lout_mix[] = {
        SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,
                        RT5640_M_DAC_L1_LM_SFT, 1, 1),
@@ -824,7 +874,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum,
                                  0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
 
 static const struct snd_kcontrol_new rt5640_dac_l2_mux =
-       SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
+       SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
 
 static const char * const rt5640_dac_r2_src[] = {
        "IF2",
@@ -859,7 +909,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum,
                                  rt5640_dai_iis_map_values);
 
 static const struct snd_kcontrol_new rt5640_dai_mux =
-       SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum);
+       SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum);
 
 /* SDI select */
 static const char * const rt5640_sdi_sel[] = {
@@ -872,54 +922,6 @@ static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
 static const struct snd_kcontrol_new rt5640_sdi_mux =
        SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
 
-static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
-                       RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK,
-                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA);
-               snd_soc_update_bits(codec, RT5640_DMIC,
-                       RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK |
-                       RT5640_DMIC_1_DP_MASK,
-                       RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING |
-                       RT5640_DMIC_1_DP_IN1P);
-               break;
-
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
-static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
-                       RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK,
-                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA);
-               snd_soc_update_bits(codec, RT5640_DMIC,
-                       RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK |
-                       RT5640_DMIC_2_DP_MASK,
-                       RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING |
-                       RT5640_DMIC_2_DP_IN1N);
-               break;
-
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
 static void hp_amp_power_on(struct snd_soc_codec *codec)
 {
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1054,12 +1056,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
 
        SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
                set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
-       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC,
-               RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event,
-               SND_SOC_DAPM_PRE_PMU),
-       SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC,
-               RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event,
-               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, RT5640_DMIC_1_EN_SFT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, RT5640_DMIC_2_EN_SFT, 0,
+               NULL, 0),
        /* Boost */
        SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,
                RT5640_PWR_BST1_BIT, 0, NULL, 0),
@@ -1146,26 +1146,15 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
-       /* Audio DSP */
-       SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
-       /* ANC */
-       SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
        /* Output Side */
        /* DAC mixer before sound effect  */
        SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
                rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),
        SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
                rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)),
-       /* DAC2 channel Mux */
-       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0,
-                               &rt5640_dac_l2_mux),
-       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0,
-                               &rt5640_dac_r2_mux),
+
        /* DAC Mixer */
-       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
-               rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
-       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
-               rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
        SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
                rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),
        SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
@@ -1177,21 +1166,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
        /* DACs */
        SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1,
                        RT5640_PWR_DAC_L1_BIT, 0),
-       SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1,
-                       RT5640_PWR_DAC_L2_BIT, 0),
        SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1,
                        RT5640_PWR_DAC_R1_BIT, 0),
-       SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1,
-                       RT5640_PWR_DAC_R2_BIT, 0),
+
        /* SPK/OUT Mixer */
        SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,
                0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
        SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,
                0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)),
-       SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
-               0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
-       SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
-               0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
        /* Ouput Volume */
        SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,
                RT5640_PWR_SV_L_BIT, 0, NULL, 0),
@@ -1210,16 +1192,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
                0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
        SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
                0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
-       SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
-               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
-       SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
-               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
        SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,
                rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)),
-       SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
-               rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
-       SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
-               RT5640_PWR_MA_BIT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,
                0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
@@ -1251,10 +1225,69 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("HPOR"),
        SND_SOC_DAPM_OUTPUT("LOUTL"),
        SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = {
+       /* Audio DSP */
+       SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* ANC */
+       SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* DAC2 channel Mux */
+       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_r2_mux),
+
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
+
+       SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R2_BIT,
+               0),
+       SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L2_BIT,
+               0),
+
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+               0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+               0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
+
+       SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+       SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+
+       SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
+               rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
+       SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
+               RT5640_PWR_MA_BIT, 0, NULL, 0),
+
        SND_SOC_DAPM_OUTPUT("MONOP"),
        SND_SOC_DAPM_OUTPUT("MONON"),
 };
 
+static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5639_sto_dac_l_mix, ARRAY_SIZE(rt5639_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)),
+
+       SND_SOC_DAPM_SUPPLY("DAC L2 Filter", RT5640_PWR_DIG1,
+               RT5640_PWR_DAC_L2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC R2 Filter", RT5640_PWR_DIG1,
+               RT5640_PWR_DAC_R2_BIT, 0, NULL, 0),
+
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+               0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+               0, rt5639_out_r_mix, ARRAY_SIZE(rt5639_out_r_mix)),
+
+       SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+               rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)),
+       SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+               rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)),
+};
+
 static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"IN1P", NULL, "LDO2"},
        {"IN2P", NULL, "LDO2"},
@@ -1323,22 +1356,22 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
        {"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
        {"Stereo ADC MIXL", NULL, "Stereo Filter"},
-       {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+       {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
        {"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
        {"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
        {"Stereo ADC MIXR", NULL, "Stereo Filter"},
-       {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+       {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
        {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
        {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
        {"Mono ADC MIXL", NULL, "Mono Left Filter"},
-       {"Mono Left Filter", NULL, "PLL1", check_sysclk1_source},
+       {"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
        {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
        {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
        {"Mono ADC MIXR", NULL, "Mono Right Filter"},
-       {"Mono Right Filter", NULL, "PLL1", check_sysclk1_source},
+       {"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
        {"IF2 ADC L", NULL, "Mono ADC MIXL"},
        {"IF2 ADC R", NULL, "Mono ADC MIXR"},
@@ -1396,71 +1429,38 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},
        {"DAC MIXR", "INF1 Switch", "IF1 DAC R"},
 
-       {"ANC", NULL, "Stereo ADC MIXL"},
-       {"ANC", NULL, "Stereo ADC MIXR"},
-
-       {"Audio DSP", NULL, "DAC MIXL"},
-       {"Audio DSP", NULL, "DAC MIXR"},
-
-       {"DAC L2 Mux", "IF2", "IF2 DAC L"},
-       {"DAC L2 Mux", "Base L/R", "Audio DSP"},
-
-       {"DAC R2 Mux", "IF2", "IF2 DAC R"},
-
        {"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
-       {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
-       {"Stereo DAC MIXL", "ANC Switch", "ANC"},
        {"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
-       {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
-       {"Stereo DAC MIXR", "ANC Switch", "ANC"},
 
        {"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
-       {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
-       {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
        {"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
-       {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
-       {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
 
        {"DIG MIXL", "DAC L1 Switch", "DAC MIXL"},
-       {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
        {"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
-       {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
 
        {"DAC L1", NULL, "Stereo DAC MIXL"},
-       {"DAC L1", NULL, "PLL1", check_sysclk1_source},
+       {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
        {"DAC R1", NULL, "Stereo DAC MIXR"},
-       {"DAC R1", NULL, "PLL1", check_sysclk1_source},
-       {"DAC L2", NULL, "Mono DAC MIXL"},
-       {"DAC L2", NULL, "PLL1", check_sysclk1_source},
-       {"DAC R2", NULL, "Mono DAC MIXR"},
-       {"DAC R2", NULL, "PLL1", check_sysclk1_source},
+       {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
 
        {"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
        {"SPK MIXL", "INL Switch", "INL VOL"},
        {"SPK MIXL", "DAC L1 Switch", "DAC L1"},
-       {"SPK MIXL", "DAC L2 Switch", "DAC L2"},
        {"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},
        {"SPK MIXR", "REC MIXR Switch", "RECMIXR"},
        {"SPK MIXR", "INR Switch", "INR VOL"},
        {"SPK MIXR", "DAC R1 Switch", "DAC R1"},
-       {"SPK MIXR", "DAC R2 Switch", "DAC R2"},
        {"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"},
 
-       {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
        {"OUT MIXL", "BST1 Switch", "BST1"},
        {"OUT MIXL", "INL Switch", "INL VOL"},
        {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
-       {"OUT MIXL", "DAC R2 Switch", "DAC R2"},
-       {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
        {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
 
-       {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
        {"OUT MIXR", "BST2 Switch", "BST2"},
        {"OUT MIXR", "BST1 Switch", "BST1"},
        {"OUT MIXR", "INR Switch", "INR VOL"},
        {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
-       {"OUT MIXR", "DAC L2 Switch", "DAC L2"},
-       {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
        {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
 
        {"SPKVOL L", NULL, "SPK MIXL"},
@@ -1479,11 +1479,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},
        {"SPOR MIX", "BST1 Switch", "BST1"},
 
-       {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
        {"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
        {"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
        {"HPO MIX L", NULL, "HP L Amp"},
-       {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
        {"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
        {"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
        {"HPO MIX R", NULL, "HP R Amp"},
@@ -1493,12 +1491,6 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
        {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
 
-       {"Mono MIX", "DAC R2 Switch", "DAC R2"},
-       {"Mono MIX", "DAC L2 Switch", "DAC L2"},
-       {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
-       {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
-       {"Mono MIX", "BST1 Switch", "BST1"},
-
        {"HP Amp", NULL, "HPO MIX L"},
        {"HP Amp", NULL, "HPO MIX R"},
 
@@ -1523,11 +1515,82 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"HPOR", NULL, "HP R Playback"},
        {"LOUTL", NULL, "LOUT MIX"},
        {"LOUTR", NULL, "LOUT MIX"},
+};
+
+static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
+       {"ANC", NULL, "Stereo ADC MIXL"},
+       {"ANC", NULL, "Stereo ADC MIXR"},
+
+       {"Audio DSP", NULL, "DAC MIXL"},
+       {"Audio DSP", NULL, "DAC MIXR"},
+
+       {"DAC L2 Mux", "IF2", "IF2 DAC L"},
+       {"DAC L2 Mux", "Base L/R", "Audio DSP"},
+
+       {"DAC R2 Mux", "IF2", "IF2 DAC R"},
+
+       {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Stereo DAC MIXL", "ANC Switch", "ANC"},
+       {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Stereo DAC MIXR", "ANC Switch", "ANC"},
+
+       {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+
+       {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+
+       {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+
+       {"DAC L2", NULL, "Mono DAC MIXL"},
+       {"DAC L2", NULL, "PLL1", is_sys_clk_from_pll},
+       {"DAC R2", NULL, "Mono DAC MIXR"},
+       {"DAC R2", NULL, "PLL1", is_sys_clk_from_pll},
+
+       {"SPK MIXL", "DAC L2 Switch", "DAC L2"},
+       {"SPK MIXR", "DAC R2 Switch", "DAC R2"},
+
+       {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
+       {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
+
+       {"OUT MIXL", "DAC R2 Switch", "DAC R2"},
+       {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+
+       {"OUT MIXR", "DAC L2 Switch", "DAC L2"},
+       {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+
+       {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
+       {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
+
+       {"Mono MIX", "DAC R2 Switch", "DAC R2"},
+       {"Mono MIX", "DAC L2 Switch", "DAC L2"},
+       {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
+       {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"Mono MIX", "BST1 Switch", "BST1"},
+
        {"MONOP", NULL, "Mono MIX"},
        {"MONON", NULL, "Mono MIX"},
        {"MONOP", NULL, "Improve MONO Amp Drv"},
 };
 
+static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = {
+       {"Stereo DAC MIXL", "DAC L2 Switch", "IF2 DAC L"},
+       {"Stereo DAC MIXR", "DAC R2 Switch", "IF2 DAC R"},
+
+       {"Mono DAC MIXL", "DAC L2 Switch", "IF2 DAC L"},
+       {"Mono DAC MIXL", "DAC R2 Switch", "IF2 DAC R"},
+
+       {"Mono DAC MIXR", "DAC R2 Switch", "IF2 DAC R"},
+       {"Mono DAC MIXR", "DAC L2 Switch", "IF2 DAC L"},
+
+       {"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"},
+       {"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"},
+
+       {"IF2 DAC L", NULL, "DAC L2 Filter"},
+       {"IF2 DAC R", NULL, "DAC R2 Filter"},
+};
+
 static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
 {
        int ret = 0, val;
@@ -1622,16 +1685,16 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
                                bclk_ms, pre_div, dai->id);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                val_len |= RT5640_I2S_DL_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                val_len |= RT5640_I2S_DL_24;
                break;
-       case SNDRV_PCM_FORMAT_S8:
+       case 8:
                val_len |= RT5640_I2S_DL_8;
                break;
        default:
@@ -1744,12 +1807,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
        case RT5640_SCLK_S_PLL1:
                reg_val |= RT5640_SCLK_SRC_PLL1;
                break;
-       case RT5640_SCLK_S_PLL1_TK:
-               reg_val |= RT5640_SCLK_SRC_PLL1T;
-               break;
-       case RT5640_SCLK_S_RCCLK:
-               reg_val |= RT5640_SCLK_SRC_RCCLK;
-               break;
        default:
                dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
                return -EINVAL;
@@ -1890,11 +1947,9 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt5640_set_bias_level(struct snd_soc_codec *codec,
                        enum snd_soc_bias_level level)
 {
-       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
                if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
-                       regcache_cache_only(rt5640->regmap, false);
                        snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
                                RT5640_PWR_VREF1 | RT5640_PWR_MB |
                                RT5640_PWR_BG | RT5640_PWR_VREF2,
@@ -1904,7 +1959,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
                        snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
                                RT5640_PWR_FV1 | RT5640_PWR_FV2,
                                RT5640_PWR_FV1 | RT5640_PWR_FV2);
-                       regcache_sync(rt5640->regmap);
                        snd_soc_update_bits(codec, RT5640_DUMMY1,
                                                0x0301, 0x0301);
                        snd_soc_update_bits(codec, RT5640_MICBIAS,
@@ -1938,13 +1992,35 @@ static int rt5640_probe(struct snd_soc_codec *codec)
 
        rt5640->codec = codec;
 
-       codec->dapm.idle_bias_off = 1;
        rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
        snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
        snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
 
+       switch (snd_soc_read(codec, RT5640_RESET) & RT5640_ID_MASK) {
+       case RT5640_ID_5640:
+       case RT5640_ID_5642:
+               snd_soc_add_codec_controls(codec,
+                       rt5640_specific_snd_controls,
+                       ARRAY_SIZE(rt5640_specific_snd_controls));
+               snd_soc_dapm_new_controls(&codec->dapm,
+                       rt5640_specific_dapm_widgets,
+                       ARRAY_SIZE(rt5640_specific_dapm_widgets));
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5640_specific_dapm_routes,
+                       ARRAY_SIZE(rt5640_specific_dapm_routes));
+               break;
+       case RT5640_ID_5639:
+               snd_soc_dapm_new_controls(&codec->dapm,
+                       rt5639_specific_dapm_widgets,
+                       ARRAY_SIZE(rt5639_specific_dapm_widgets));
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5639_specific_dapm_routes,
+                       ARRAY_SIZE(rt5639_specific_dapm_routes));
+               break;
+       }
+
        return 0;
 }
 
@@ -1979,6 +2055,9 @@ static int rt5640_resume(struct snd_soc_codec *codec)
                msleep(400);
        }
 
+       regcache_cache_only(rt5640->regmap, false);
+       regcache_sync(rt5640->regmap);
+
        return 0;
 }
 #else
@@ -2044,6 +2123,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
        .suspend = rt5640_suspend,
        .resume = rt5640_resume,
        .set_bias_level = rt5640_set_bias_level,
+       .idle_bias_off = true,
        .controls = rt5640_snd_controls,
        .num_controls = ARRAY_SIZE(rt5640_snd_controls),
        .dapm_widgets = rt5640_dapm_widgets,
@@ -2070,12 +2150,15 @@ static const struct regmap_config rt5640_regmap = {
 
 static const struct i2c_device_id rt5640_i2c_id[] = {
        { "rt5640", 0 },
+       { "rt5639", 0 },
+       { "rt5642", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
 
 #if defined(CONFIG_OF)
 static const struct of_device_id rt5640_of_match[] = {
+       { .compatible = "realtek,rt5639", },
        { .compatible = "realtek,rt5640", },
        {},
 };
@@ -2166,7 +2249,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
        }
 
        regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
-       if ((val != RT5640_DEVICE_ID)) {
+       if (val != RT5640_DEVICE_ID) {
                dev_err(&i2c->dev,
                        "Device with ID register %x is not rt5640/39\n", val);
                return -ENODEV;
@@ -2187,6 +2270,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
                                        RT5640_IN_DF2, RT5640_IN_DF2);
 
+       if (rt5640->pdata.dmic_en) {
+               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+               if (rt5640->pdata.dmic1_data_pin) {
+                       regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+                               RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+                       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                               RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+               }
+
+               if (rt5640->pdata.dmic2_data_pin) {
+                       regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+                               RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+                       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                               RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+               }
+       }
+
        rt5640->hp_mute = 1;
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
@@ -2219,6 +2321,6 @@ static struct i2c_driver rt5640_i2c_driver = {
 };
 module_i2c_driver(rt5640_i2c_driver);
 
-MODULE_DESCRIPTION("ASoC RT5640 driver");
+MODULE_DESCRIPTION("ASoC RT5640/RT5639 driver");
 MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
 MODULE_LICENSE("GPL v2");
index 5e8df25a13f34b9edc2e992a49d2a1e7a22d7e88..ded20595e9ae9df5974a8d6f5d2317dc15dcd24b 100644 (file)
 #define RT5640_R_VOL_MASK                      (0x3f)
 #define RT5640_R_VOL_SFT                       0
 
+/* SW Reset & Device ID (0x00) */
+#define RT5640_ID_MASK                         (0x3 << 1)
+#define RT5640_ID_5639                         (0x0 << 1)
+#define RT5640_ID_5640                         (0x1 << 1)
+#define RT5640_ID_5642                         (0x3 << 1)
+
+
 /* IN1 and IN2 Control (0x0d) */
 /* IN3 and IN4 Control (0x0e) */
 #define RT5640_BST_SFT1                                12
 #define RT5640_SCLK_SRC_SFT                    14
 #define RT5640_SCLK_SRC_MCLK                   (0x0 << 14)
 #define RT5640_SCLK_SRC_PLL1                   (0x1 << 14)
-#define RT5640_SCLK_SRC_PLL1T                  (0x2 << 14)
-#define RT5640_SCLK_SRC_RCCLK                  (0x3 << 14) /* 15MHz */
 #define RT5640_PLL1_SRC_MASK                   (0x3 << 12)
 #define RT5640_PLL1_SRC_SFT                    12
 #define RT5640_PLL1_SRC_MCLK                   (0x0 << 12)
@@ -2097,7 +2102,6 @@ struct rt5640_priv {
        int pll_in;
        int pll_out;
 
-       int dmic_en;
        bool hp_mute;
 };
 
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
new file mode 100644 (file)
index 0000000..f785b81
--- /dev/null
@@ -0,0 +1,1898 @@
+/*
+ * rt5651.c  --  RT5651 ALSA SoC audio codec driver
+ *
+ * Copyright 2014 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5651.h"
+
+#define RT5651_DEVICE_ID_VALUE 0x6281
+
+#define RT5651_PR_RANGE_BASE (0xff + 1)
+#define RT5651_PR_SPACING 0x100
+
+#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING))
+
+static const struct regmap_range_cfg rt5651_ranges[] = {
+       { .name = "PR", .range_min = RT5651_PR_BASE,
+         .range_max = RT5651_PR_BASE + 0xb4,
+         .selector_reg = RT5651_PRIV_INDEX,
+         .selector_mask = 0xff,
+         .selector_shift = 0x0,
+         .window_start = RT5651_PRIV_DATA,
+         .window_len = 0x1, },
+};
+
+static struct reg_default init_list[] = {
+       {RT5651_PR_BASE + 0x3d, 0x3e00},
+};
+
+static const struct reg_default rt5651_reg[] = {
+       { 0x00, 0x0000 },
+       { 0x02, 0xc8c8 },
+       { 0x03, 0xc8c8 },
+       { 0x05, 0x0000 },
+       { 0x0d, 0x0000 },
+       { 0x0e, 0x0000 },
+       { 0x0f, 0x0808 },
+       { 0x10, 0x0808 },
+       { 0x19, 0xafaf },
+       { 0x1a, 0xafaf },
+       { 0x1b, 0x0c00 },
+       { 0x1c, 0x2f2f },
+       { 0x1d, 0x2f2f },
+       { 0x1e, 0x0000 },
+       { 0x27, 0x7860 },
+       { 0x28, 0x7070 },
+       { 0x29, 0x8080 },
+       { 0x2a, 0x5252 },
+       { 0x2b, 0x5454 },
+       { 0x2f, 0x0000 },
+       { 0x30, 0x5000 },
+       { 0x3b, 0x0000 },
+       { 0x3c, 0x006f },
+       { 0x3d, 0x0000 },
+       { 0x3e, 0x006f },
+       { 0x45, 0x6000 },
+       { 0x4d, 0x0000 },
+       { 0x4e, 0x0000 },
+       { 0x4f, 0x0279 },
+       { 0x50, 0x0000 },
+       { 0x51, 0x0000 },
+       { 0x52, 0x0279 },
+       { 0x53, 0xf000 },
+       { 0x61, 0x0000 },
+       { 0x62, 0x0000 },
+       { 0x63, 0x00c0 },
+       { 0x64, 0x0000 },
+       { 0x65, 0x0000 },
+       { 0x66, 0x0000 },
+       { 0x70, 0x8000 },
+       { 0x71, 0x8000 },
+       { 0x73, 0x1104 },
+       { 0x74, 0x0c00 },
+       { 0x75, 0x1400 },
+       { 0x77, 0x0c00 },
+       { 0x78, 0x4000 },
+       { 0x79, 0x0123 },
+       { 0x80, 0x0000 },
+       { 0x81, 0x0000 },
+       { 0x82, 0x0000 },
+       { 0x83, 0x0800 },
+       { 0x84, 0x0000 },
+       { 0x85, 0x0008 },
+       { 0x89, 0x0000 },
+       { 0x8e, 0x0004 },
+       { 0x8f, 0x1100 },
+       { 0x90, 0x0000 },
+       { 0x93, 0x2000 },
+       { 0x94, 0x0200 },
+       { 0xb0, 0x2080 },
+       { 0xb1, 0x0000 },
+       { 0xb4, 0x2206 },
+       { 0xb5, 0x1f00 },
+       { 0xb6, 0x0000 },
+       { 0xbb, 0x0000 },
+       { 0xbc, 0x0000 },
+       { 0xbd, 0x0000 },
+       { 0xbe, 0x0000 },
+       { 0xbf, 0x0000 },
+       { 0xc0, 0x0400 },
+       { 0xc1, 0x0000 },
+       { 0xc2, 0x0000 },
+       { 0xcf, 0x0013 },
+       { 0xd0, 0x0680 },
+       { 0xd1, 0x1c17 },
+       { 0xd3, 0xb320 },
+       { 0xd9, 0x0809 },
+       { 0xfa, 0x0010 },
+       { 0xfe, 0x10ec },
+       { 0xff, 0x6281 },
+};
+
+static bool rt5651_volatile_register(struct device *dev,  unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) {
+               if ((reg >= rt5651_ranges[i].window_start &&
+                    reg <= rt5651_ranges[i].window_start +
+                    rt5651_ranges[i].window_len) ||
+                   (reg >= rt5651_ranges[i].range_min &&
+                    reg <= rt5651_ranges[i].range_max)) {
+                       return true;
+               }
+       }
+
+       switch (reg) {
+       case RT5651_RESET:
+       case RT5651_PRIV_DATA:
+       case RT5651_EQ_CTRL1:
+       case RT5651_ALC_1:
+       case RT5651_IRQ_CTRL2:
+       case RT5651_INT_IRQ_ST:
+       case RT5651_PGM_REG_ARR1:
+       case RT5651_PGM_REG_ARR3:
+       case RT5651_VENDOR_ID:
+       case RT5651_DEVICE_ID:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5651_readable_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) {
+               if ((reg >= rt5651_ranges[i].window_start &&
+                    reg <= rt5651_ranges[i].window_start +
+                    rt5651_ranges[i].window_len) ||
+                   (reg >= rt5651_ranges[i].range_min &&
+                    reg <= rt5651_ranges[i].range_max)) {
+                       return true;
+               }
+       }
+
+       switch (reg) {
+       case RT5651_RESET:
+       case RT5651_VERSION_ID:
+       case RT5651_VENDOR_ID:
+       case RT5651_DEVICE_ID:
+       case RT5651_HP_VOL:
+       case RT5651_LOUT_CTRL1:
+       case RT5651_LOUT_CTRL2:
+       case RT5651_IN1_IN2:
+       case RT5651_IN3:
+       case RT5651_INL1_INR1_VOL:
+       case RT5651_INL2_INR2_VOL:
+       case RT5651_DAC1_DIG_VOL:
+       case RT5651_DAC2_DIG_VOL:
+       case RT5651_DAC2_CTRL:
+       case RT5651_ADC_DIG_VOL:
+       case RT5651_ADC_DATA:
+       case RT5651_ADC_BST_VOL:
+       case RT5651_STO1_ADC_MIXER:
+       case RT5651_STO2_ADC_MIXER:
+       case RT5651_AD_DA_MIXER:
+       case RT5651_STO_DAC_MIXER:
+       case RT5651_DD_MIXER:
+       case RT5651_DIG_INF_DATA:
+       case RT5651_PDM_CTL:
+       case RT5651_REC_L1_MIXER:
+       case RT5651_REC_L2_MIXER:
+       case RT5651_REC_R1_MIXER:
+       case RT5651_REC_R2_MIXER:
+       case RT5651_HPO_MIXER:
+       case RT5651_OUT_L1_MIXER:
+       case RT5651_OUT_L2_MIXER:
+       case RT5651_OUT_L3_MIXER:
+       case RT5651_OUT_R1_MIXER:
+       case RT5651_OUT_R2_MIXER:
+       case RT5651_OUT_R3_MIXER:
+       case RT5651_LOUT_MIXER:
+       case RT5651_PWR_DIG1:
+       case RT5651_PWR_DIG2:
+       case RT5651_PWR_ANLG1:
+       case RT5651_PWR_ANLG2:
+       case RT5651_PWR_MIXER:
+       case RT5651_PWR_VOL:
+       case RT5651_PRIV_INDEX:
+       case RT5651_PRIV_DATA:
+       case RT5651_I2S1_SDP:
+       case RT5651_I2S2_SDP:
+       case RT5651_ADDA_CLK1:
+       case RT5651_ADDA_CLK2:
+       case RT5651_DMIC:
+       case RT5651_TDM_CTL_1:
+       case RT5651_TDM_CTL_2:
+       case RT5651_TDM_CTL_3:
+       case RT5651_GLB_CLK:
+       case RT5651_PLL_CTRL1:
+       case RT5651_PLL_CTRL2:
+       case RT5651_PLL_MODE_1:
+       case RT5651_PLL_MODE_2:
+       case RT5651_PLL_MODE_3:
+       case RT5651_PLL_MODE_4:
+       case RT5651_PLL_MODE_5:
+       case RT5651_PLL_MODE_6:
+       case RT5651_PLL_MODE_7:
+       case RT5651_DEPOP_M1:
+       case RT5651_DEPOP_M2:
+       case RT5651_DEPOP_M3:
+       case RT5651_CHARGE_PUMP:
+       case RT5651_MICBIAS:
+       case RT5651_A_JD_CTL1:
+       case RT5651_EQ_CTRL1:
+       case RT5651_EQ_CTRL2:
+       case RT5651_ALC_1:
+       case RT5651_ALC_2:
+       case RT5651_ALC_3:
+       case RT5651_JD_CTRL1:
+       case RT5651_JD_CTRL2:
+       case RT5651_IRQ_CTRL1:
+       case RT5651_IRQ_CTRL2:
+       case RT5651_INT_IRQ_ST:
+       case RT5651_GPIO_CTRL1:
+       case RT5651_GPIO_CTRL2:
+       case RT5651_GPIO_CTRL3:
+       case RT5651_PGM_REG_ARR1:
+       case RT5651_PGM_REG_ARR2:
+       case RT5651_PGM_REG_ARR3:
+       case RT5651_PGM_REG_ARR4:
+       case RT5651_PGM_REG_ARR5:
+       case RT5651_SCB_FUNC:
+       case RT5651_SCB_CTRL:
+       case RT5651_BASE_BACK:
+       case RT5651_MP3_PLUS1:
+       case RT5651_MP3_PLUS2:
+       case RT5651_ADJ_HPF_CTRL1:
+       case RT5651_ADJ_HPF_CTRL2:
+       case RT5651_HP_CALIB_AMP_DET:
+       case RT5651_HP_CALIB2:
+       case RT5651_SV_ZCD1:
+       case RT5651_SV_ZCD2:
+       case RT5651_D_MISC:
+       case RT5651_DUMMY2:
+       case RT5651_DUMMY3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+       6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+       8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+};
+
+/* Interface data select */
+static const char * const rt5651_data_select[] = {
+       "Normal", "Swap", "left copy to right", "right copy to left"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_dac_enum, RT5651_DIG_INF_DATA,
+                               RT5651_IF2_DAC_SEL_SFT, rt5651_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_enum, RT5651_DIG_INF_DATA,
+                               RT5651_IF2_ADC_SEL_SFT, rt5651_data_select);
+
+static const struct snd_kcontrol_new rt5651_snd_controls[] = {
+       /* Headphone Output Volume */
+       SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL,
+               RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* OUTPUT Control */
+       SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1,
+               RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+       /* DAC Digital Volume */
+       SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL,
+               RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1),
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL,
+                       RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
+                       RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       /* IN1/IN2 Control */
+       SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
+               RT5651_BST_SFT1, 8, 0, bst_tlv),
+       SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
+               RT5651_BST_SFT2, 8, 0, bst_tlv),
+       /* INL/INR Volume Control */
+       SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
+                       RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
+                       31, 1, in_vol_tlv),
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL,
+               RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL,
+                       RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+       SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA,
+                       RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL,
+                       RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT,
+                       3, 0, adc_bst_tlv),
+
+       /* ASRC */
+       SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1,
+               RT5651_STO1_T_SFT, 1, 0),
+       SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1,
+               RT5651_STO2_T_SFT, 1, 0),
+       SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1,
+               RT5651_DMIC_1_M_SFT, 1, 0),
+
+       SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum),
+       SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+       int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
+       int i, rate, red, bound, temp;
+
+       rate = rt5651->sysclk;
+       red = 3000000 * 12;
+       for (i = 0; i < ARRAY_SIZE(div); i++) {
+               bound = div[i] * 3000000;
+               if (rate > bound)
+                       continue;
+               temp = bound - rate;
+               if (temp < red) {
+                       red = temp;
+                       idx = i;
+               }
+       }
+       if (idx < 0)
+               dev_err(codec->dev, "Failed to set DMIC clock\n");
+       else
+               snd_soc_update_bits(codec, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
+                                       idx << RT5651_DMIC_CLK_SFT);
+
+       return idx;
+}
+
+static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+
+       val = snd_soc_read(source->codec, RT5651_GLB_CLK);
+       val &= RT5651_SCLK_SRC_MASK;
+       if (val == RT5651_SCLK_SRC_PLL1)
+               return 1;
+       else
+               return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
+                       RT5651_M_STO1_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,
+                       RT5651_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
+                       RT5651_M_STO1_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,
+                       RT5651_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER,
+                       RT5651_M_STO2_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER,
+                       RT5651_M_STO2_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER,
+                       RT5651_M_STO2_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER,
+                       RT5651_M_STO2_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER,
+                       RT5651_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER,
+                       RT5651_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER,
+                       RT5651_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER,
+                       RT5651_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER,
+                       RT5651_M_DAC_L1_MIXL_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_STO_DAC_MIXER,
+                       RT5651_M_DAC_L2_MIXL_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER,
+                       RT5651_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER,
+                       RT5651_M_DAC_R1_MIXR_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_STO_DAC_MIXER,
+                       RT5651_M_DAC_R2_MIXR_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER,
+                       RT5651_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dd_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_DD_MIXER,
+                       RT5651_M_STO_DD_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,
+                       RT5651_M_STO_DD_L2_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,
+                       RT5651_M_STO_DD_R2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dd_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_DD_MIXER,
+                       RT5651_M_STO_DD_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,
+                       RT5651_M_STO_DD_R2_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,
+                       RT5651_M_STO_DD_L2_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5651_rec_l_mix[] = {
+       SOC_DAPM_SINGLE("INL1 Switch", RT5651_REC_L2_MIXER,
+                       RT5651_M_IN1_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_L2_MIXER,
+                       RT5651_M_BST3_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_L2_MIXER,
+                       RT5651_M_BST2_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_L2_MIXER,
+                       RT5651_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_rec_r_mix[] = {
+       SOC_DAPM_SINGLE("INR1 Switch", RT5651_REC_R2_MIXER,
+                       RT5651_M_IN1_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_R2_MIXER,
+                       RT5651_M_BST3_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_R2_MIXER,
+                       RT5651_M_BST2_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_R2_MIXER,
+                       RT5651_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5651_out_l_mix[] = {
+       SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_L3_MIXER,
+                       RT5651_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_L3_MIXER,
+                       RT5651_M_BST2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL1 Switch", RT5651_OUT_L3_MIXER,
+                       RT5651_M_IN1_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5651_OUT_L3_MIXER,
+                       RT5651_M_RM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_OUT_L3_MIXER,
+                       RT5651_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_out_r_mix[] = {
+       SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_R3_MIXER,
+                       RT5651_M_BST2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_R3_MIXER,
+                       RT5651_M_BST1_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR1 Switch", RT5651_OUT_R3_MIXER,
+                       RT5651_M_IN1_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5651_OUT_R3_MIXER,
+                       RT5651_M_RM_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_OUT_R3_MIXER,
+                       RT5651_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_hpo_mix[] = {
+       SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5651_HPO_MIXER,
+                       RT5651_M_DAC1_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5651_HPO_MIXER,
+                       RT5651_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_lout_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_LOUT_MIXER,
+                       RT5651_M_DAC_L1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_LOUT_MIXER,
+                       RT5651_M_DAC_R1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5651_LOUT_MIXER,
+                       RT5651_M_OV_L_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5651_LOUT_MIXER,
+                       RT5651_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new outvol_l_control =
+       SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1,
+                       RT5651_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_control =
+       SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1,
+                       RT5651_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_mute_control =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1,
+                                   RT5651_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_mute_control =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1,
+                                   RT5651_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpovol_l_control =
+       SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL,
+                       RT5651_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpovol_r_control =
+       SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL,
+                       RT5651_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_mute_control =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
+                                   RT5651_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_mute_control =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
+                                   RT5651_R_MUTE_SFT, 1, 1);
+
+/* INL/R source */
+static const char * const rt5651_inl_src[] = {"IN2P", "HPOVOLLP"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_inl_enum, RT5651_INL1_INR1_VOL,
+       RT5651_INL_SEL_SFT, rt5651_inl_src);
+
+static const struct snd_kcontrol_new rt5651_inl1_mux =
+       SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum);
+
+static const char * const rt5651_inr1_src[] = {"IN2N", "HPOVOLRP"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_inr1_enum, RT5651_INL1_INR1_VOL,
+       RT5651_INR_SEL_SFT, rt5651_inr1_src);
+
+static const struct snd_kcontrol_new rt5651_inr1_mux =
+       SOC_DAPM_ENUM("INR1 source", rt5651_inr1_enum);
+
+static const char * const rt5651_inl2_src[] = {"IN3P", "OUTVOLLP"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_inl2_enum, RT5651_INL2_INR2_VOL,
+       RT5651_INL_SEL_SFT, rt5651_inl2_src);
+
+static const struct snd_kcontrol_new rt5651_inl2_mux =
+       SOC_DAPM_ENUM("INL2 source", rt5651_inl2_enum);
+
+static const char * const rt5651_inr2_src[] = {"IN3N", "OUTVOLRP"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_inr2_enum, RT5651_INL2_INR2_VOL,
+       RT5651_INR_SEL_SFT, rt5651_inr2_src);
+
+static const struct snd_kcontrol_new rt5651_inr2_mux =
+       SOC_DAPM_ENUM("INR2 source", rt5651_inr2_enum);
+
+
+/* Stereo ADC source */
+static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_stereo1_adc1_enum, RT5651_STO1_ADC_MIXER,
+       RT5651_STO1_ADC_1_SRC_SFT, rt5651_stereo1_adc1_src);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_l1_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5651_stereo1_adc1_enum);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r1_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5651_stereo1_adc1_enum);
+
+static const char * const rt5651_stereo1_adc2_src[] = {"DMIC", "DD MIX"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_stereo1_adc2_enum, RT5651_STO1_ADC_MIXER,
+       RT5651_STO1_ADC_2_SRC_SFT, rt5651_stereo1_adc2_src);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_l2_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5651_stereo1_adc2_enum);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r2_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5651_stereo1_adc2_enum);
+
+/* Mono ADC source */
+static const char * const rt5651_sto2_adc_l1_src[] = {"DD MIXL", "ADCL"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_sto2_adc_l1_enum, RT5651_STO1_ADC_MIXER,
+       RT5651_STO2_ADC_L1_SRC_SFT, rt5651_sto2_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l1_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC1 left source", rt5651_sto2_adc_l1_enum);
+
+static const char * const rt5651_sto2_adc_l2_src[] = {"DMIC L", "DD MIXL"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_sto2_adc_l2_enum, RT5651_STO1_ADC_MIXER,
+       RT5651_STO2_ADC_L2_SRC_SFT, rt5651_sto2_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l2_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC2 left source", rt5651_sto2_adc_l2_enum);
+
+static const char * const rt5651_sto2_adc_r1_src[] = {"DD MIXR", "ADCR"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_sto2_adc_r1_enum, RT5651_STO1_ADC_MIXER,
+       RT5651_STO2_ADC_R1_SRC_SFT, rt5651_sto2_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r1_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC1 right source", rt5651_sto2_adc_r1_enum);
+
+static const char * const rt5651_sto2_adc_r2_src[] = {"DMIC R", "DD MIXR"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_sto2_adc_r2_enum, RT5651_STO1_ADC_MIXER,
+       RT5651_STO2_ADC_R2_SRC_SFT, rt5651_sto2_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r2_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC2 right source", rt5651_sto2_adc_r2_enum);
+
+/* DAC2 channel source */
+
+static const char * const rt5651_dac_src[] = {"IF1", "IF2"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_dac_l2_enum, RT5651_DAC2_CTRL,
+                               RT5651_SEL_DAC_L2_SFT, rt5651_dac_src);
+
+static const struct snd_kcontrol_new rt5651_dac_l2_mux =
+       SOC_DAPM_ENUM("DAC2 left channel source", rt5651_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_dac_r2_enum, RT5651_DAC2_CTRL,
+       RT5651_SEL_DAC_R2_SFT, rt5651_dac_src);
+
+static const struct snd_kcontrol_new rt5651_dac_r2_mux =
+       SOC_DAPM_ENUM("DAC2 right channel source", rt5651_dac_r2_enum);
+
+/* IF2_ADC channel source */
+
+static const char * const rt5651_adc_src[] = {"IF1 ADC1", "IF1 ADC2"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_src_enum, RT5651_DIG_INF_DATA,
+                               RT5651_IF2_ADC_SRC_SFT, rt5651_adc_src);
+
+static const struct snd_kcontrol_new rt5651_if2_adc_src_mux =
+       SOC_DAPM_ENUM("IF2 ADC channel source", rt5651_if2_adc_src_enum);
+
+/* PDM select */
+static const char * const rt5651_pdm_sel[] = {"DD MIX", "Stereo DAC MIX"};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_pdm_l_sel_enum, RT5651_PDM_CTL,
+       RT5651_PDM_L_SEL_SFT, rt5651_pdm_sel);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5651_pdm_r_sel_enum, RT5651_PDM_CTL,
+       RT5651_PDM_R_SEL_SFT, rt5651_pdm_sel);
+
+static const struct snd_kcontrol_new rt5651_pdm_l_mux =
+       SOC_DAPM_ENUM("PDM L select", rt5651_pdm_l_sel_enum);
+
+static const struct snd_kcontrol_new rt5651_pdm_r_mux =
+       SOC_DAPM_ENUM("PDM R select", rt5651_pdm_r_sel_enum);
+
+static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* depop parameters */
+               regmap_update_bits(rt5651->regmap, RT5651_PR_BASE +
+                       RT5651_CHPUMP_INT_REG1, 0x0700, 0x0200);
+               regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2,
+                       RT5651_DEPOP_MASK, RT5651_DEPOP_MAN);
+               regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1,
+                       RT5651_HP_CP_MASK | RT5651_HP_SG_MASK |
+                       RT5651_HP_CB_MASK, RT5651_HP_CP_PU |
+                       RT5651_HP_SG_DIS | RT5651_HP_CB_PU);
+               regmap_write(rt5651->regmap, RT5651_PR_BASE +
+                               RT5651_HP_DCC_INT1, 0x9f00);
+               /* headphone amp power on */
+               regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+                       RT5651_PWR_FV1 | RT5651_PWR_FV2, 0);
+               regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+                       RT5651_PWR_HA,
+                       RT5651_PWR_HA);
+               usleep_range(10000, 15000);
+               regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+                       RT5651_PWR_FV1 | RT5651_PWR_FV2 ,
+                       RT5651_PWR_FV1 | RT5651_PWR_FV2);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* headphone unmute sequence */
+               regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2,
+                       RT5651_DEPOP_MASK | RT5651_DIG_DP_MASK,
+                       RT5651_DEPOP_AUTO | RT5651_DIG_DP_EN);
+               regmap_update_bits(rt5651->regmap, RT5651_CHARGE_PUMP,
+                       RT5651_PM_HP_MASK, RT5651_PM_HP_HV);
+
+               regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M3,
+                       RT5651_CP_FQ1_MASK | RT5651_CP_FQ2_MASK |
+                       RT5651_CP_FQ3_MASK,
+                       (RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ1_SFT) |
+                       (RT5651_CP_FQ_12_KHZ << RT5651_CP_FQ2_SFT) |
+                       (RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ3_SFT));
+
+               regmap_write(rt5651->regmap, RT5651_PR_BASE +
+                       RT5651_MAMP_INT_REG2, 0x1c00);
+               regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1,
+                       RT5651_HP_CP_MASK | RT5651_HP_SG_MASK,
+                       RT5651_HP_CP_PD | RT5651_HP_SG_EN);
+               regmap_update_bits(rt5651->regmap, RT5651_PR_BASE +
+                       RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400);
+               rt5651->hp_mute = 0;
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               rt5651->hp_mute = 1;
+               usleep_range(70000, 75000);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (!rt5651->hp_mute)
+                       usleep_range(80000, 85000);
+
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+                       RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+                       RT5651_PWR_BST1_OP2, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+                       RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+                       RT5651_PWR_BST2_OP2, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+                       RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+                       RT5651_PWR_BST3_OP2, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5651_PLL_MODE_2,
+                             15, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5651_PLL_MODE_2,
+                             14, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("STO1 DAC ASRC", 1, RT5651_PLL_MODE_2,
+                             13, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("STO2 DAC ASRC", 1, RT5651_PLL_MODE_2,
+                             12, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2,
+                             11, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2,
+                       RT5651_PWR_PLL_BIT, 0, NULL, 0),
+       /* Input Side */
+       /* micbias */
+       SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1,
+                       RT5651_PWR_LDO_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2,
+                       RT5651_PWR_MB1_BIT, 0),
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("MIC3"),
+
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN2P"),
+       SND_SOC_DAPM_INPUT("IN2N"),
+       SND_SOC_DAPM_INPUT("IN3P"),
+       SND_SOC_DAPM_INPUT("DMIC L1"),
+       SND_SOC_DAPM_INPUT("DMIC R1"),
+       SND_SOC_DAPM_SUPPLY("DMIC CLK", RT5651_DMIC, RT5651_DMIC_1_EN_SFT,
+                           0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+       /* Boost */
+       SND_SOC_DAPM_PGA_E("BST1", RT5651_PWR_ANLG2,
+               RT5651_PWR_BST1_BIT, 0, NULL, 0, rt5651_bst1_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_E("BST2", RT5651_PWR_ANLG2,
+               RT5651_PWR_BST2_BIT, 0, NULL, 0, rt5651_bst2_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_E("BST3", RT5651_PWR_ANLG2,
+               RT5651_PWR_BST3_BIT, 0, NULL, 0, rt5651_bst3_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       /* Input Volume */
+       SND_SOC_DAPM_PGA("INL1 VOL", RT5651_PWR_VOL,
+                        RT5651_PWR_IN1_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR1 VOL", RT5651_PWR_VOL,
+                        RT5651_PWR_IN1_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INL2 VOL", RT5651_PWR_VOL,
+                        RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL,
+                        RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
+       /* IN Mux */
+       SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux),
+       SND_SOC_DAPM_MUX("INR1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr1_mux),
+       SND_SOC_DAPM_MUX("INL2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl2_mux),
+       SND_SOC_DAPM_MUX("INR2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr2_mux),
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0,
+                          rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIXR", RT5651_PWR_MIXER, RT5651_PWR_RM_R_BIT, 0,
+                          rt5651_rec_r_mix, ARRAY_SIZE(rt5651_rec_r_mix)),
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("ADC L Power", RT5651_PWR_DIG1,
+                           RT5651_PWR_ADC_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC R Power", RT5651_PWR_DIG1,
+                           RT5651_PWR_ADC_R_BIT, 0, NULL, 0),
+       /* ADC Mux */
+       SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto1_adc_l2_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto1_adc_r2_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto1_adc_l1_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto1_adc_r1_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto2_adc_l2_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto2_adc_l1_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto2_adc_r1_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+                        &rt5651_sto2_adc_r2_mux),
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("Stereo1 Filter", RT5651_PWR_DIG2,
+                           RT5651_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Stereo2 Filter", RT5651_PWR_DIG2,
+                           RT5651_PWR_ADC_STO2_F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+                          rt5651_sto1_adc_l_mix,
+                          ARRAY_SIZE(rt5651_sto1_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+                          rt5651_sto1_adc_r_mix,
+                          ARRAY_SIZE(rt5651_sto1_adc_r_mix)),
+       SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+                          rt5651_sto2_adc_l_mix,
+                          ARRAY_SIZE(rt5651_sto2_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+                          rt5651_sto2_adc_r_mix,
+                          ARRAY_SIZE(rt5651_sto2_adc_r_mix)),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1", RT5651_PWR_DIG1,
+                           RT5651_PWR_I2S1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2", RT5651_PWR_DIG1,
+                           RT5651_PWR_I2S2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("IF2 ADC", SND_SOC_NOPM, 0, 0,
+                        &rt5651_if2_adc_src_mux),
+
+       /* Digital Interface Select */
+
+       SND_SOC_DAPM_MUX("PDM L Mux", RT5651_PDM_CTL,
+                        RT5651_M_PDM_L_SFT, 1, &rt5651_pdm_l_mux),
+       SND_SOC_DAPM_MUX("PDM R Mux", RT5651_PDM_CTL,
+                        RT5651_M_PDM_R_SFT, 1, &rt5651_pdm_r_mux),
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Audio DSP */
+       SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+                          rt5651_dac_l_mix, ARRAY_SIZE(rt5651_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+                          rt5651_dac_r_mix, ARRAY_SIZE(rt5651_dac_r_mix)),
+
+       /* DAC2 channel Mux */
+       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_r2_mux),
+       SND_SOC_DAPM_PGA("DAC L2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DAC R2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5651_PWR_DIG2,
+                           RT5651_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Stero2 DAC Power", RT5651_PWR_DIG2,
+                           RT5651_PWR_DAC_STO2_F_BIT, 0, NULL, 0),
+       /* DAC Mixer */
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+                          rt5651_sto_dac_l_mix,
+                          ARRAY_SIZE(rt5651_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+                          rt5651_sto_dac_r_mix,
+                          ARRAY_SIZE(rt5651_sto_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("DD MIXL", SND_SOC_NOPM, 0, 0,
+                          rt5651_dd_dac_l_mix,
+                          ARRAY_SIZE(rt5651_dd_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DD MIXR", SND_SOC_NOPM, 0, 0,
+                          rt5651_dd_dac_r_mix,
+                          ARRAY_SIZE(rt5651_dd_dac_r_mix)),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5651_PWR_DIG1,
+                           RT5651_PWR_DAC_L1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5651_PWR_DIG1,
+                           RT5651_PWR_DAC_R1_BIT, 0, NULL, 0),
+       /* OUT Mixer */
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5651_PWR_MIXER, RT5651_PWR_OM_L_BIT,
+                          0, rt5651_out_l_mix, ARRAY_SIZE(rt5651_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5651_PWR_MIXER, RT5651_PWR_OM_R_BIT,
+                          0, rt5651_out_r_mix, ARRAY_SIZE(rt5651_out_r_mix)),
+       /* Ouput Volume */
+       SND_SOC_DAPM_SWITCH("OUTVOL L", RT5651_PWR_VOL,
+                           RT5651_PWR_OV_L_BIT, 0, &outvol_l_control),
+       SND_SOC_DAPM_SWITCH("OUTVOL R", RT5651_PWR_VOL,
+                           RT5651_PWR_OV_R_BIT, 0, &outvol_r_control),
+       SND_SOC_DAPM_SWITCH("HPOVOL L", RT5651_PWR_VOL,
+                           RT5651_PWR_HV_L_BIT, 0, &hpovol_l_control),
+       SND_SOC_DAPM_SWITCH("HPOVOL R", RT5651_PWR_VOL,
+                           RT5651_PWR_HV_R_BIT, 0, &hpovol_r_control),
+       SND_SOC_DAPM_PGA("INL1", RT5651_PWR_VOL,
+                        RT5651_PWR_IN1_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR1", RT5651_PWR_VOL,
+                        RT5651_PWR_IN1_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INL2", RT5651_PWR_VOL,
+                        RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR2", RT5651_PWR_VOL,
+                        RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
+       /* HPO/LOUT/Mono Mixer */
+       SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0,
+                          rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)),
+       SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0,
+                          rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)),
+       SND_SOC_DAPM_SUPPLY("HP L Amp", RT5651_PWR_ANLG1,
+                           RT5651_PWR_HP_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("HP R Amp", RT5651_PWR_ANLG1,
+                           RT5651_PWR_HP_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("LOUT MIX", RT5651_PWR_ANLG1, RT5651_PWR_LM_BIT, 0,
+                          rt5651_lout_mix, ARRAY_SIZE(rt5651_lout_mix)),
+
+       SND_SOC_DAPM_SUPPLY("Amp Power", RT5651_PWR_ANLG1,
+                           RT5651_PWR_HA_BIT, 0, rt5651_amp_power_event,
+                           SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5651_hp_event,
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+                           &hpo_l_mute_control),
+       SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+                           &hpo_r_mute_control),
+       SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+                           &lout_l_mute_control),
+       SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+                           &lout_r_mute_control),
+       SND_SOC_DAPM_POST("HP Post", rt5651_hp_post_event),
+
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+       SND_SOC_DAPM_OUTPUT("PDML"),
+       SND_SOC_DAPM_OUTPUT("PDMR"),
+};
+
+static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
+       {"Stero1 DAC Power", NULL, "STO1 DAC ASRC"},
+       {"Stero2 DAC Power", NULL, "STO2 DAC ASRC"},
+       {"I2S1", NULL, "I2S1 ASRC"},
+       {"I2S2", NULL, "I2S2 ASRC"},
+
+       {"IN1P", NULL, "LDO"},
+       {"IN2P", NULL, "LDO"},
+       {"IN3P", NULL, "LDO"},
+
+       {"IN1P", NULL, "MIC1"},
+       {"IN2P", NULL, "MIC2"},
+       {"IN2N", NULL, "MIC2"},
+       {"IN3P", NULL, "MIC3"},
+
+       {"BST1", NULL, "IN1P"},
+       {"BST2", NULL, "IN2P"},
+       {"BST2", NULL, "IN2N"},
+       {"BST3", NULL, "IN3P"},
+
+       {"INL1 VOL", NULL, "IN2P"},
+       {"INR1 VOL", NULL, "IN2N"},
+
+       {"RECMIXL", "INL1 Switch", "INL1 VOL"},
+       {"RECMIXL", "BST3 Switch", "BST3"},
+       {"RECMIXL", "BST2 Switch", "BST2"},
+       {"RECMIXL", "BST1 Switch", "BST1"},
+
+       {"RECMIXR", "INR1 Switch", "INR1 VOL"},
+       {"RECMIXR", "BST3 Switch", "BST3"},
+       {"RECMIXR", "BST2 Switch", "BST2"},
+       {"RECMIXR", "BST1 Switch", "BST1"},
+
+       {"ADC L", NULL, "RECMIXL"},
+       {"ADC L", NULL, "ADC L Power"},
+       {"ADC R", NULL, "RECMIXR"},
+       {"ADC R", NULL, "ADC R Power"},
+
+       {"DMIC L1", NULL, "DMIC CLK"},
+       {"DMIC R1", NULL, "DMIC CLK"},
+
+       {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+       {"Stereo1 ADC L2 Mux", "DD MIX", "DD MIXL"},
+       {"Stereo1 ADC L1 Mux", "ADC", "ADC L"},
+       {"Stereo1 ADC L1 Mux", "DD MIX", "DD MIXL"},
+
+       {"Stereo1 ADC R1 Mux", "ADC", "ADC R"},
+       {"Stereo1 ADC R1 Mux", "DD MIX", "DD MIXR"},
+       {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+       {"Stereo1 ADC R2 Mux", "DD MIX", "DD MIXR"},
+
+       {"Stereo2 ADC L2 Mux", "DMIC L", "DMIC L1"},
+       {"Stereo2 ADC L2 Mux", "DD MIXL", "DD MIXL"},
+       {"Stereo2 ADC L1 Mux", "DD MIXL", "DD MIXL"},
+       {"Stereo2 ADC L1 Mux", "ADCL", "ADC L"},
+
+       {"Stereo2 ADC R1 Mux", "DD MIXR", "DD MIXR"},
+       {"Stereo2 ADC R1 Mux", "ADCR", "ADC R"},
+       {"Stereo2 ADC R2 Mux", "DMIC R", "DMIC R1"},
+       {"Stereo2 ADC R2 Mux", "DD MIXR", "DD MIXR"},
+
+       {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+       {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+       {"Stereo1 ADC MIXL", NULL, "Stereo1 Filter"},
+       {"Stereo1 Filter", NULL, "PLL1", is_sysclk_from_pll},
+       {"Stereo1 Filter", NULL, "ADC ASRC"},
+
+       {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+       {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+       {"Stereo1 ADC MIXR", NULL, "Stereo1 Filter"},
+
+       {"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"},
+       {"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"},
+       {"Stereo2 ADC MIXL", NULL, "Stereo2 Filter"},
+       {"Stereo2 Filter", NULL, "PLL1", is_sysclk_from_pll},
+       {"Stereo2 Filter", NULL, "ADC ASRC"},
+
+       {"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"},
+       {"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"},
+       {"Stereo2 ADC MIXR", NULL, "Stereo2 Filter"},
+
+       {"IF1 ADC2", NULL, "Stereo2 ADC MIXL"},
+       {"IF1 ADC2", NULL, "Stereo2 ADC MIXR"},
+       {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+       {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+
+       {"IF1 ADC1", NULL, "I2S1"},
+
+       {"IF2 ADC", "IF1 ADC1", "IF1 ADC1"},
+       {"IF2 ADC", "IF1 ADC2", "IF1 ADC2"},
+       {"IF2 ADC", NULL, "I2S2"},
+
+       {"AIF1TX", NULL, "IF1 ADC1"},
+       {"AIF1TX", NULL, "IF1 ADC2"},
+       {"AIF2TX", NULL, "IF2 ADC"},
+
+       {"IF1 DAC", NULL, "AIF1RX"},
+       {"IF1 DAC", NULL, "I2S1"},
+       {"IF2 DAC", NULL, "AIF2RX"},
+       {"IF2 DAC", NULL, "I2S2"},
+
+       {"IF1 DAC1 L", NULL, "IF1 DAC"},
+       {"IF1 DAC1 R", NULL, "IF1 DAC"},
+       {"IF1 DAC2 L", NULL, "IF1 DAC"},
+       {"IF1 DAC2 R", NULL, "IF1 DAC"},
+       {"IF2 DAC L", NULL, "IF2 DAC"},
+       {"IF2 DAC R", NULL, "IF2 DAC"},
+
+       {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+       {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+       {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+       {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+       {"Audio DSP", NULL, "DAC MIXL"},
+       {"Audio DSP", NULL, "DAC MIXR"},
+
+       {"DAC L2 Mux", "IF1", "IF1 DAC2 L"},
+       {"DAC L2 Mux", "IF2", "IF2 DAC L"},
+       {"DAC L2 Volume", NULL, "DAC L2 Mux"},
+
+       {"DAC R2 Mux", "IF1", "IF1 DAC2 R"},
+       {"DAC R2 Mux", "IF2", "IF2 DAC R"},
+       {"DAC R2 Volume", NULL, "DAC R2 Mux"},
+
+       {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+       {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"},
+       {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+       {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+       {"Stereo DAC MIXL", NULL, "Stero2 DAC Power"},
+       {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+       {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"},
+       {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+       {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+       {"Stereo DAC MIXR", NULL, "Stero2 DAC Power"},
+
+       {"PDM L Mux", "Stereo DAC MIX", "Stereo DAC MIXL"},
+       {"PDM L Mux", "DD MIX", "DAC MIXL"},
+       {"PDM R Mux", "Stereo DAC MIX", "Stereo DAC MIXR"},
+       {"PDM R Mux", "DD MIX", "DAC MIXR"},
+
+       {"DAC L1", NULL, "Stereo DAC MIXL"},
+       {"DAC L1", NULL, "PLL1", is_sysclk_from_pll},
+       {"DAC L1", NULL, "DAC L1 Power"},
+       {"DAC R1", NULL, "Stereo DAC MIXR"},
+       {"DAC R1", NULL, "PLL1", is_sysclk_from_pll},
+       {"DAC R1", NULL, "DAC R1 Power"},
+
+       {"DD MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"DD MIXL", "DAC L2 Switch", "DAC L2 Volume"},
+       {"DD MIXL", "DAC R2 Switch", "DAC R2 Volume"},
+       {"DD MIXL", NULL, "Stero2 DAC Power"},
+
+       {"DD MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"DD MIXR", "DAC R2 Switch", "DAC R2 Volume"},
+       {"DD MIXR", "DAC L2 Switch", "DAC L2 Volume"},
+       {"DD MIXR", NULL, "Stero2 DAC Power"},
+
+       {"OUT MIXL", "BST1 Switch", "BST1"},
+       {"OUT MIXL", "BST2 Switch", "BST2"},
+       {"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+       {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+       {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+       {"OUT MIXR", "BST2 Switch", "BST2"},
+       {"OUT MIXR", "BST1 Switch", "BST1"},
+       {"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+       {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+       {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+       {"HPOVOL L", "Switch", "OUT MIXL"},
+       {"HPOVOL R", "Switch", "OUT MIXR"},
+       {"OUTVOL L", "Switch", "OUT MIXL"},
+       {"OUTVOL R", "Switch", "OUT MIXR"},
+
+       {"HPOL MIX", "HPO MIX DAC1 Switch", "DAC L1"},
+       {"HPOL MIX", "HPO MIX HPVOL Switch", "HPOVOL L"},
+       {"HPOL MIX", NULL, "HP L Amp"},
+       {"HPOR MIX", "HPO MIX DAC1 Switch", "DAC R1"},
+       {"HPOR MIX", "HPO MIX HPVOL Switch", "HPOVOL R"},
+       {"HPOR MIX", NULL, "HP R Amp"},
+
+       {"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+       {"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+       {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+       {"HP Amp", NULL, "HPOL MIX"},
+       {"HP Amp", NULL, "HPOR MIX"},
+       {"HP Amp", NULL, "Amp Power"},
+       {"HPO L Playback", "Switch", "HP Amp"},
+       {"HPO R Playback", "Switch", "HP Amp"},
+       {"HPOL", NULL, "HPO L Playback"},
+       {"HPOR", NULL, "HPO R Playback"},
+
+       {"LOUT L Playback", "Switch", "LOUT MIX"},
+       {"LOUT R Playback", "Switch", "LOUT MIX"},
+       {"LOUTL", NULL, "LOUT L Playback"},
+       {"LOUTL", NULL, "Amp Power"},
+       {"LOUTR", NULL, "LOUT R Playback"},
+       {"LOUTR", NULL, "Amp Power"},
+
+       {"PDML", NULL, "PDM L Mux"},
+       {"PDMR", NULL, "PDM R Mux"},
+};
+
+static int get_clk_info(int sclk, int rate)
+{
+       int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+       if (sclk <= 0 || rate <= 0)
+               return -EINVAL;
+
+       rate = rate << 8;
+       for (i = 0; i < ARRAY_SIZE(pd); i++)
+               if (sclk == rate * pd[i])
+                       return i;
+
+       return -EINVAL;
+}
+
+static int rt5651_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0, val_clk, mask_clk;
+       int pre_div, bclk_ms, frame_size;
+
+       rt5651->lrck[dai->id] = params_rate(params);
+       pre_div = get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
+
+       if (pre_div < 0) {
+               dev_err(codec->dev, "Unsupported clock setting\n");
+               return -EINVAL;
+       }
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               return -EINVAL;
+       }
+       bclk_ms = frame_size > 32 ? 1 : 0;
+       rt5651->bclk[dai->id] = rt5651->lrck[dai->id] * (32 << bclk_ms);
+
+       dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+               rt5651->bclk[dai->id], rt5651->lrck[dai->id]);
+       dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+                               bclk_ms, pre_div, dai->id);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val_len |= RT5651_I2S_DL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val_len |= RT5651_I2S_DL_24;
+               break;
+       case SNDRV_PCM_FORMAT_S8:
+               val_len |= RT5651_I2S_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5651_AIF1:
+               mask_clk = RT5651_I2S_PD1_MASK;
+               val_clk = pre_div << RT5651_I2S_PD1_SFT;
+               snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+                       RT5651_I2S_DL_MASK, val_len);
+               snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+               break;
+       case RT5651_AIF2:
+               mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK;
+               val_clk = pre_div << RT5651_I2S_PD2_SFT;
+               snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+                       RT5651_I2S_DL_MASK, val_len);
+               snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+               break;
+       default:
+               dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5651->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg_val |= RT5651_I2S_MS_S;
+               rt5651->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5651_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5651_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5651_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val |= RT5651_I2S_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5651_AIF1:
+               snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+                       RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
+                       RT5651_I2S_DF_MASK, reg_val);
+               break;
+       case RT5651_AIF2:
+               snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+                       RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
+                       RT5651_I2S_DF_MASK, reg_val);
+               break;
+       default:
+               dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5651_SCLK_S_MCLK:
+               reg_val |= RT5651_SCLK_SRC_MCLK;
+               break;
+       case RT5651_SCLK_S_PLL1:
+               reg_val |= RT5651_SCLK_SRC_PLL1;
+               break;
+       case RT5651_SCLK_S_RCCLK:
+               reg_val |= RT5651_SCLK_SRC_RCCLK;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, RT5651_GLB_CLK,
+               RT5651_SCLK_SRC_MASK, reg_val);
+       rt5651->sysclk = freq;
+       rt5651->sysclk_src = clk_id;
+
+       dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+       return 0;
+}
+
+/**
+ * rt5651_pll_calc - Calcualte PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ *
+ * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2
+ * which make calculation more efficiently.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5651_pll_calc(const unsigned int freq_in,
+       const unsigned int freq_out, struct rt5651_pll_code *pll_code)
+{
+       int max_n = RT5651_PLL_N_MAX, max_m = RT5651_PLL_M_MAX;
+       int n = 0, m = 0, red, n_t, m_t, in_t, out_t;
+       int red_t = abs(freq_out - freq_in);
+       bool bypass = false;
+
+       if (RT5651_PLL_INP_MAX < freq_in || RT5651_PLL_INP_MIN > freq_in)
+               return -EINVAL;
+
+       for (n_t = 0; n_t <= max_n; n_t++) {
+               in_t = (freq_in >> 1) + (freq_in >> 2) * n_t;
+               if (in_t < 0)
+                       continue;
+               if (in_t == freq_out) {
+                       bypass = true;
+                       n = n_t;
+                       goto code_find;
+               }
+               for (m_t = 0; m_t <= max_m; m_t++) {
+                       out_t = in_t / (m_t + 2);
+                       red = abs(out_t - freq_out);
+                       if (red < red_t) {
+                               n = n_t;
+                               m = m_t;
+                               if (red == 0)
+                                       goto code_find;
+                               red_t = red;
+                       }
+               }
+       }
+       pr_debug("Only get approximation about PLL\n");
+
+code_find:
+       pll_code->m_bp = bypass;
+       pll_code->m_code = m;
+       pll_code->n_code = n;
+       pll_code->k_code = 2;
+       return 0;
+}
+
+static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+                       unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+       struct rt5651_pll_code *pll_code = &rt5651->pll_code;
+       int ret;
+
+       if (source == rt5651->pll_src && freq_in == rt5651->pll_in &&
+           freq_out == rt5651->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(codec->dev, "PLL disabled\n");
+
+               rt5651->pll_in = 0;
+               rt5651->pll_out = 0;
+               snd_soc_update_bits(codec, RT5651_GLB_CLK,
+                       RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (source) {
+       case RT5651_PLL1_S_MCLK:
+               snd_soc_update_bits(codec, RT5651_GLB_CLK,
+                       RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK);
+               break;
+       case RT5651_PLL1_S_BCLK1:
+               snd_soc_update_bits(codec, RT5651_GLB_CLK,
+                               RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1);
+               break;
+       case RT5651_PLL1_S_BCLK2:
+                       snd_soc_update_bits(codec, RT5651_GLB_CLK,
+                               RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2);
+               break;
+       default:
+               dev_err(codec->dev, "Unknown PLL source %d\n", source);
+               return -EINVAL;
+       }
+
+       ret = rt5651_pll_calc(freq_in, freq_out, pll_code);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp,
+               (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code);
+
+       snd_soc_write(codec, RT5651_PLL_CTRL1,
+               pll_code->n_code << RT5651_PLL_N_SFT | pll_code->k_code);
+       snd_soc_write(codec, RT5651_PLL_CTRL2,
+               (pll_code->m_bp ? 0 : pll_code->m_code) << RT5651_PLL_M_SFT |
+               pll_code->m_bp << RT5651_PLL_M_BP_SFT);
+
+       rt5651->pll_in = freq_in;
+       rt5651->pll_out = freq_out;
+       rt5651->pll_src = source;
+
+       return 0;
+}
+
+static int rt5651_set_bias_level(struct snd_soc_codec *codec,
+                       enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+                       snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+                               RT5651_PWR_VREF1 | RT5651_PWR_MB |
+                               RT5651_PWR_BG | RT5651_PWR_VREF2,
+                               RT5651_PWR_VREF1 | RT5651_PWR_MB |
+                               RT5651_PWR_BG | RT5651_PWR_VREF2);
+                       usleep_range(10000, 15000);
+                       snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+                               RT5651_PWR_FV1 | RT5651_PWR_FV2,
+                               RT5651_PWR_FV1 | RT5651_PWR_FV2);
+                       snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+                               RT5651_PWR_LDO_DVO_MASK,
+                               RT5651_PWR_LDO_DVO_1_2V);
+                       snd_soc_update_bits(codec, RT5651_D_MISC, 0x1, 0x1);
+                       if (snd_soc_read(codec, RT5651_PLL_MODE_1) & 0x9200)
+                               snd_soc_update_bits(codec, RT5651_D_MISC,
+                                                   0xc00, 0xc00);
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               snd_soc_write(codec, RT5651_D_MISC, 0x0010);
+               snd_soc_write(codec, RT5651_PWR_DIG1, 0x0000);
+               snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000);
+               snd_soc_write(codec, RT5651_PWR_VOL, 0x0000);
+               snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000);
+               snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
+               snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
+               break;
+
+       default:
+               break;
+       }
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int rt5651_probe(struct snd_soc_codec *codec)
+{
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+       rt5651->codec = codec;
+
+       snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+               RT5651_PWR_VREF1 | RT5651_PWR_MB |
+               RT5651_PWR_BG | RT5651_PWR_VREF2,
+               RT5651_PWR_VREF1 | RT5651_PWR_MB |
+               RT5651_PWR_BG | RT5651_PWR_VREF2);
+       usleep_range(10000, 15000);
+       snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+               RT5651_PWR_FV1 | RT5651_PWR_FV2,
+               RT5651_PWR_FV1 | RT5651_PWR_FV2);
+
+       rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5651_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5651->regmap, true);
+       regcache_mark_dirty(rt5651->regmap);
+       return 0;
+}
+
+static int rt5651_resume(struct snd_soc_codec *codec)
+{
+       struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5651->regmap, false);
+       snd_soc_cache_sync(codec);
+
+       return 0;
+}
+#else
+#define rt5651_suspend NULL
+#define rt5651_resume NULL
+#endif
+
+#define RT5651_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5651_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5651_aif_dai_ops = {
+       .hw_params = rt5651_hw_params,
+       .set_fmt = rt5651_set_dai_fmt,
+       .set_sysclk = rt5651_set_dai_sysclk,
+       .set_pll = rt5651_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5651_dai[] = {
+       {
+               .name = "rt5651-aif1",
+               .id = RT5651_AIF1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5651_STEREO_RATES,
+                       .formats = RT5651_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5651_STEREO_RATES,
+                       .formats = RT5651_FORMATS,
+               },
+               .ops = &rt5651_aif_dai_ops,
+       },
+       {
+               .name = "rt5651-aif2",
+               .id = RT5651_AIF2,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5651_STEREO_RATES,
+                       .formats = RT5651_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5651_STEREO_RATES,
+                       .formats = RT5651_FORMATS,
+               },
+               .ops = &rt5651_aif_dai_ops,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
+       .probe = rt5651_probe,
+       .suspend = rt5651_suspend,
+       .resume = rt5651_resume,
+       .set_bias_level = rt5651_set_bias_level,
+       .idle_bias_off = true,
+       .controls = rt5651_snd_controls,
+       .num_controls = ARRAY_SIZE(rt5651_snd_controls),
+       .dapm_widgets = rt5651_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
+       .dapm_routes = rt5651_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
+};
+
+static const struct regmap_config rt5651_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .max_register = RT5651_DEVICE_ID + 1 + (ARRAY_SIZE(rt5651_ranges) *
+                                              RT5651_PR_SPACING),
+       .volatile_reg = rt5651_volatile_register,
+       .readable_reg = rt5651_readable_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5651_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5651_reg),
+       .ranges = rt5651_ranges,
+       .num_ranges = ARRAY_SIZE(rt5651_ranges),
+};
+
+static const struct i2c_device_id rt5651_i2c_id[] = {
+       { "rt5651", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
+
+static int rt5651_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5651_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       struct rt5651_priv *rt5651;
+       int ret;
+
+       rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651),
+                               GFP_KERNEL);
+       if (NULL == rt5651)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, rt5651);
+
+       if (pdata)
+               rt5651->pdata = *pdata;
+
+       rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
+       if (IS_ERR(rt5651->regmap)) {
+               ret = PTR_ERR(rt5651->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret);
+       if (ret != RT5651_DEVICE_ID_VALUE) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %x is not rt5651\n", ret);
+               return -ENODEV;
+       }
+
+       regmap_write(rt5651->regmap, RT5651_RESET, 0);
+
+       ret = regmap_register_patch(rt5651->regmap, init_list,
+                                   ARRAY_SIZE(init_list));
+       if (ret != 0)
+               dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+       if (rt5651->pdata.in2_diff)
+               regmap_update_bits(rt5651->regmap, RT5651_IN1_IN2,
+                                       RT5651_IN_DF2, RT5651_IN_DF2);
+
+       if (rt5651->pdata.dmic_en)
+               regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1,
+                               RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL);
+
+       rt5651->hp_mute = 1;
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,
+                               rt5651_dai, ARRAY_SIZE(rt5651_dai));
+
+       return ret;
+}
+
+static int rt5651_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static struct i2c_driver rt5651_i2c_driver = {
+       .driver = {
+               .name = "rt5651",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5651_i2c_probe,
+       .remove   = rt5651_i2c_remove,
+       .id_table = rt5651_i2c_id,
+};
+module_i2c_driver(rt5651_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5651 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
new file mode 100644 (file)
index 0000000..a28bd0c
--- /dev/null
@@ -0,0 +1,2081 @@
+/*
+ * rt5651.h  --  RT5651 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5651_H__
+#define __RT5651_H__
+
+#include <sound/rt5651.h>
+
+/* Info */
+#define RT5651_RESET                           0x00
+#define RT5651_VERSION_ID                      0xfd
+#define RT5651_VENDOR_ID                       0xfe
+#define RT5651_DEVICE_ID                       0xff
+/*  I/O - Output */
+#define RT5651_HP_VOL                          0x02
+#define RT5651_LOUT_CTRL1                      0x03
+#define RT5651_LOUT_CTRL2                      0x05
+/* I/O - Input */
+#define RT5651_IN1_IN2                         0x0d
+#define RT5651_IN3                             0x0e
+#define RT5651_INL1_INR1_VOL                   0x0f
+#define RT5651_INL2_INR2_VOL                   0x10
+/* I/O - ADC/DAC/DMIC */
+#define RT5651_DAC1_DIG_VOL                    0x19
+#define RT5651_DAC2_DIG_VOL                    0x1a
+#define RT5651_DAC2_CTRL                       0x1b
+#define RT5651_ADC_DIG_VOL                     0x1c
+#define RT5651_ADC_DATA                                0x1d
+#define RT5651_ADC_BST_VOL                     0x1e
+/* Mixer - D-D */
+#define RT5651_STO1_ADC_MIXER                  0x27
+#define RT5651_STO2_ADC_MIXER                  0x28
+#define RT5651_AD_DA_MIXER                     0x29
+#define RT5651_STO_DAC_MIXER                   0x2a
+#define RT5651_DD_MIXER                                0x2b
+#define RT5651_DIG_INF_DATA                    0x2f
+/* PDM */
+#define RT5651_PDM_CTL                         0x30
+#define RT5651_PDM_I2C_CTL1                    0x31
+#define RT5651_PDM_I2C_CTL2                    0x32
+#define RT5651_PDM_I2C_DATA_W                  0x33
+#define RT5651_PDM_I2C_DATA_R                  0x34
+/* Mixer - ADC */
+#define RT5651_REC_L1_MIXER                    0x3b
+#define RT5651_REC_L2_MIXER                    0x3c
+#define RT5651_REC_R1_MIXER                    0x3d
+#define RT5651_REC_R2_MIXER                    0x3e
+/* Mixer - DAC */
+#define RT5651_HPO_MIXER                       0x45
+#define RT5651_OUT_L1_MIXER                    0x4d
+#define RT5651_OUT_L2_MIXER                    0x4e
+#define RT5651_OUT_L3_MIXER                    0x4f
+#define RT5651_OUT_R1_MIXER                    0x50
+#define RT5651_OUT_R2_MIXER                    0x51
+#define RT5651_OUT_R3_MIXER                    0x52
+#define RT5651_LOUT_MIXER                      0x53
+/* Power */
+#define RT5651_PWR_DIG1                                0x61
+#define RT5651_PWR_DIG2                                0x62
+#define RT5651_PWR_ANLG1                       0x63
+#define RT5651_PWR_ANLG2                       0x64
+#define RT5651_PWR_MIXER                       0x65
+#define RT5651_PWR_VOL                         0x66
+/* Private Register Control */
+#define RT5651_PRIV_INDEX                      0x6a
+#define RT5651_PRIV_DATA                       0x6c
+/* Format - ADC/DAC */
+#define RT5651_I2S1_SDP                                0x70
+#define RT5651_I2S2_SDP                                0x71
+#define RT5651_ADDA_CLK1                       0x73
+#define RT5651_ADDA_CLK2                       0x74
+#define RT5651_DMIC                            0x75
+/* TDM Control */
+#define RT5651_TDM_CTL_1                       0x77
+#define RT5651_TDM_CTL_2                       0x78
+#define RT5651_TDM_CTL_3                       0x79
+/* Function - Analog */
+#define RT5651_GLB_CLK                         0x80
+#define RT5651_PLL_CTRL1                       0x81
+#define RT5651_PLL_CTRL2                       0x82
+#define RT5651_PLL_MODE_1                      0x83
+#define RT5651_PLL_MODE_2                      0x84
+#define RT5651_PLL_MODE_3                      0x85
+#define RT5651_PLL_MODE_4                      0x86
+#define RT5651_PLL_MODE_5                      0x87
+#define RT5651_PLL_MODE_6                      0x89
+#define RT5651_PLL_MODE_7                      0x8a
+#define RT5651_DEPOP_M1                                0x8e
+#define RT5651_DEPOP_M2                                0x8f
+#define RT5651_DEPOP_M3                                0x90
+#define RT5651_CHARGE_PUMP                     0x91
+#define RT5651_MICBIAS                         0x93
+#define RT5651_A_JD_CTL1                       0x94
+/* Function - Digital */
+#define RT5651_EQ_CTRL1                                0xb0
+#define RT5651_EQ_CTRL2                                0xb1
+#define RT5651_ALC_1                           0xb4
+#define RT5651_ALC_2                           0xb5
+#define RT5651_ALC_3                           0xb6
+#define RT5651_JD_CTRL1                                0xbb
+#define RT5651_JD_CTRL2                                0xbc
+#define RT5651_IRQ_CTRL1                       0xbd
+#define RT5651_IRQ_CTRL2                       0xbe
+#define RT5651_INT_IRQ_ST                      0xbf
+#define RT5651_GPIO_CTRL1                      0xc0
+#define RT5651_GPIO_CTRL2                      0xc1
+#define RT5651_GPIO_CTRL3                      0xc2
+#define RT5651_PGM_REG_ARR1                    0xc8
+#define RT5651_PGM_REG_ARR2                    0xc9
+#define RT5651_PGM_REG_ARR3                    0xca
+#define RT5651_PGM_REG_ARR4                    0xcb
+#define RT5651_PGM_REG_ARR5                    0xcc
+#define RT5651_SCB_FUNC                                0xcd
+#define RT5651_SCB_CTRL                                0xce
+#define RT5651_BASE_BACK                       0xcf
+#define RT5651_MP3_PLUS1                       0xd0
+#define RT5651_MP3_PLUS2                       0xd1
+#define RT5651_ADJ_HPF_CTRL1                   0xd3
+#define RT5651_ADJ_HPF_CTRL2                   0xd4
+#define RT5651_HP_CALIB_AMP_DET                        0xd6
+#define RT5651_HP_CALIB2                       0xd7
+#define RT5651_SV_ZCD1                         0xd9
+#define RT5651_SV_ZCD2                         0xda
+#define RT5651_D_MISC                          0xfa
+/* Dummy Register */
+#define RT5651_DUMMY2                          0xfb
+#define RT5651_DUMMY3                          0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5651_BIAS_CUR1                       0x12
+#define RT5651_BIAS_CUR3                       0x14
+#define RT5651_CLSD_INT_REG1                   0x1c
+#define RT5651_CHPUMP_INT_REG1                 0x24
+#define RT5651_MAMP_INT_REG2                   0x37
+#define RT5651_CHOP_DAC_ADC                    0x3d
+#define RT5651_3D_SPK                          0x63
+#define RT5651_WND_1                           0x6c
+#define RT5651_WND_2                           0x6d
+#define RT5651_WND_3                           0x6e
+#define RT5651_WND_4                           0x6f
+#define RT5651_WND_5                           0x70
+#define RT5651_WND_8                           0x73
+#define RT5651_DIP_SPK_INF                     0x75
+#define RT5651_HP_DCC_INT1                     0x77
+#define RT5651_EQ_BW_LOP                       0xa0
+#define RT5651_EQ_GN_LOP                       0xa1
+#define RT5651_EQ_FC_BP1                       0xa2
+#define RT5651_EQ_BW_BP1                       0xa3
+#define RT5651_EQ_GN_BP1                       0xa4
+#define RT5651_EQ_FC_BP2                       0xa5
+#define RT5651_EQ_BW_BP2                       0xa6
+#define RT5651_EQ_GN_BP2                       0xa7
+#define RT5651_EQ_FC_BP3                       0xa8
+#define RT5651_EQ_BW_BP3                       0xa9
+#define RT5651_EQ_GN_BP3                       0xaa
+#define RT5651_EQ_FC_BP4                       0xab
+#define RT5651_EQ_BW_BP4                       0xac
+#define RT5651_EQ_GN_BP4                       0xad
+#define RT5651_EQ_FC_HIP1                      0xae
+#define RT5651_EQ_GN_HIP1                      0xaf
+#define RT5651_EQ_FC_HIP2                      0xb0
+#define RT5651_EQ_BW_HIP2                      0xb1
+#define RT5651_EQ_GN_HIP2                      0xb2
+#define RT5651_EQ_PRE_VOL                      0xb3
+#define RT5651_EQ_PST_VOL                      0xb4
+
+
+/* global definition */
+#define RT5651_L_MUTE                          (0x1 << 15)
+#define RT5651_L_MUTE_SFT                      15
+#define RT5651_VOL_L_MUTE                      (0x1 << 14)
+#define RT5651_VOL_L_SFT                       14
+#define RT5651_R_MUTE                          (0x1 << 7)
+#define RT5651_R_MUTE_SFT                      7
+#define RT5651_VOL_R_MUTE                      (0x1 << 6)
+#define RT5651_VOL_R_SFT                       6
+#define RT5651_L_VOL_MASK                      (0x3f << 8)
+#define RT5651_L_VOL_SFT                       8
+#define RT5651_R_VOL_MASK                      (0x3f)
+#define RT5651_R_VOL_SFT                       0
+
+/* LOUT Control 2(0x05) */
+#define RT5651_EN_DFO                          (0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5651_BST_MASK1                       (0xf<<12)
+#define RT5651_BST_SFT1                                12
+#define RT5651_BST_MASK2                       (0xf<<8)
+#define RT5651_BST_SFT2                                8
+#define RT5651_IN_DF1                          (0x1 << 7)
+#define RT5651_IN_SFT1                         7
+#define RT5651_IN_DF2                          (0x1 << 6)
+#define RT5651_IN_SFT2                         6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+/* INL2 and INR2 Volume Control (0x10) */
+#define RT5651_INL_SEL_MASK                    (0x1 << 15)
+#define RT5651_INL_SEL_SFT                     15
+#define RT5651_INL_SEL_IN4P                    (0x0 << 15)
+#define RT5651_INL_SEL_MONOP                   (0x1 << 15)
+#define RT5651_INL_VOL_MASK                    (0x1f << 8)
+#define RT5651_INL_VOL_SFT                     8
+#define RT5651_INR_SEL_MASK                    (0x1 << 7)
+#define RT5651_INR_SEL_SFT                     7
+#define RT5651_INR_SEL_IN4N                    (0x0 << 7)
+#define RT5651_INR_SEL_MONON                   (0x1 << 7)
+#define RT5651_INR_VOL_MASK                    (0x1f)
+#define RT5651_INR_VOL_SFT                     0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5651_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5651_DAC_L1_VOL_SFT                  8
+#define RT5651_DAC_R1_VOL_MASK                 (0xff)
+#define RT5651_DAC_R1_VOL_SFT                  0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5651_DAC_L2_VOL_MASK                 (0xff << 8)
+#define RT5651_DAC_L2_VOL_SFT                  8
+#define RT5651_DAC_R2_VOL_MASK                 (0xff)
+#define RT5651_DAC_R2_VOL_SFT                  0
+
+/* DAC2 Control (0x1b) */
+#define RT5651_M_DAC_L2_VOL                    (0x1 << 13)
+#define RT5651_M_DAC_L2_VOL_SFT                        13
+#define RT5651_M_DAC_R2_VOL                    (0x1 << 12)
+#define RT5651_M_DAC_R2_VOL_SFT                        12
+#define RT5651_SEL_DAC_L2                      (0x1 << 11)
+#define RT5651_IF2_DAC_L2                      (0x1 << 11)
+#define RT5651_IF1_DAC_L2                      (0x0 << 11)
+#define RT5651_SEL_DAC_L2_SFT                  11
+#define RT5651_SEL_DAC_R2                      (0x1 << 10)
+#define RT5651_IF2_DAC_R2                      (0x1 << 11)
+#define RT5651_IF1_DAC_R2                      (0x0 << 11)
+#define RT5651_SEL_DAC_R2_SFT                  10
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5651_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5651_ADC_L_VOL_SFT                   8
+#define RT5651_ADC_R_VOL_MASK                  (0x7f)
+#define RT5651_ADC_R_VOL_SFT                   0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5651_M_MONO_ADC_L                    (0x1 << 15)
+#define RT5651_M_MONO_ADC_L_SFT                        15
+#define RT5651_MONO_ADC_L_VOL_MASK             (0x7f << 8)
+#define RT5651_MONO_ADC_L_VOL_SFT              8
+#define RT5651_M_MONO_ADC_R                    (0x1 << 7)
+#define RT5651_M_MONO_ADC_R_SFT                        7
+#define RT5651_MONO_ADC_R_VOL_MASK             (0x7f)
+#define RT5651_MONO_ADC_R_VOL_SFT              0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5651_ADC_L_BST_MASK                  (0x3 << 14)
+#define RT5651_ADC_L_BST_SFT                   14
+#define RT5651_ADC_R_BST_MASK                  (0x3 << 12)
+#define RT5651_ADC_R_BST_SFT                   12
+#define RT5651_ADC_COMP_MASK                   (0x3 << 10)
+#define RT5651_ADC_COMP_SFT                    10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5651_M_STO1_ADC_L1                   (0x1 << 14)
+#define RT5651_M_STO1_ADC_L1_SFT               14
+#define RT5651_M_STO1_ADC_L2                   (0x1 << 13)
+#define RT5651_M_STO1_ADC_L2_SFT               13
+#define RT5651_STO1_ADC_1_SRC_MASK             (0x1 << 12)
+#define RT5651_STO1_ADC_1_SRC_SFT              12
+#define RT5651_STO1_ADC_1_SRC_ADC              (0x1 << 12)
+#define RT5651_STO1_ADC_1_SRC_DACMIX           (0x0 << 12)
+#define RT5651_STO1_ADC_2_SRC_MASK             (0x1 << 11)
+#define RT5651_STO1_ADC_2_SRC_SFT              11
+#define RT5651_STO1_ADC_2_SRC_DMIC             (0x0 << 11)
+#define RT5651_STO1_ADC_2_SRC_DACMIXR  (0x1 << 11)
+#define RT5651_M_STO1_ADC_R1                   (0x1 << 6)
+#define RT5651_M_STO1_ADC_R1_SFT               6
+#define RT5651_M_STO1_ADC_R2                   (0x1 << 5)
+#define RT5651_M_STO1_ADC_R2_SFT               5
+
+/* Stereo ADC2 Mixer Control (0x28) */
+#define RT5651_M_STO2_ADC_L1                   (0x1 << 14)
+#define RT5651_M_STO2_ADC_L1_SFT               14
+#define RT5651_M_STO2_ADC_L2                   (0x1 << 13)
+#define RT5651_M_STO2_ADC_L2_SFT               13
+#define RT5651_STO2_ADC_L1_SRC_MASK            (0x1 << 12)
+#define RT5651_STO2_ADC_L1_SRC_SFT             12
+#define RT5651_STO2_ADC_L1_SRC_DACMIXL         (0x0 << 12)
+#define RT5651_STO2_ADC_L1_SRC_ADCL            (0x1 << 12)
+#define RT5651_STO2_ADC_L2_SRC_MASK            (0x1 << 11)
+#define RT5651_STO2_ADC_L2_SRC_SFT             11
+#define RT5651_STO2_ADC_L2_SRC_DMIC            (0x0 << 11)
+#define RT5651_STO2_ADC_L2_SRC_DACMIXR         (0x1 << 11)
+#define RT5651_M_STO2_ADC_R1                   (0x1 << 6)
+#define RT5651_M_STO2_ADC_R1_SFT               6
+#define RT5651_M_STO2_ADC_R2                   (0x1 << 5)
+#define RT5651_M_STO2_ADC_R2_SFT               5
+#define RT5651_STO2_ADC_R1_SRC_MASK            (0x1 << 4)
+#define RT5651_STO2_ADC_R1_SRC_SFT             4
+#define RT5651_STO2_ADC_R1_SRC_ADCR            (0x1 << 4)
+#define RT5651_STO2_ADC_R1_SRC_DACMIXR         (0x0 << 4)
+#define RT5651_STO2_ADC_R2_SRC_MASK            (0x1 << 3)
+#define RT5651_STO2_ADC_R2_SRC_SFT             3
+#define RT5651_STO2_ADC_R2_SRC_DMIC            (0x0 << 3)
+#define RT5651_STO2_ADC_R2_SRC_DACMIXR         (0x1 << 3)
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5651_M_ADCMIX_L                      (0x1 << 15)
+#define RT5651_M_ADCMIX_L_SFT                  15
+#define RT5651_M_IF1_DAC_L                     (0x1 << 14)
+#define RT5651_M_IF1_DAC_L_SFT                 14
+#define RT5651_M_ADCMIX_R                      (0x1 << 7)
+#define RT5651_M_ADCMIX_R_SFT                  7
+#define RT5651_M_IF1_DAC_R                     (0x1 << 6)
+#define RT5651_M_IF1_DAC_R_SFT                 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5651_M_DAC_L1_MIXL                   (0x1 << 14)
+#define RT5651_M_DAC_L1_MIXL_SFT               14
+#define RT5651_DAC_L1_STO_L_VOL_MASK           (0x1 << 13)
+#define RT5651_DAC_L1_STO_L_VOL_SFT            13
+#define RT5651_M_DAC_L2_MIXL                   (0x1 << 12)
+#define RT5651_M_DAC_L2_MIXL_SFT               12
+#define RT5651_DAC_L2_STO_L_VOL_MASK           (0x1 << 11)
+#define RT5651_DAC_L2_STO_L_VOL_SFT            11
+#define RT5651_M_DAC_R1_MIXL                   (0x1 << 9)
+#define RT5651_M_DAC_R1_MIXL_SFT               9
+#define RT5651_DAC_R1_STO_L_VOL_MASK           (0x1 << 8)
+#define RT5651_DAC_R1_STO_L_VOL_SFT            8
+#define RT5651_M_DAC_R1_MIXR                   (0x1 << 6)
+#define RT5651_M_DAC_R1_MIXR_SFT               6
+#define RT5651_DAC_R1_STO_R_VOL_MASK           (0x1 << 5)
+#define RT5651_DAC_R1_STO_R_VOL_SFT            5
+#define RT5651_M_DAC_R2_MIXR                   (0x1 << 4)
+#define RT5651_M_DAC_R2_MIXR_SFT               4
+#define RT5651_DAC_R2_STO_R_VOL_MASK           (0x1 << 3)
+#define RT5651_DAC_R2_STO_R_VOL_SFT            3
+#define RT5651_M_DAC_L1_MIXR                   (0x1 << 1)
+#define RT5651_M_DAC_L1_MIXR_SFT               1
+#define RT5651_DAC_L1_STO_R_VOL_MASK           (0x1)
+#define RT5651_DAC_L1_STO_R_VOL_SFT            0
+
+/* DD Mixer Control (0x2b) */
+#define RT5651_M_STO_DD_L1                     (0x1 << 14)
+#define RT5651_M_STO_DD_L1_SFT                 14
+#define RT5651_STO_DD_L1_VOL_MASK              (0x1 << 13)
+#define RT5651_DAC_DD_L1_VOL_SFT               13
+#define RT5651_M_STO_DD_L2                     (0x1 << 12)
+#define RT5651_M_STO_DD_L2_SFT                 12
+#define RT5651_STO_DD_L2_VOL_MASK              (0x1 << 11)
+#define RT5651_STO_DD_L2_VOL_SFT               11
+#define RT5651_M_STO_DD_R2_L                   (0x1 << 10)
+#define RT5651_M_STO_DD_R2_L_SFT               10
+#define RT5651_STO_DD_R2_L_VOL_MASK            (0x1 << 9)
+#define RT5651_STO_DD_R2_L_VOL_SFT             9
+#define RT5651_M_STO_DD_R1                     (0x1 << 6)
+#define RT5651_M_STO_DD_R1_SFT                 6
+#define RT5651_STO_DD_R1_VOL_MASK              (0x1 << 5)
+#define RT5651_STO_DD_R1_VOL_SFT               5
+#define RT5651_M_STO_DD_R2                     (0x1 << 4)
+#define RT5651_M_STO_DD_R2_SFT                 4
+#define RT5651_STO_DD_R2_VOL_MASK              (0x1 << 3)
+#define RT5651_STO_DD_R2_VOL_SFT               3
+#define RT5651_M_STO_DD_L2_R                   (0x1 << 2)
+#define RT5651_M_STO_DD_L2_R_SFT               2
+#define RT5651_STO_DD_L2_R_VOL_MASK            (0x1 << 1)
+#define RT5651_STO_DD_L2_R_VOL_SFT             1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5651_M_STO_L_DAC_L                   (0x1 << 15)
+#define RT5651_M_STO_L_DAC_L_SFT               15
+#define RT5651_STO_L_DAC_L_VOL_MASK            (0x1 << 14)
+#define RT5651_STO_L_DAC_L_VOL_SFT             14
+#define RT5651_M_DAC_L2_DAC_L                  (0x1 << 13)
+#define RT5651_M_DAC_L2_DAC_L_SFT              13
+#define RT5651_DAC_L2_DAC_L_VOL_MASK           (0x1 << 12)
+#define RT5651_DAC_L2_DAC_L_VOL_SFT            12
+#define RT5651_M_STO_R_DAC_R                   (0x1 << 11)
+#define RT5651_M_STO_R_DAC_R_SFT               11
+#define RT5651_STO_R_DAC_R_VOL_MASK            (0x1 << 10)
+#define RT5651_STO_R_DAC_R_VOL_SFT             10
+#define RT5651_M_DAC_R2_DAC_R                  (0x1 << 9)
+#define RT5651_M_DAC_R2_DAC_R_SFT              9
+#define RT5651_DAC_R2_DAC_R_VOL_MASK           (0x1 << 8)
+#define RT5651_DAC_R2_DAC_R_VOL_SFT            8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5651_RXDP_SRC_MASK                   (0x1 << 15)
+#define RT5651_RXDP_SRC_SFT                    15
+#define RT5651_RXDP_SRC_NOR                    (0x0 << 15)
+#define RT5651_RXDP_SRC_DIV3                   (0x1 << 15)
+#define RT5651_TXDP_SRC_MASK                   (0x1 << 14)
+#define RT5651_TXDP_SRC_SFT                    14
+#define RT5651_TXDP_SRC_NOR                    (0x0 << 14)
+#define RT5651_TXDP_SRC_DIV3                   (0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5651_DAC_L2_SEL_MASK                 (0x3 << 14)
+#define RT5651_DAC_L2_SEL_SFT                  14
+#define RT5651_DAC_L2_SEL_IF2                  (0x0 << 14)
+#define RT5651_DAC_L2_SEL_IF3                  (0x1 << 14)
+#define RT5651_DAC_L2_SEL_TXDC                 (0x2 << 14)
+#define RT5651_DAC_L2_SEL_BASS                 (0x3 << 14)
+#define RT5651_DAC_R2_SEL_MASK                 (0x3 << 12)
+#define RT5651_DAC_R2_SEL_SFT                  12
+#define RT5651_DAC_R2_SEL_IF2                  (0x0 << 12)
+#define RT5651_DAC_R2_SEL_IF3                  (0x1 << 12)
+#define RT5651_DAC_R2_SEL_TXDC                 (0x2 << 12)
+#define RT5651_IF2_ADC_L_SEL_MASK              (0x1 << 11)
+#define RT5651_IF2_ADC_L_SEL_SFT               11
+#define RT5651_IF2_ADC_L_SEL_TXDP              (0x0 << 11)
+#define RT5651_IF2_ADC_L_SEL_PASS              (0x1 << 11)
+#define RT5651_IF2_ADC_R_SEL_MASK              (0x1 << 10)
+#define RT5651_IF2_ADC_R_SEL_SFT               10
+#define RT5651_IF2_ADC_R_SEL_TXDP              (0x0 << 10)
+#define RT5651_IF2_ADC_R_SEL_PASS              (0x1 << 10)
+#define RT5651_RXDC_SEL_MASK                   (0x3 << 8)
+#define RT5651_RXDC_SEL_SFT                    8
+#define RT5651_RXDC_SEL_NOR                    (0x0 << 8)
+#define RT5651_RXDC_SEL_L2R                    (0x1 << 8)
+#define RT5651_RXDC_SEL_R2L                    (0x2 << 8)
+#define RT5651_RXDC_SEL_SWAP                   (0x3 << 8)
+#define RT5651_RXDP_SEL_MASK                   (0x3 << 6)
+#define RT5651_RXDP_SEL_SFT                    6
+#define RT5651_RXDP_SEL_NOR                    (0x0 << 6)
+#define RT5651_RXDP_SEL_L2R                    (0x1 << 6)
+#define RT5651_RXDP_SEL_R2L                    (0x2 << 6)
+#define RT5651_RXDP_SEL_SWAP                   (0x3 << 6)
+#define RT5651_TXDC_SEL_MASK                   (0x3 << 4)
+#define RT5651_TXDC_SEL_SFT                    4
+#define RT5651_TXDC_SEL_NOR                    (0x0 << 4)
+#define RT5651_TXDC_SEL_L2R                    (0x1 << 4)
+#define RT5651_TXDC_SEL_R2L                    (0x2 << 4)
+#define RT5651_TXDC_SEL_SWAP                   (0x3 << 4)
+#define RT5651_TXDP_SEL_MASK                   (0x3 << 2)
+#define RT5651_TXDP_SEL_SFT                    2
+#define RT5651_TXDP_SEL_NOR                    (0x0 << 2)
+#define RT5651_TXDP_SEL_L2R                    (0x1 << 2)
+#define RT5651_TXDP_SEL_R2L                    (0x2 << 2)
+#define RT5651_TRXDP_SEL_SWAP                  (0x3 << 2)
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5651_IF2_DAC_SEL_MASK                        (0x3 << 10)
+#define RT5651_IF2_DAC_SEL_SFT                 10
+#define RT5651_IF2_DAC_SEL_NOR                 (0x0 << 10)
+#define RT5651_IF2_DAC_SEL_SWAP                        (0x1 << 10)
+#define RT5651_IF2_DAC_SEL_L2R                 (0x2 << 10)
+#define RT5651_IF2_DAC_SEL_R2L                 (0x3 << 10)
+#define RT5651_IF2_ADC_SEL_MASK                        (0x3 << 8)
+#define RT5651_IF2_ADC_SEL_SFT                 8
+#define RT5651_IF2_ADC_SEL_NOR                 (0x0 << 8)
+#define RT5651_IF2_ADC_SEL_SWAP                        (0x1 << 8)
+#define RT5651_IF2_ADC_SEL_L2R                 (0x2 << 8)
+#define RT5651_IF2_ADC_SEL_R2L                 (0x3 << 8)
+#define RT5651_IF2_ADC_SRC_MASK                        (0x1 << 7)
+#define RT5651_IF2_ADC_SRC_SFT                 7
+#define RT5651_IF1_ADC1                                (0x0 << 7)
+#define RT5651_IF1_ADC2                                (0x1 << 7)
+
+/* PDM Output Control (0x30) */
+#define RT5651_PDM_L_SEL_MASK                  (0x1 << 15)
+#define RT5651_PDM_L_SEL_SFT                   15
+#define RT5651_PDM_L_SEL_DD_L                  (0x0 << 15)
+#define RT5651_PDM_L_SEL_STO_L                 (0x1 << 15)
+#define RT5651_M_PDM_L                         (0x1 << 14)
+#define RT5651_M_PDM_L_SFT                     14
+#define RT5651_PDM_R_SEL_MASK                  (0x1 << 13)
+#define RT5651_PDM_R_SEL_SFT                   13
+#define RT5651_PDM_R_SEL_DD_L                  (0x0 << 13)
+#define RT5651_PDM_R_SEL_STO_L                 (0x1 << 13)
+#define RT5651_M_PDM_R                         (0x1 << 12)
+#define RT5651_M_PDM_R_SFT                     12
+#define RT5651_PDM_BUSY                                (0x1 << 6)
+#define RT5651_PDM_BUSY_SFT                    6
+#define RT5651_PDM_PATTERN_SEL_MASK            (0x1 << 5)
+#define RT5651_PDM_PATTERN_SEL_64              (0x0 << 5)
+#define RT5651_PDM_PATTERN_SEL_128             (0x1 << 5)
+#define RT5651_PDM_VOL_MASK                    (0x1 << 4)
+#define RT5651_PDM_VOL_SFT                     4
+#define RT5651_PDM_DIV_MASK                    (0x3)
+#define RT5651_PDM_DIV_SFT                     0
+#define RT5651_PDM_DIV_1                       0
+#define RT5651_PDM_DIV_2                       1
+#define RT5651_PDM_DIV_3                       2
+#define RT5651_PDM_DIV_4                       3
+
+/* PDM I2C/Data Control 1 (0x31) */
+#define RT5651_PDM_I2C_ID_MASK                 (0xf << 12)
+#define PT5631_PDM_CMD_EXE                     (0x1 << 11)
+#define RT5651_PDM_I2C_CMD_MASK                        (0x1 << 10)
+#define RT5651_PDM_I2C_CMD_R                   (0x0 << 10)
+#define RT5651_PDM_I2C_CMD_W                   (0x1 << 10)
+#define RT5651_PDM_I2C_CMD_EXE                 (0x1 << 9)
+#define RT5651_PDM_I2C_NORMAL                  (0x0 << 8)
+#define RT5651_PDM_I2C_BUSY                    (0x1 << 8)
+
+/* PDM I2C/Data Control 2 (0x32) */
+#define RT5651_PDM_I2C_ADDR                    (0xff << 8)
+#define RT5651_PDM_I2C_CMD_PATTERN             (0xff)
+
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5651_G_LN_L2_RM_L_MASK               (0x7 << 13)
+#define RT5651_G_IN_L2_RM_L_SFT                        13
+#define RT5651_G_LN_L1_RM_L_MASK               (0x7 << 10)
+#define RT5651_G_IN_L1_RM_L_SFT                        10
+#define RT5651_G_BST3_RM_L_MASK                        (0x7 << 4)
+#define RT5651_G_BST3_RM_L_SFT                 4
+#define RT5651_G_BST2_RM_L_MASK                        (0x7 << 1)
+#define RT5651_G_BST2_RM_L_SFT                 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5651_G_BST1_RM_L_MASK                        (0x7 << 13)
+#define RT5651_G_BST1_RM_L_SFT                 13
+#define RT5651_G_OM_L_RM_L_MASK                        (0x7 << 10)
+#define RT5651_G_OM_L_RM_L_SFT                 10
+#define RT5651_M_IN2_L_RM_L                    (0x1 << 6)
+#define RT5651_M_IN2_L_RM_L_SFT                        6
+#define RT5651_M_IN1_L_RM_L                    (0x1 << 5)
+#define RT5651_M_IN1_L_RM_L_SFT                        5
+#define RT5651_M_BST3_RM_L                     (0x1 << 3)
+#define RT5651_M_BST3_RM_L_SFT                 3
+#define RT5651_M_BST2_RM_L                     (0x1 << 2)
+#define RT5651_M_BST2_RM_L_SFT                 2
+#define RT5651_M_BST1_RM_L                     (0x1 << 1)
+#define RT5651_M_BST1_RM_L_SFT                 1
+#define RT5651_M_OM_L_RM_L                     (0x1)
+#define RT5651_M_OM_L_RM_L_SFT                 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5651_G_IN2_R_RM_R_MASK               (0x7 << 13)
+#define RT5651_G_IN2_R_RM_R_SFT                        13
+#define RT5651_G_IN1_R_RM_R_MASK               (0x7 << 10)
+#define RT5651_G_IN1_R_RM_R_SFT                        10
+#define RT5651_G_BST3_RM_R_MASK                        (0x7 << 4)
+#define RT5651_G_BST3_RM_R_SFT                 4
+#define RT5651_G_BST2_RM_R_MASK                        (0x7 << 1)
+#define RT5651_G_BST2_RM_R_SFT                 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5651_G_BST1_RM_R_MASK                        (0x7 << 13)
+#define RT5651_G_BST1_RM_R_SFT                 13
+#define RT5651_G_OM_R_RM_R_MASK                        (0x7 << 10)
+#define RT5651_G_OM_R_RM_R_SFT                 10
+#define RT5651_M_IN2_R_RM_R                    (0x1 << 6)
+#define RT5651_M_IN2_R_RM_R_SFT                        6
+#define RT5651_M_IN1_R_RM_R                    (0x1 << 5)
+#define RT5651_M_IN1_R_RM_R_SFT                        5
+#define RT5651_M_BST3_RM_R                     (0x1 << 3)
+#define RT5651_M_BST3_RM_R_SFT                 3
+#define RT5651_M_BST2_RM_R                     (0x1 << 2)
+#define RT5651_M_BST2_RM_R_SFT                 2
+#define RT5651_M_BST1_RM_R                     (0x1 << 1)
+#define RT5651_M_BST1_RM_R_SFT                 1
+#define RT5651_M_OM_R_RM_R                     (0x1)
+#define RT5651_M_OM_R_RM_R_SFT                 0
+
+/* HPMIX Control (0x45) */
+#define RT5651_M_DAC1_HM                       (0x1 << 14)
+#define RT5651_M_DAC1_HM_SFT                   14
+#define RT5651_M_HPVOL_HM                      (0x1 << 13)
+#define RT5651_M_HPVOL_HM_SFT                  13
+#define RT5651_G_HPOMIX_MASK                   (0x1 << 12)
+#define RT5651_G_HPOMIX_SFT                    12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5651_G_RM_L_SM_L_MASK                        (0x3 << 14)
+#define RT5651_G_RM_L_SM_L_SFT                 14
+#define RT5651_G_IN_L_SM_L_MASK                        (0x3 << 12)
+#define RT5651_G_IN_L_SM_L_SFT                 12
+#define RT5651_G_DAC_L1_SM_L_MASK              (0x3 << 10)
+#define RT5651_G_DAC_L1_SM_L_SFT               10
+#define RT5651_G_DAC_L2_SM_L_MASK              (0x3 << 8)
+#define RT5651_G_DAC_L2_SM_L_SFT               8
+#define RT5651_G_OM_L_SM_L_MASK                        (0x3 << 6)
+#define RT5651_G_OM_L_SM_L_SFT                 6
+#define RT5651_M_RM_L_SM_L                     (0x1 << 5)
+#define RT5651_M_RM_L_SM_L_SFT                 5
+#define RT5651_M_IN_L_SM_L                     (0x1 << 4)
+#define RT5651_M_IN_L_SM_L_SFT                 4
+#define RT5651_M_DAC_L1_SM_L                   (0x1 << 3)
+#define RT5651_M_DAC_L1_SM_L_SFT               3
+#define RT5651_M_DAC_L2_SM_L                   (0x1 << 2)
+#define RT5651_M_DAC_L2_SM_L_SFT               2
+#define RT5651_M_OM_L_SM_L                     (0x1 << 1)
+#define RT5651_M_OM_L_SM_L_SFT                 1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5651_G_RM_R_SM_R_MASK                        (0x3 << 14)
+#define RT5651_G_RM_R_SM_R_SFT                 14
+#define RT5651_G_IN_R_SM_R_MASK                        (0x3 << 12)
+#define RT5651_G_IN_R_SM_R_SFT                 12
+#define RT5651_G_DAC_R1_SM_R_MASK              (0x3 << 10)
+#define RT5651_G_DAC_R1_SM_R_SFT               10
+#define RT5651_G_DAC_R2_SM_R_MASK              (0x3 << 8)
+#define RT5651_G_DAC_R2_SM_R_SFT               8
+#define RT5651_G_OM_R_SM_R_MASK                        (0x3 << 6)
+#define RT5651_G_OM_R_SM_R_SFT                 6
+#define RT5651_M_RM_R_SM_R                     (0x1 << 5)
+#define RT5651_M_RM_R_SM_R_SFT                 5
+#define RT5651_M_IN_R_SM_R                     (0x1 << 4)
+#define RT5651_M_IN_R_SM_R_SFT                 4
+#define RT5651_M_DAC_R1_SM_R                   (0x1 << 3)
+#define RT5651_M_DAC_R1_SM_R_SFT               3
+#define RT5651_M_DAC_R2_SM_R                   (0x1 << 2)
+#define RT5651_M_DAC_R2_SM_R_SFT               2
+#define RT5651_M_OM_R_SM_R                     (0x1 << 1)
+#define RT5651_M_OM_R_SM_R_SFT                 1
+
+/* SPOLMIX Control (0x48) */
+#define RT5651_M_DAC_R1_SPM_L                  (0x1 << 15)
+#define RT5651_M_DAC_R1_SPM_L_SFT              15
+#define RT5651_M_DAC_L1_SPM_L                  (0x1 << 14)
+#define RT5651_M_DAC_L1_SPM_L_SFT              14
+#define RT5651_M_SV_R_SPM_L                    (0x1 << 13)
+#define RT5651_M_SV_R_SPM_L_SFT                        13
+#define RT5651_M_SV_L_SPM_L                    (0x1 << 12)
+#define RT5651_M_SV_L_SPM_L_SFT                        12
+#define RT5651_M_BST1_SPM_L                    (0x1 << 11)
+#define RT5651_M_BST1_SPM_L_SFT                        11
+
+/* SPORMIX Control (0x49) */
+#define RT5651_M_DAC_R1_SPM_R                  (0x1 << 13)
+#define RT5651_M_DAC_R1_SPM_R_SFT              13
+#define RT5651_M_SV_R_SPM_R                    (0x1 << 12)
+#define RT5651_M_SV_R_SPM_R_SFT                        12
+#define RT5651_M_BST1_SPM_R                    (0x1 << 11)
+#define RT5651_M_BST1_SPM_R_SFT                        11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5651_SPO_CLSD_RATIO_MASK             (0x7)
+#define RT5651_SPO_CLSD_RATIO_SFT              0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5651_M_DAC_R2_MM                     (0x1 << 15)
+#define RT5651_M_DAC_R2_MM_SFT                 15
+#define RT5651_M_DAC_L2_MM                     (0x1 << 14)
+#define RT5651_M_DAC_L2_MM_SFT                 14
+#define RT5651_M_OV_R_MM                       (0x1 << 13)
+#define RT5651_M_OV_R_MM_SFT                   13
+#define RT5651_M_OV_L_MM                       (0x1 << 12)
+#define RT5651_M_OV_L_MM_SFT                   12
+#define RT5651_M_BST1_MM                       (0x1 << 11)
+#define RT5651_M_BST1_MM_SFT                   11
+#define RT5651_G_MONOMIX_MASK                  (0x1 << 10)
+#define RT5651_G_MONOMIX_SFT                   10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5651_G_BST2_OM_L_MASK                        (0x7 << 10)
+#define RT5651_G_BST2_OM_L_SFT                 10
+#define RT5651_G_BST1_OM_L_MASK                        (0x7 << 7)
+#define RT5651_G_BST1_OM_L_SFT                 7
+#define RT5651_G_IN1_L_OM_L_MASK               (0x7 << 4)
+#define RT5651_G_IN1_L_OM_L_SFT                        4
+#define RT5651_G_RM_L_OM_L_MASK                        (0x7 << 1)
+#define RT5651_G_RM_L_OM_L_SFT                 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5651_G_DAC_L1_OM_L_MASK              (0x7 << 7)
+#define RT5651_G_DAC_L1_OM_L_SFT               7
+#define RT5651_G_IN2_L_OM_L_MASK               (0x7 << 4)
+#define RT5651_G_IN2_L_OM_L_SFT                        4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5651_M_IN2_L_OM_L                    (0x1 << 9)
+#define RT5651_M_IN2_L_OM_L_SFT                        9
+#define RT5651_M_BST2_OM_L                     (0x1 << 6)
+#define RT5651_M_BST2_OM_L_SFT                 6
+#define RT5651_M_BST1_OM_L                     (0x1 << 5)
+#define RT5651_M_BST1_OM_L_SFT                 5
+#define RT5651_M_IN1_L_OM_L                    (0x1 << 4)
+#define RT5651_M_IN1_L_OM_L_SFT                        4
+#define RT5651_M_RM_L_OM_L                     (0x1 << 3)
+#define RT5651_M_RM_L_OM_L_SFT                 3
+#define RT5651_M_DAC_L1_OM_L                   (0x1)
+#define RT5651_M_DAC_L1_OM_L_SFT               0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5651_G_BST2_OM_R_MASK                        (0x7 << 10)
+#define RT5651_G_BST2_OM_R_SFT                 10
+#define RT5651_G_BST1_OM_R_MASK                        (0x7 << 7)
+#define RT5651_G_BST1_OM_R_SFT                 7
+#define RT5651_G_IN1_R_OM_R_MASK               (0x7 << 4)
+#define RT5651_G_IN1_R_OM_R_SFT                        4
+#define RT5651_G_RM_R_OM_R_MASK                        (0x7 << 1)
+#define RT5651_G_RM_R_OM_R_SFT                 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5651_G_DAC_R1_OM_R_MASK              (0x7 << 7)
+#define RT5651_G_DAC_R1_OM_R_SFT               7
+#define RT5651_G_IN2_R_OM_R_MASK               (0x7 << 4)
+#define RT5651_G_IN2_R_OM_R_SFT                        4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5651_M_IN2_R_OM_R                    (0x1 << 9)
+#define RT5651_M_IN2_R_OM_R_SFT                        9
+#define RT5651_M_BST2_OM_R                     (0x1 << 6)
+#define RT5651_M_BST2_OM_R_SFT                 6
+#define RT5651_M_BST1_OM_R                     (0x1 << 5)
+#define RT5651_M_BST1_OM_R_SFT                 5
+#define RT5651_M_IN1_R_OM_R                    (0x1 << 4)
+#define RT5651_M_IN1_R_OM_R_SFT                        4
+#define RT5651_M_RM_R_OM_R                     (0x1 << 3)
+#define RT5651_M_RM_R_OM_R_SFT                 3
+#define RT5651_M_DAC_R1_OM_R                   (0x1)
+#define RT5651_M_DAC_R1_OM_R_SFT               0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5651_M_DAC_L1_LM                     (0x1 << 15)
+#define RT5651_M_DAC_L1_LM_SFT                 15
+#define RT5651_M_DAC_R1_LM                     (0x1 << 14)
+#define RT5651_M_DAC_R1_LM_SFT                 14
+#define RT5651_M_OV_L_LM                       (0x1 << 13)
+#define RT5651_M_OV_L_LM_SFT                   13
+#define RT5651_M_OV_R_LM                       (0x1 << 12)
+#define RT5651_M_OV_R_LM_SFT                   12
+#define RT5651_G_LOUTMIX_MASK                  (0x1 << 11)
+#define RT5651_G_LOUTMIX_SFT                   11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5651_PWR_I2S1                                (0x1 << 15)
+#define RT5651_PWR_I2S1_BIT                    15
+#define RT5651_PWR_I2S2                                (0x1 << 14)
+#define RT5651_PWR_I2S2_BIT                    14
+#define RT5651_PWR_DAC_L1                      (0x1 << 12)
+#define RT5651_PWR_DAC_L1_BIT                  12
+#define RT5651_PWR_DAC_R1                      (0x1 << 11)
+#define RT5651_PWR_DAC_R1_BIT                  11
+#define RT5651_PWR_ADC_L                       (0x1 << 2)
+#define RT5651_PWR_ADC_L_BIT                   2
+#define RT5651_PWR_ADC_R                       (0x1 << 1)
+#define RT5651_PWR_ADC_R_BIT                   1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5651_PWR_ADC_STO1_F                  (0x1 << 15)
+#define RT5651_PWR_ADC_STO1_F_BIT                      15
+#define RT5651_PWR_ADC_STO2_F                  (0x1 << 14)
+#define RT5651_PWR_ADC_STO2_F_BIT              14
+#define RT5651_PWR_DAC_STO1_F                  (0x1 << 11)
+#define RT5651_PWR_DAC_STO1_F_BIT                      11
+#define RT5651_PWR_DAC_STO2_F                  (0x1 << 10)
+#define RT5651_PWR_DAC_STO2_F_BIT              10
+#define RT5651_PWR_PDM                         (0x1 << 9)
+#define RT5651_PWR_PDM_BIT                     9
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5651_PWR_VREF1                       (0x1 << 15)
+#define RT5651_PWR_VREF1_BIT                   15
+#define RT5651_PWR_FV1                         (0x1 << 14)
+#define RT5651_PWR_FV1_BIT                     14
+#define RT5651_PWR_MB                          (0x1 << 13)
+#define RT5651_PWR_MB_BIT                      13
+#define RT5651_PWR_LM                          (0x1 << 12)
+#define RT5651_PWR_LM_BIT                      12
+#define RT5651_PWR_BG                          (0x1 << 11)
+#define RT5651_PWR_BG_BIT                      11
+#define RT5651_PWR_HP_L                                (0x1 << 7)
+#define RT5651_PWR_HP_L_BIT                    7
+#define RT5651_PWR_HP_R                                (0x1 << 6)
+#define RT5651_PWR_HP_R_BIT                    6
+#define RT5651_PWR_HA                          (0x1 << 5)
+#define RT5651_PWR_HA_BIT                      5
+#define RT5651_PWR_VREF2                       (0x1 << 4)
+#define RT5651_PWR_VREF2_BIT                   4
+#define RT5651_PWR_FV2                         (0x1 << 3)
+#define RT5651_PWR_FV2_BIT                     3
+#define RT5651_PWR_LDO                         (0x1 << 2)
+#define RT5651_PWR_LDO_BIT                     2
+#define RT5651_PWR_LDO_DVO_MASK                        (0x3)
+#define RT5651_PWR_LDO_DVO_1_0V                        0
+#define RT5651_PWR_LDO_DVO_1_1V                        1
+#define RT5651_PWR_LDO_DVO_1_2V                        2
+#define RT5651_PWR_LDO_DVO_1_3V                        3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5651_PWR_BST1                                (0x1 << 15)
+#define RT5651_PWR_BST1_BIT                    15
+#define RT5651_PWR_BST2                                (0x1 << 14)
+#define RT5651_PWR_BST2_BIT                    14
+#define RT5651_PWR_BST3                                (0x1 << 13)
+#define RT5651_PWR_BST3_BIT                    13
+#define RT5651_PWR_MB1                         (0x1 << 11)
+#define RT5651_PWR_MB1_BIT                     11
+#define RT5651_PWR_PLL                         (0x1 << 9)
+#define RT5651_PWR_PLL_BIT                     9
+#define RT5651_PWR_BST1_OP2                    (0x1 << 5)
+#define RT5651_PWR_BST1_OP2_BIT                        5
+#define RT5651_PWR_BST2_OP2                    (0x1 << 4)
+#define RT5651_PWR_BST2_OP2_BIT                        4
+#define RT5651_PWR_BST3_OP2                    (0x1 << 3)
+#define RT5651_PWR_BST3_OP2_BIT                        3
+#define RT5651_PWR_JD_M                                (0x1 << 2)
+#define RT5651_PWM_JD_M_BIT                    2
+#define RT5651_PWR_JD2                         (0x1 << 1)
+#define RT5651_PWM_JD2_BIT                     1
+#define RT5651_PWR_JD3                         (0x1)
+#define RT5651_PWM_JD3_BIT                     0
+
+/* Power Management for Mixer (0x65) */
+#define RT5651_PWR_OM_L                                (0x1 << 15)
+#define RT5651_PWR_OM_L_BIT                    15
+#define RT5651_PWR_OM_R                                (0x1 << 14)
+#define RT5651_PWR_OM_R_BIT                    14
+#define RT5651_PWR_RM_L                                (0x1 << 11)
+#define RT5651_PWR_RM_L_BIT                    11
+#define RT5651_PWR_RM_R                                (0x1 << 10)
+#define RT5651_PWR_RM_R_BIT                    10
+
+/* Power Management for Volume (0x66) */
+#define RT5651_PWR_OV_L                                (0x1 << 13)
+#define RT5651_PWR_OV_L_BIT                    13
+#define RT5651_PWR_OV_R                                (0x1 << 12)
+#define RT5651_PWR_OV_R_BIT                    12
+#define RT5651_PWR_HV_L                                (0x1 << 11)
+#define RT5651_PWR_HV_L_BIT                    11
+#define RT5651_PWR_HV_R                                (0x1 << 10)
+#define RT5651_PWR_HV_R_BIT                    10
+#define RT5651_PWR_IN1_L                       (0x1 << 9)
+#define RT5651_PWR_IN1_L_BIT                   9
+#define RT5651_PWR_IN1_R                       (0x1 << 8)
+#define RT5651_PWR_IN1_R_BIT                   8
+#define RT5651_PWR_IN2_L                       (0x1 << 7)
+#define RT5651_PWR_IN2_L_BIT                   7
+#define RT5651_PWR_IN2_R                       (0x1 << 6)
+#define RT5651_PWR_IN2_R_BIT                   6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5651_I2S_MS_MASK                     (0x1 << 15)
+#define RT5651_I2S_MS_SFT                      15
+#define RT5651_I2S_MS_M                                (0x0 << 15)
+#define RT5651_I2S_MS_S                                (0x1 << 15)
+#define RT5651_I2S_O_CP_MASK                   (0x3 << 10)
+#define RT5651_I2S_O_CP_SFT                    10
+#define RT5651_I2S_O_CP_OFF                    (0x0 << 10)
+#define RT5651_I2S_O_CP_U_LAW                  (0x1 << 10)
+#define RT5651_I2S_O_CP_A_LAW                  (0x2 << 10)
+#define RT5651_I2S_I_CP_MASK                   (0x3 << 8)
+#define RT5651_I2S_I_CP_SFT                    8
+#define RT5651_I2S_I_CP_OFF                    (0x0 << 8)
+#define RT5651_I2S_I_CP_U_LAW                  (0x1 << 8)
+#define RT5651_I2S_I_CP_A_LAW                  (0x2 << 8)
+#define RT5651_I2S_BP_MASK                     (0x1 << 7)
+#define RT5651_I2S_BP_SFT                      7
+#define RT5651_I2S_BP_NOR                      (0x0 << 7)
+#define RT5651_I2S_BP_INV                      (0x1 << 7)
+#define RT5651_I2S_DL_MASK                     (0x3 << 2)
+#define RT5651_I2S_DL_SFT                      2
+#define RT5651_I2S_DL_16                       (0x0 << 2)
+#define RT5651_I2S_DL_20                       (0x1 << 2)
+#define RT5651_I2S_DL_24                       (0x2 << 2)
+#define RT5651_I2S_DL_8                                (0x3 << 2)
+#define RT5651_I2S_DF_MASK                     (0x3)
+#define RT5651_I2S_DF_SFT                      0
+#define RT5651_I2S_DF_I2S                      (0x0)
+#define RT5651_I2S_DF_LEFT                     (0x1)
+#define RT5651_I2S_DF_PCM_A                    (0x2)
+#define RT5651_I2S_DF_PCM_B                    (0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5651_I2S_PD1_MASK                    (0x7 << 12)
+#define RT5651_I2S_PD1_SFT                     12
+#define RT5651_I2S_PD1_1                       (0x0 << 12)
+#define RT5651_I2S_PD1_2                       (0x1 << 12)
+#define RT5651_I2S_PD1_3                       (0x2 << 12)
+#define RT5651_I2S_PD1_4                       (0x3 << 12)
+#define RT5651_I2S_PD1_6                       (0x4 << 12)
+#define RT5651_I2S_PD1_8                       (0x5 << 12)
+#define RT5651_I2S_PD1_12                      (0x6 << 12)
+#define RT5651_I2S_PD1_16                      (0x7 << 12)
+#define RT5651_I2S_BCLK_MS2_MASK               (0x1 << 11)
+#define RT5651_I2S_BCLK_MS2_SFT                        11
+#define RT5651_I2S_BCLK_MS2_32                 (0x0 << 11)
+#define RT5651_I2S_BCLK_MS2_64                 (0x1 << 11)
+#define RT5651_I2S_PD2_MASK                    (0x7 << 8)
+#define RT5651_I2S_PD2_SFT                     8
+#define RT5651_I2S_PD2_1                       (0x0 << 8)
+#define RT5651_I2S_PD2_2                       (0x1 << 8)
+#define RT5651_I2S_PD2_3                       (0x2 << 8)
+#define RT5651_I2S_PD2_4                       (0x3 << 8)
+#define RT5651_I2S_PD2_6                       (0x4 << 8)
+#define RT5651_I2S_PD2_8                       (0x5 << 8)
+#define RT5651_I2S_PD2_12                      (0x6 << 8)
+#define RT5651_I2S_PD2_16                      (0x7 << 8)
+#define RT5651_DAC_OSR_MASK                    (0x3 << 2)
+#define RT5651_DAC_OSR_SFT                     2
+#define RT5651_DAC_OSR_128                     (0x0 << 2)
+#define RT5651_DAC_OSR_64                      (0x1 << 2)
+#define RT5651_DAC_OSR_32                      (0x2 << 2)
+#define RT5651_DAC_OSR_128_3                   (0x3 << 2)
+#define RT5651_ADC_OSR_MASK                    (0x3)
+#define RT5651_ADC_OSR_SFT                     0
+#define RT5651_ADC_OSR_128                     (0x0)
+#define RT5651_ADC_OSR_64                      (0x1)
+#define RT5651_ADC_OSR_32                      (0x2)
+#define RT5651_ADC_OSR_128_3                   (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5651_DAHPF_EN                                (0x1 << 11)
+#define RT5651_DAHPF_EN_SFT                    11
+#define RT5651_ADHPF_EN                                (0x1 << 10)
+#define RT5651_ADHPF_EN_SFT                    10
+
+/* Digital Microphone Control (0x75) */
+#define RT5651_DMIC_1_EN_MASK                  (0x1 << 15)
+#define RT5651_DMIC_1_EN_SFT                   15
+#define RT5651_DMIC_1_DIS                      (0x0 << 15)
+#define RT5651_DMIC_1_EN                       (0x1 << 15)
+#define RT5651_DMIC_1L_LH_MASK                 (0x1 << 13)
+#define RT5651_DMIC_1L_LH_SFT                  13
+#define RT5651_DMIC_1L_LH_FALLING              (0x0 << 13)
+#define RT5651_DMIC_1L_LH_RISING               (0x1 << 13)
+#define RT5651_DMIC_1R_LH_MASK                 (0x1 << 12)
+#define RT5651_DMIC_1R_LH_SFT                  12
+#define RT5651_DMIC_1R_LH_FALLING              (0x0 << 12)
+#define RT5651_DMIC_1R_LH_RISING               (0x1 << 12)
+#define RT5651_DMIC_1_DP_MASK                  (0x3 << 10)
+#define RT5651_DMIC_1_DP_SFT                   10
+#define RT5651_DMIC_1_DP_GPIO6                 (0x0 << 10)
+#define RT5651_DMIC_1_DP_IN1P                  (0x1 << 10)
+#define RT5651_DMIC_2_DP_GPIO8                 (0x2 << 10)
+#define RT5651_DMIC_CLK_MASK                   (0x7 << 5)
+#define RT5651_DMIC_CLK_SFT                    5
+
+/* TDM Control 1 (0x77) */
+#define RT5651_TDM_INTEL_SEL_MASK              (0x1 << 15)
+#define RT5651_TDM_INTEL_SEL_SFT               15
+#define RT5651_TDM_INTEL_SEL_64                        (0x0 << 15)
+#define RT5651_TDM_INTEL_SEL_50                        (0x1 << 15)
+#define RT5651_TDM_MODE_SEL_MASK               (0x1 << 14)
+#define RT5651_TDM_MODE_SEL_SFT                        14
+#define RT5651_TDM_MODE_SEL_NOR                        (0x0 << 14)
+#define RT5651_TDM_MODE_SEL_TDM                        (0x1 << 14)
+#define RT5651_TDM_CH_NUM_SEL_MASK             (0x3 << 12)
+#define RT5651_TDM_CH_NUM_SEL_SFT              12
+#define RT5651_TDM_CH_NUM_SEL_2                        (0x0 << 12)
+#define RT5651_TDM_CH_NUM_SEL_4                        (0x1 << 12)
+#define RT5651_TDM_CH_NUM_SEL_6                        (0x2 << 12)
+#define RT5651_TDM_CH_NUM_SEL_8                        (0x3 << 12)
+#define RT5651_TDM_CH_LEN_SEL_MASK             (0x3 << 10)
+#define RT5651_TDM_CH_LEN_SEL_SFT              10
+#define RT5651_TDM_CH_LEN_SEL_16               (0x0 << 10)
+#define RT5651_TDM_CH_LEN_SEL_20               (0x1 << 10)
+#define RT5651_TDM_CH_LEN_SEL_24               (0x2 << 10)
+#define RT5651_TDM_CH_LEN_SEL_32               (0x3 << 10)
+#define RT5651_TDM_ADC_SEL_MASK                        (0x1 << 9)
+#define RT5651_TDM_ADC_SEL_SFT                 9
+#define RT5651_TDM_ADC_SEL_NOR                 (0x0 << 9)
+#define RT5651_TDM_ADC_SEL_SWAP                        (0x1 << 9)
+#define RT5651_TDM_ADC_START_SEL_MASK          (0x1 << 8)
+#define RT5651_TDM_ADC_START_SEL_SFT           8
+#define RT5651_TDM_ADC_START_SEL_SL0           (0x0 << 8)
+#define RT5651_TDM_ADC_START_SEL_SL4           (0x1 << 8)
+#define RT5651_TDM_I2S_CH2_SEL_MASK            (0x3 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_SFT             6
+#define RT5651_TDM_I2S_CH2_SEL_LR              (0x0 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_RL              (0x1 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_LL              (0x2 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_RR              (0x3 << 6)
+#define RT5651_TDM_I2S_CH4_SEL_MASK            (0x3 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_SFT             4
+#define RT5651_TDM_I2S_CH4_SEL_LR              (0x0 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_RL              (0x1 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_LL              (0x2 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_RR              (0x3 << 4)
+#define RT5651_TDM_I2S_CH6_SEL_MASK            (0x3 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_SFT             2
+#define RT5651_TDM_I2S_CH6_SEL_LR              (0x0 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_RL              (0x1 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_LL              (0x2 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_RR              (0x3 << 2)
+#define RT5651_TDM_I2S_CH8_SEL_MASK            (0x3)
+#define RT5651_TDM_I2S_CH8_SEL_SFT             0
+#define RT5651_TDM_I2S_CH8_SEL_LR              (0x0)
+#define RT5651_TDM_I2S_CH8_SEL_RL              (0x1)
+#define RT5651_TDM_I2S_CH8_SEL_LL              (0x2)
+#define RT5651_TDM_I2S_CH8_SEL_RR              (0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5651_TDM_LRCK_POL_SEL_MASK           (0x1 << 15)
+#define RT5651_TDM_LRCK_POL_SEL_SFT            15
+#define RT5651_TDM_LRCK_POL_SEL_NOR            (0x0 << 15)
+#define RT5651_TDM_LRCK_POL_SEL_INV            (0x1 << 15)
+#define RT5651_TDM_CH_VAL_SEL_MASK             (0x1 << 14)
+#define RT5651_TDM_CH_VAL_SEL_SFT              14
+#define RT5651_TDM_CH_VAL_SEL_CH01             (0x0 << 14)
+#define RT5651_TDM_CH_VAL_SEL_CH0123           (0x1 << 14)
+#define RT5651_TDM_CH_VAL_EN                   (0x1 << 13)
+#define RT5651_TDM_CH_VAL_SFT                  13
+#define RT5651_TDM_LPBK_EN                     (0x1 << 12)
+#define RT5651_TDM_LPBK_SFT                    12
+#define RT5651_TDM_LRCK_PULSE_SEL_MASK         (0x1 << 11)
+#define RT5651_TDM_LRCK_PULSE_SEL_SFT          11
+#define RT5651_TDM_LRCK_PULSE_SEL_BCLK         (0x0 << 11)
+#define RT5651_TDM_LRCK_PULSE_SEL_CH           (0x1 << 11)
+#define RT5651_TDM_END_EDGE_SEL_MASK           (0x1 << 10)
+#define RT5651_TDM_END_EDGE_SEL_SFT            10
+#define RT5651_TDM_END_EDGE_SEL_POS            (0x0 << 10)
+#define RT5651_TDM_END_EDGE_SEL_NEG            (0x1 << 10)
+#define RT5651_TDM_END_EDGE_EN                 (0x1 << 9)
+#define RT5651_TDM_END_EDGE_EN_SFT             9
+#define RT5651_TDM_TRAN_EDGE_SEL_MASK          (0x1 << 8)
+#define RT5651_TDM_TRAN_EDGE_SEL_SFT           8
+#define RT5651_TDM_TRAN_EDGE_SEL_POS           (0x0 << 8)
+#define RT5651_TDM_TRAN_EDGE_SEL_NEG           (0x1 << 8)
+#define RT5651_M_TDM2_L                                (0x1 << 7)
+#define RT5651_M_TDM2_L_SFT                    7
+#define RT5651_M_TDM2_R                                (0x1 << 6)
+#define RT5651_M_TDM2_R_SFT                    6
+#define RT5651_M_TDM4_L                                (0x1 << 5)
+#define RT5651_M_TDM4_L_SFT                    5
+#define RT5651_M_TDM4_R                                (0x1 << 4)
+#define RT5651_M_TDM4_R_SFT                    4
+
+/* TDM Control 3 (0x79) */
+#define RT5651_CH2_L_SEL_MASK                  (0x7 << 12)
+#define RT5651_CH2_L_SEL_SFT                   12
+#define RT5651_CH2_L_SEL_SL0                   (0x0 << 12)
+#define RT5651_CH2_L_SEL_SL1                   (0x1 << 12)
+#define RT5651_CH2_L_SEL_SL2                   (0x2 << 12)
+#define RT5651_CH2_L_SEL_SL3                   (0x3 << 12)
+#define RT5651_CH2_L_SEL_SL4                   (0x4 << 12)
+#define RT5651_CH2_L_SEL_SL5                   (0x5 << 12)
+#define RT5651_CH2_L_SEL_SL6                   (0x6 << 12)
+#define RT5651_CH2_L_SEL_SL7                   (0x7 << 12)
+#define RT5651_CH2_R_SEL_MASK                  (0x7 << 8)
+#define RT5651_CH2_R_SEL_SFT                   8
+#define RT5651_CH2_R_SEL_SL0                   (0x0 << 8)
+#define RT5651_CH2_R_SEL_SL1                   (0x1 << 8)
+#define RT5651_CH2_R_SEL_SL2                   (0x2 << 8)
+#define RT5651_CH2_R_SEL_SL3                   (0x3 << 8)
+#define RT5651_CH2_R_SEL_SL4                   (0x4 << 8)
+#define RT5651_CH2_R_SEL_SL5                   (0x5 << 8)
+#define RT5651_CH2_R_SEL_SL6                   (0x6 << 8)
+#define RT5651_CH2_R_SEL_SL7                   (0x7 << 8)
+#define RT5651_CH4_L_SEL_MASK                  (0x7 << 4)
+#define RT5651_CH4_L_SEL_SFT                   4
+#define RT5651_CH4_L_SEL_SL0                   (0x0 << 4)
+#define RT5651_CH4_L_SEL_SL1                   (0x1 << 4)
+#define RT5651_CH4_L_SEL_SL2                   (0x2 << 4)
+#define RT5651_CH4_L_SEL_SL3                   (0x3 << 4)
+#define RT5651_CH4_L_SEL_SL4                   (0x4 << 4)
+#define RT5651_CH4_L_SEL_SL5                   (0x5 << 4)
+#define RT5651_CH4_L_SEL_SL6                   (0x6 << 4)
+#define RT5651_CH4_L_SEL_SL7                   (0x7 << 4)
+#define RT5651_CH4_R_SEL_MASK                  (0x7)
+#define RT5651_CH4_R_SEL_SFT                   0
+#define RT5651_CH4_R_SEL_SL0                   (0x0)
+#define RT5651_CH4_R_SEL_SL1                   (0x1)
+#define RT5651_CH4_R_SEL_SL2                   (0x2)
+#define RT5651_CH4_R_SEL_SL3                   (0x3)
+#define RT5651_CH4_R_SEL_SL4                   (0x4)
+#define RT5651_CH4_R_SEL_SL5                   (0x5)
+#define RT5651_CH4_R_SEL_SL6                   (0x6)
+#define RT5651_CH4_R_SEL_SL7                   (0x7)
+
+/* Global Clock Control (0x80) */
+#define RT5651_SCLK_SRC_MASK                   (0x3 << 14)
+#define RT5651_SCLK_SRC_SFT                    14
+#define RT5651_SCLK_SRC_MCLK                   (0x0 << 14)
+#define RT5651_SCLK_SRC_PLL1                   (0x1 << 14)
+#define RT5651_SCLK_SRC_RCCLK                  (0x2 << 14)
+#define RT5651_PLL1_SRC_MASK                   (0x3 << 12)
+#define RT5651_PLL1_SRC_SFT                    12
+#define RT5651_PLL1_SRC_MCLK                   (0x0 << 12)
+#define RT5651_PLL1_SRC_BCLK1                  (0x1 << 12)
+#define RT5651_PLL1_SRC_BCLK2                  (0x2 << 12)
+#define RT5651_PLL1_PD_MASK                    (0x1 << 3)
+#define RT5651_PLL1_PD_SFT                     3
+#define RT5651_PLL1_PD_1                       (0x0 << 3)
+#define RT5651_PLL1_PD_2                       (0x1 << 3)
+
+#define RT5651_PLL_INP_MAX                     40000000
+#define RT5651_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5651_PLL_N_MAX                       0x1ff
+#define RT5651_PLL_N_MASK                      (RT5651_PLL_N_MAX << 7)
+#define RT5651_PLL_N_SFT                       7
+#define RT5651_PLL_K_MAX                       0x1f
+#define RT5651_PLL_K_MASK                      (RT5651_PLL_K_MAX)
+#define RT5651_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5651_PLL_M_MAX                       0xf
+#define RT5651_PLL_M_MASK                      (RT5651_PLL_M_MAX << 12)
+#define RT5651_PLL_M_SFT                       12
+#define RT5651_PLL_M_BP                                (0x1 << 11)
+#define RT5651_PLL_M_BP_SFT                    11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5651_STO1_T_MASK                     (0x1 << 15)
+#define RT5651_STO1_T_SFT                      15
+#define RT5651_STO1_T_SCLK                     (0x0 << 15)
+#define RT5651_STO1_T_LRCK1                    (0x1 << 15)
+#define RT5651_STO2_T_MASK                     (0x1 << 12)
+#define RT5651_STO2_T_SFT                      12
+#define RT5651_STO2_T_I2S2                     (0x0 << 12)
+#define RT5651_STO2_T_LRCK2                    (0x1 << 12)
+#define RT5651_ASRC2_REF_MASK                  (0x1 << 11)
+#define RT5651_ASRC2_REF_SFT                   11
+#define RT5651_ASRC2_REF_LRCK2                 (0x0 << 11)
+#define RT5651_ASRC2_REF_LRCK1                 (0x1 << 11)
+#define RT5651_DMIC_1_M_MASK                   (0x1 << 9)
+#define RT5651_DMIC_1_M_SFT                    9
+#define RT5651_DMIC_1_M_NOR                    (0x0 << 9)
+#define RT5651_DMIC_1_M_ASYN                   (0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5651_STO1_ASRC_EN                    (0x1 << 15)
+#define RT5651_STO1_ASRC_EN_SFT                        15
+#define RT5651_STO2_ASRC_EN                    (0x1 << 14)
+#define RT5651_STO2_ASRC_EN_SFT                        14
+#define RT5651_STO1_DAC_M_MASK                 (0x1 << 13)
+#define RT5651_STO1_DAC_M_SFT                  13
+#define RT5651_STO1_DAC_M_NOR                  (0x0 << 13)
+#define RT5651_STO1_DAC_M_ASRC                 (0x1 << 13)
+#define RT5651_STO2_DAC_M_MASK                 (0x1 << 12)
+#define RT5651_STO2_DAC_M_SFT                  12
+#define RT5651_STO2_DAC_M_NOR                  (0x0 << 12)
+#define RT5651_STO2_DAC_M_ASRC                 (0x1 << 12)
+#define RT5651_ADC_M_MASK                      (0x1 << 11)
+#define RT5651_ADC_M_SFT                       11
+#define RT5651_ADC_M_NOR                       (0x0 << 11)
+#define RT5651_ADC_M_ASRC                      (0x1 << 11)
+#define RT5651_I2S1_R_D_MASK                   (0x1 << 4)
+#define RT5651_I2S1_R_D_SFT                    4
+#define RT5651_I2S1_R_D_DIS                    (0x0 << 4)
+#define RT5651_I2S1_R_D_EN                     (0x1 << 4)
+#define RT5651_I2S2_R_D_MASK                   (0x1 << 3)
+#define RT5651_I2S2_R_D_SFT                    3
+#define RT5651_I2S2_R_D_DIS                    (0x0 << 3)
+#define RT5651_I2S2_R_D_EN                     (0x1 << 3)
+#define RT5651_PRE_SCLK_MASK                   (0x3)
+#define RT5651_PRE_SCLK_SFT                    0
+#define RT5651_PRE_SCLK_512                    (0x0)
+#define RT5651_PRE_SCLK_1024                   (0x1)
+#define RT5651_PRE_SCLK_2048                   (0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5651_I2S1_RATE_MASK                  (0xf << 12)
+#define RT5651_I2S1_RATE_SFT                   12
+#define RT5651_I2S2_RATE_MASK                  (0xf << 8)
+#define RT5651_I2S2_RATE_SFT                   8
+#define RT5651_G_ASRC_LP_MASK                  (0x1 << 3)
+#define RT5651_G_ASRC_LP_SFT                   3
+#define RT5651_ASRC_LP_F_M                     (0x1 << 2)
+#define RT5651_ASRC_LP_F_SFT                   2
+#define RT5651_ASRC_LP_F_NOR                   (0x0 << 2)
+#define RT5651_ASRC_LP_F_SB                    (0x1 << 2)
+#define RT5651_FTK_PH_DET_MASK                 (0x3)
+#define RT5651_FTK_PH_DET_SFT                  0
+#define RT5651_FTK_PH_DET_DIV1                 (0x0)
+#define RT5651_FTK_PH_DET_DIV2                 (0x1)
+#define RT5651_FTK_PH_DET_DIV4                 (0x2)
+#define RT5651_FTK_PH_DET_DIV8                 (0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5651_I2S1_PD_MASK                    (0x7 << 12)
+#define RT5651_I2S1_PD_SFT                     12
+#define RT5651_I2S2_PD_MASK                    (0x7 << 8)
+#define RT5651_I2S2_PD_SFT                     8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5651_FSI1_RATE_MASK                  (0xf << 12)
+#define RT5651_FSI1_RATE_SFT                   12
+#define RT5651_FSI2_RATE_MASK                  (0xf << 8)
+#define RT5651_FSI2_RATE_SFT                   8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5651_HP_OVCD_MASK                    (0x1 << 10)
+#define RT5651_HP_OVCD_SFT                     10
+#define RT5651_HP_OVCD_DIS                     (0x0 << 10)
+#define RT5651_HP_OVCD_EN                      (0x1 << 10)
+#define RT5651_HP_OC_TH_MASK                   (0x3 << 8)
+#define RT5651_HP_OC_TH_SFT                    8
+#define RT5651_HP_OC_TH_90                     (0x0 << 8)
+#define RT5651_HP_OC_TH_105                    (0x1 << 8)
+#define RT5651_HP_OC_TH_120                    (0x2 << 8)
+#define RT5651_HP_OC_TH_135                    (0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5651_SMT_TRIG_MASK                   (0x1 << 15)
+#define RT5651_SMT_TRIG_SFT                    15
+#define RT5651_SMT_TRIG_DIS                    (0x0 << 15)
+#define RT5651_SMT_TRIG_EN                     (0x1 << 15)
+#define RT5651_HP_L_SMT_MASK                   (0x1 << 9)
+#define RT5651_HP_L_SMT_SFT                    9
+#define RT5651_HP_L_SMT_DIS                    (0x0 << 9)
+#define RT5651_HP_L_SMT_EN                     (0x1 << 9)
+#define RT5651_HP_R_SMT_MASK                   (0x1 << 8)
+#define RT5651_HP_R_SMT_SFT                    8
+#define RT5651_HP_R_SMT_DIS                    (0x0 << 8)
+#define RT5651_HP_R_SMT_EN                     (0x1 << 8)
+#define RT5651_HP_CD_PD_MASK                   (0x1 << 7)
+#define RT5651_HP_CD_PD_SFT                    7
+#define RT5651_HP_CD_PD_DIS                    (0x0 << 7)
+#define RT5651_HP_CD_PD_EN                     (0x1 << 7)
+#define RT5651_RSTN_MASK                       (0x1 << 6)
+#define RT5651_RSTN_SFT                                6
+#define RT5651_RSTN_DIS                                (0x0 << 6)
+#define RT5651_RSTN_EN                         (0x1 << 6)
+#define RT5651_RSTP_MASK                       (0x1 << 5)
+#define RT5651_RSTP_SFT                                5
+#define RT5651_RSTP_DIS                                (0x0 << 5)
+#define RT5651_RSTP_EN                         (0x1 << 5)
+#define RT5651_HP_CO_MASK                      (0x1 << 4)
+#define RT5651_HP_CO_SFT                       4
+#define RT5651_HP_CO_DIS                       (0x0 << 4)
+#define RT5651_HP_CO_EN                                (0x1 << 4)
+#define RT5651_HP_CP_MASK                      (0x1 << 3)
+#define RT5651_HP_CP_SFT                       3
+#define RT5651_HP_CP_PD                                (0x0 << 3)
+#define RT5651_HP_CP_PU                                (0x1 << 3)
+#define RT5651_HP_SG_MASK                      (0x1 << 2)
+#define RT5651_HP_SG_SFT                       2
+#define RT5651_HP_SG_DIS                       (0x0 << 2)
+#define RT5651_HP_SG_EN                                (0x1 << 2)
+#define RT5651_HP_DP_MASK                      (0x1 << 1)
+#define RT5651_HP_DP_SFT                       1
+#define RT5651_HP_DP_PD                                (0x0 << 1)
+#define RT5651_HP_DP_PU                                (0x1 << 1)
+#define RT5651_HP_CB_MASK                      (0x1)
+#define RT5651_HP_CB_SFT                       0
+#define RT5651_HP_CB_PD                                (0x0)
+#define RT5651_HP_CB_PU                                (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5651_DEPOP_MASK                      (0x1 << 13)
+#define RT5651_DEPOP_SFT                       13
+#define RT5651_DEPOP_AUTO                      (0x0 << 13)
+#define RT5651_DEPOP_MAN                       (0x1 << 13)
+#define RT5651_RAMP_MASK                       (0x1 << 12)
+#define RT5651_RAMP_SFT                                12
+#define RT5651_RAMP_DIS                                (0x0 << 12)
+#define RT5651_RAMP_EN                         (0x1 << 12)
+#define RT5651_BPS_MASK                                (0x1 << 11)
+#define RT5651_BPS_SFT                         11
+#define RT5651_BPS_DIS                         (0x0 << 11)
+#define RT5651_BPS_EN                          (0x1 << 11)
+#define RT5651_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5651_FAST_UPDN_SFT                   10
+#define RT5651_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5651_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5651_MRES_MASK                       (0x3 << 8)
+#define RT5651_MRES_SFT                                8
+#define RT5651_MRES_15MO                       (0x0 << 8)
+#define RT5651_MRES_25MO                       (0x1 << 8)
+#define RT5651_MRES_35MO                       (0x2 << 8)
+#define RT5651_MRES_45MO                       (0x3 << 8)
+#define RT5651_VLO_MASK                                (0x1 << 7)
+#define RT5651_VLO_SFT                         7
+#define RT5651_VLO_3V                          (0x0 << 7)
+#define RT5651_VLO_32V                         (0x1 << 7)
+#define RT5651_DIG_DP_MASK                     (0x1 << 6)
+#define RT5651_DIG_DP_SFT                      6
+#define RT5651_DIG_DP_DIS                      (0x0 << 6)
+#define RT5651_DIG_DP_EN                       (0x1 << 6)
+#define RT5651_DP_TH_MASK                      (0x3 << 4)
+#define RT5651_DP_TH_SFT                       4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5651_CP_SYS_MASK                     (0x7 << 12)
+#define RT5651_CP_SYS_SFT                      12
+#define RT5651_CP_FQ1_MASK                     (0x7 << 8)
+#define RT5651_CP_FQ1_SFT                      8
+#define RT5651_CP_FQ2_MASK                     (0x7 << 4)
+#define RT5651_CP_FQ2_SFT                      4
+#define RT5651_CP_FQ3_MASK                     (0x7)
+#define RT5651_CP_FQ3_SFT                      0
+#define RT5651_CP_FQ_1_5_KHZ                   0
+#define RT5651_CP_FQ_3_KHZ                     1
+#define RT5651_CP_FQ_6_KHZ                     2
+#define RT5651_CP_FQ_12_KHZ                    3
+#define RT5651_CP_FQ_24_KHZ                    4
+#define RT5651_CP_FQ_48_KHZ                    5
+#define RT5651_CP_FQ_96_KHZ                    6
+#define RT5651_CP_FQ_192_KHZ                   7
+
+/* HPOUT charge pump (0x91) */
+#define RT5651_OSW_L_MASK                      (0x1 << 11)
+#define RT5651_OSW_L_SFT                       11
+#define RT5651_OSW_L_DIS                       (0x0 << 11)
+#define RT5651_OSW_L_EN                                (0x1 << 11)
+#define RT5651_OSW_R_MASK                      (0x1 << 10)
+#define RT5651_OSW_R_SFT                       10
+#define RT5651_OSW_R_DIS                       (0x0 << 10)
+#define RT5651_OSW_R_EN                                (0x1 << 10)
+#define RT5651_PM_HP_MASK                      (0x3 << 8)
+#define RT5651_PM_HP_SFT                       8
+#define RT5651_PM_HP_LV                                (0x0 << 8)
+#define RT5651_PM_HP_MV                                (0x1 << 8)
+#define RT5651_PM_HP_HV                                (0x2 << 8)
+#define RT5651_IB_HP_MASK                      (0x3 << 6)
+#define RT5651_IB_HP_SFT                       6
+#define RT5651_IB_HP_125IL                     (0x0 << 6)
+#define RT5651_IB_HP_25IL                      (0x1 << 6)
+#define RT5651_IB_HP_5IL                       (0x2 << 6)
+#define RT5651_IB_HP_1IL                       (0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5651_MIC1_BS_MASK                    (0x1 << 15)
+#define RT5651_MIC1_BS_SFT                     15
+#define RT5651_MIC1_BS_9AV                     (0x0 << 15)
+#define RT5651_MIC1_BS_75AV                    (0x1 << 15)
+#define RT5651_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5651_MIC1_CLK_SFT                    13
+#define RT5651_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5651_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5651_MIC1_OVCD_MASK                  (0x1 << 11)
+#define RT5651_MIC1_OVCD_SFT                   11
+#define RT5651_MIC1_OVCD_DIS                   (0x0 << 11)
+#define RT5651_MIC1_OVCD_EN                    (0x1 << 11)
+#define RT5651_MIC1_OVTH_MASK                  (0x3 << 9)
+#define RT5651_MIC1_OVTH_SFT                   9
+#define RT5651_MIC1_OVTH_600UA                 (0x0 << 9)
+#define RT5651_MIC1_OVTH_1500UA                        (0x1 << 9)
+#define RT5651_MIC1_OVTH_2000UA                        (0x2 << 9)
+#define RT5651_PWR_MB_MASK                     (0x1 << 5)
+#define RT5651_PWR_MB_SFT                      5
+#define RT5651_PWR_MB_PD                       (0x0 << 5)
+#define RT5651_PWR_MB_PU                       (0x1 << 5)
+#define RT5651_PWR_CLK12M_MASK                 (0x1 << 4)
+#define RT5651_PWR_CLK12M_SFT                  4
+#define RT5651_PWR_CLK12M_PD                   (0x0 << 4)
+#define RT5651_PWR_CLK12M_PU                   (0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5651_JD2_CMP_MASK                    (0x7 << 12)
+#define RT5651_JD2_CMP_SFT                     12
+#define RT5651_JD_PU                           (0x1 << 11)
+#define RT5651_JD_PU_SFT                       11
+#define RT5651_JD_PD                           (0x1 << 10)
+#define RT5651_JD_PD_SFT                       10
+#define RT5651_JD_MODE_SEL_MASK                        (0x3 << 8)
+#define RT5651_JD_MODE_SEL_SFT                 8
+#define RT5651_JD_MODE_SEL_M0                  (0x0 << 8)
+#define RT5651_JD_MODE_SEL_M1                  (0x1 << 8)
+#define RT5651_JD_MODE_SEL_M2                  (0x2 << 8)
+#define RT5651_JD_M_CMP                                (0x7 << 4)
+#define RT5651_JD_M_CMP_SFT                    4
+#define RT5651_JD_M_PU                         (0x1 << 3)
+#define RT5651_JD_M_PU_SFT                     3
+#define RT5651_JD_M_PD                         (0x1 << 2)
+#define RT5651_JD_M_PD_SFT                     2
+#define RT5651_JD_M_MODE_SEL_MASK              (0x3)
+#define RT5651_JD_M_MODE_SEL_SFT               0
+#define RT5651_JD_M_MODE_SEL_M0                        (0x0)
+#define RT5651_JD_M_MODE_SEL_M1                        (0x1)
+#define RT5651_JD_M_MODE_SEL_M2                        (0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5651_JD3_CMP_MASK                    (0x7 << 12)
+#define RT5651_JD3_CMP_SFT                     12
+
+/* EQ Control 1 (0xb0) */
+#define RT5651_EQ_SRC_MASK                     (0x1 << 15)
+#define RT5651_EQ_SRC_SFT                      15
+#define RT5651_EQ_SRC_DAC                      (0x0 << 15)
+#define RT5651_EQ_SRC_ADC                      (0x1 << 15)
+#define RT5651_EQ_UPD                          (0x1 << 14)
+#define RT5651_EQ_UPD_BIT                      14
+#define RT5651_EQ_CD_MASK                      (0x1 << 13)
+#define RT5651_EQ_CD_SFT                       13
+#define RT5651_EQ_CD_DIS                       (0x0 << 13)
+#define RT5651_EQ_CD_EN                                (0x1 << 13)
+#define RT5651_EQ_DITH_MASK                    (0x3 << 8)
+#define RT5651_EQ_DITH_SFT                     8
+#define RT5651_EQ_DITH_NOR                     (0x0 << 8)
+#define RT5651_EQ_DITH_LSB                     (0x1 << 8)
+#define RT5651_EQ_DITH_LSB_1                   (0x2 << 8)
+#define RT5651_EQ_DITH_LSB_2                   (0x3 << 8)
+#define RT5651_EQ_CD_F                         (0x1 << 7)
+#define RT5651_EQ_CD_F_BIT                     7
+#define RT5651_EQ_STA_HP2                      (0x1 << 6)
+#define RT5651_EQ_STA_HP2_BIT                  6
+#define RT5651_EQ_STA_HP1                      (0x1 << 5)
+#define RT5651_EQ_STA_HP1_BIT                  5
+#define RT5651_EQ_STA_BP4                      (0x1 << 4)
+#define RT5651_EQ_STA_BP4_BIT                  4
+#define RT5651_EQ_STA_BP3                      (0x1 << 3)
+#define RT5651_EQ_STA_BP3_BIT                  3
+#define RT5651_EQ_STA_BP2                      (0x1 << 2)
+#define RT5651_EQ_STA_BP2_BIT                  2
+#define RT5651_EQ_STA_BP1                      (0x1 << 1)
+#define RT5651_EQ_STA_BP1_BIT                  1
+#define RT5651_EQ_STA_LP                       (0x1)
+#define RT5651_EQ_STA_LP_BIT                   0
+
+/* EQ Control 2 (0xb1) */
+#define RT5651_EQ_HPF1_M_MASK                  (0x1 << 8)
+#define RT5651_EQ_HPF1_M_SFT                   8
+#define RT5651_EQ_HPF1_M_HI                    (0x0 << 8)
+#define RT5651_EQ_HPF1_M_1ST                   (0x1 << 8)
+#define RT5651_EQ_LPF1_M_MASK                  (0x1 << 7)
+#define RT5651_EQ_LPF1_M_SFT                   7
+#define RT5651_EQ_LPF1_M_LO                    (0x0 << 7)
+#define RT5651_EQ_LPF1_M_1ST                   (0x1 << 7)
+#define RT5651_EQ_HPF2_MASK                    (0x1 << 6)
+#define RT5651_EQ_HPF2_SFT                     6
+#define RT5651_EQ_HPF2_DIS                     (0x0 << 6)
+#define RT5651_EQ_HPF2_EN                      (0x1 << 6)
+#define RT5651_EQ_HPF1_MASK                    (0x1 << 5)
+#define RT5651_EQ_HPF1_SFT                     5
+#define RT5651_EQ_HPF1_DIS                     (0x0 << 5)
+#define RT5651_EQ_HPF1_EN                      (0x1 << 5)
+#define RT5651_EQ_BPF4_MASK                    (0x1 << 4)
+#define RT5651_EQ_BPF4_SFT                     4
+#define RT5651_EQ_BPF4_DIS                     (0x0 << 4)
+#define RT5651_EQ_BPF4_EN                      (0x1 << 4)
+#define RT5651_EQ_BPF3_MASK                    (0x1 << 3)
+#define RT5651_EQ_BPF3_SFT                     3
+#define RT5651_EQ_BPF3_DIS                     (0x0 << 3)
+#define RT5651_EQ_BPF3_EN                      (0x1 << 3)
+#define RT5651_EQ_BPF2_MASK                    (0x1 << 2)
+#define RT5651_EQ_BPF2_SFT                     2
+#define RT5651_EQ_BPF2_DIS                     (0x0 << 2)
+#define RT5651_EQ_BPF2_EN                      (0x1 << 2)
+#define RT5651_EQ_BPF1_MASK                    (0x1 << 1)
+#define RT5651_EQ_BPF1_SFT                     1
+#define RT5651_EQ_BPF1_DIS                     (0x0 << 1)
+#define RT5651_EQ_BPF1_EN                      (0x1 << 1)
+#define RT5651_EQ_LPF_MASK                     (0x1)
+#define RT5651_EQ_LPF_SFT                      0
+#define RT5651_EQ_LPF_DIS                      (0x0)
+#define RT5651_EQ_LPF_EN                       (0x1)
+#define RT5651_EQ_CTRL_MASK                    (0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5651_MT_MASK                         (0x1 << 15)
+#define RT5651_MT_SFT                          15
+#define RT5651_MT_DIS                          (0x0 << 15)
+#define RT5651_MT_EN                           (0x1 << 15)
+
+/* ALC Control 1 (0xb4) */
+#define RT5651_ALC_P_MASK                      (0x1 << 15)
+#define RT5651_ALC_P_SFT                       15
+#define RT5651_ALC_P_DAC                       (0x0 << 15)
+#define RT5651_ALC_P_ADC                       (0x1 << 15)
+#define RT5651_ALC_MASK                                (0x1 << 14)
+#define RT5651_ALC_SFT                         14
+#define RT5651_ALC_DIS                         (0x0 << 14)
+#define RT5651_ALC_EN                          (0x1 << 14)
+#define RT5651_ALC_UPD                         (0x1 << 13)
+#define RT5651_ALC_UPD_BIT                     13
+#define RT5651_ALC_AR_MASK                     (0x1f << 8)
+#define RT5651_ALC_AR_SFT                      8
+#define RT5651_ALC_R_MASK                      (0x7 << 5)
+#define RT5651_ALC_R_SFT                       5
+#define RT5651_ALC_R_48K                       (0x1 << 5)
+#define RT5651_ALC_R_96K                       (0x2 << 5)
+#define RT5651_ALC_R_192K                      (0x3 << 5)
+#define RT5651_ALC_R_441K                      (0x5 << 5)
+#define RT5651_ALC_R_882K                      (0x6 << 5)
+#define RT5651_ALC_R_1764K                     (0x7 << 5)
+#define RT5651_ALC_RC_MASK                     (0x1f)
+#define RT5651_ALC_RC_SFT                      0
+
+/* ALC Control 2 (0xb5) */
+#define RT5651_ALC_POB_MASK                    (0x3f << 8)
+#define RT5651_ALC_POB_SFT                     8
+#define RT5651_ALC_DRC_MASK                    (0x1 << 7)
+#define RT5651_ALC_DRC_SFT                     7
+#define RT5651_ALC_DRC_DIS                     (0x0 << 7)
+#define RT5651_ALC_DRC_EN                      (0x1 << 7)
+#define RT5651_ALC_CPR_MASK                    (0x3 << 5)
+#define RT5651_ALC_CPR_SFT                     5
+#define RT5651_ALC_CPR_1_1                     (0x0 << 5)
+#define RT5651_ALC_CPR_1_2                     (0x1 << 5)
+#define RT5651_ALC_CPR_1_4                     (0x2 << 5)
+#define RT5651_ALC_CPR_1_8                     (0x3 << 5)
+#define RT5651_ALC_PRB_MASK                    (0x1f)
+#define RT5651_ALC_PRB_SFT                     0
+
+/* ALC Control 3 (0xb6) */
+#define RT5651_ALC_NGB_MASK                    (0xf << 12)
+#define RT5651_ALC_NGB_SFT                     12
+#define RT5651_ALC_TAR_MASK                    (0x1f << 7)
+#define RT5651_ALC_TAR_SFT                     7
+#define RT5651_ALC_NG_MASK                     (0x1 << 6)
+#define RT5651_ALC_NG_SFT                      6
+#define RT5651_ALC_NG_DIS                      (0x0 << 6)
+#define RT5651_ALC_NG_EN                       (0x1 << 6)
+#define RT5651_ALC_NGH_MASK                    (0x1 << 5)
+#define RT5651_ALC_NGH_SFT                     5
+#define RT5651_ALC_NGH_DIS                     (0x0 << 5)
+#define RT5651_ALC_NGH_EN                      (0x1 << 5)
+#define RT5651_ALC_NGT_MASK                    (0x1f)
+#define RT5651_ALC_NGT_SFT                     0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5651_JD_MASK                         (0x7 << 13)
+#define RT5651_JD_SFT                          13
+#define RT5651_JD_DIS                          (0x0 << 13)
+#define RT5651_JD_GPIO1                                (0x1 << 13)
+#define RT5651_JD_GPIO2                                (0x2 << 13)
+#define RT5651_JD_GPIO3                                (0x3 << 13)
+#define RT5651_JD_GPIO4                                (0x4 << 13)
+#define RT5651_JD_GPIO5                                (0x5 << 13)
+#define RT5651_JD_GPIO6                                (0x6 << 13)
+#define RT5651_JD_HP_MASK                      (0x1 << 11)
+#define RT5651_JD_HP_SFT                       11
+#define RT5651_JD_HP_DIS                       (0x0 << 11)
+#define RT5651_JD_HP_EN                                (0x1 << 11)
+#define RT5651_JD_HP_TRG_MASK                  (0x1 << 10)
+#define RT5651_JD_HP_TRG_SFT                   10
+#define RT5651_JD_HP_TRG_LO                    (0x0 << 10)
+#define RT5651_JD_HP_TRG_HI                    (0x1 << 10)
+#define RT5651_JD_SPL_MASK                     (0x1 << 9)
+#define RT5651_JD_SPL_SFT                      9
+#define RT5651_JD_SPL_DIS                      (0x0 << 9)
+#define RT5651_JD_SPL_EN                       (0x1 << 9)
+#define RT5651_JD_SPL_TRG_MASK                 (0x1 << 8)
+#define RT5651_JD_SPL_TRG_SFT                  8
+#define RT5651_JD_SPL_TRG_LO                   (0x0 << 8)
+#define RT5651_JD_SPL_TRG_HI                   (0x1 << 8)
+#define RT5651_JD_SPR_MASK                     (0x1 << 7)
+#define RT5651_JD_SPR_SFT                      7
+#define RT5651_JD_SPR_DIS                      (0x0 << 7)
+#define RT5651_JD_SPR_EN                       (0x1 << 7)
+#define RT5651_JD_SPR_TRG_MASK                 (0x1 << 6)
+#define RT5651_JD_SPR_TRG_SFT                  6
+#define RT5651_JD_SPR_TRG_LO                   (0x0 << 6)
+#define RT5651_JD_SPR_TRG_HI                   (0x1 << 6)
+#define RT5651_JD_LO_MASK                      (0x1 << 3)
+#define RT5651_JD_LO_SFT                       3
+#define RT5651_JD_LO_DIS                       (0x0 << 3)
+#define RT5651_JD_LO_EN                                (0x1 << 3)
+#define RT5651_JD_LO_TRG_MASK                  (0x1 << 2)
+#define RT5651_JD_LO_TRG_SFT                   2
+#define RT5651_JD_LO_TRG_LO                    (0x0 << 2)
+#define RT5651_JD_LO_TRG_HI                    (0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5651_JD_TRG_SEL_MASK                 (0x7 << 9)
+#define RT5651_JD_TRG_SEL_SFT                  9
+#define RT5651_JD_TRG_SEL_GPIO                 (0x0 << 9)
+#define RT5651_JD_TRG_SEL_JD1_1                        (0x1 << 9)
+#define RT5651_JD_TRG_SEL_JD1_2                        (0x2 << 9)
+#define RT5651_JD_TRG_SEL_JD2                  (0x3 << 9)
+#define RT5651_JD_TRG_SEL_JD3                  (0x4 << 9)
+#define RT5651_JD3_IRQ_EN                      (0x1 << 8)
+#define RT5651_JD3_IRQ_EN_SFT                  8
+#define RT5651_JD3_EN_STKY                     (0x1 << 7)
+#define RT5651_JD3_EN_STKY_SFT                 7
+#define RT5651_JD3_INV                         (0x1 << 6)
+#define RT5651_JD3_INV_SFT                     6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5651_IRQ_JD_MASK                     (0x1 << 15)
+#define RT5651_IRQ_JD_SFT                      15
+#define RT5651_IRQ_JD_BP                       (0x0 << 15)
+#define RT5651_IRQ_JD_NOR                      (0x1 << 15)
+#define RT5651_JD_STKY_MASK                    (0x1 << 13)
+#define RT5651_JD_STKY_SFT                     13
+#define RT5651_JD_STKY_DIS                     (0x0 << 13)
+#define RT5651_JD_STKY_EN                      (0x1 << 13)
+#define RT5651_JD_P_MASK                       (0x1 << 11)
+#define RT5651_JD_P_SFT                                11
+#define RT5651_JD_P_NOR                                (0x0 << 11)
+#define RT5651_JD_P_INV                                (0x1 << 11)
+#define RT5651_JD1_1_IRQ_EN                    (0x1 << 9)
+#define RT5651_JD1_1_IRQ_EN_SFT                        9
+#define RT5651_JD1_1_EN_STKY                   (0x1 << 8)
+#define RT5651_JD1_1_EN_STKY_SFT                       8
+#define RT5651_JD1_1_INV                       (0x1 << 7)
+#define RT5651_JD1_1_INV_SFT                   7
+#define RT5651_JD1_2_IRQ_EN                    (0x1 << 6)
+#define RT5651_JD1_2_IRQ_EN_SFT                        6
+#define RT5651_JD1_2_EN_STKY                   (0x1 << 5)
+#define RT5651_JD1_2_EN_STKY_SFT                       5
+#define RT5651_JD1_2_INV                       (0x1 << 4)
+#define RT5651_JD1_2_INV_SFT                   4
+#define RT5651_JD2_IRQ_EN                      (0x1 << 3)
+#define RT5651_JD2_IRQ_EN_SFT                  3
+#define RT5651_JD2_EN_STKY                     (0x1 << 2)
+#define RT5651_JD2_EN_STKY_SFT                 2
+#define RT5651_JD2_INV                         (0x1 << 1)
+#define RT5651_JD2_INV_SFT                     1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5651_IRQ_MB1_OC_MASK                 (0x1 << 15)
+#define RT5651_IRQ_MB1_OC_SFT                  15
+#define RT5651_IRQ_MB1_OC_BP                   (0x0 << 15)
+#define RT5651_IRQ_MB1_OC_NOR                  (0x1 << 15)
+#define RT5651_MB1_OC_STKY_MASK                        (0x1 << 11)
+#define RT5651_MB1_OC_STKY_SFT                 11
+#define RT5651_MB1_OC_STKY_DIS                 (0x0 << 11)
+#define RT5651_MB1_OC_STKY_EN                  (0x1 << 11)
+#define RT5651_MB1_OC_P_MASK                   (0x1 << 7)
+#define RT5651_MB1_OC_P_SFT                    7
+#define RT5651_MB1_OC_P_NOR                    (0x0 << 7)
+#define RT5651_MB1_OC_P_INV                    (0x1 << 7)
+#define RT5651_MB2_OC_P_MASK                   (0x1 << 6)
+#define RT5651_MB1_OC_CLR                      (0x1 << 3)
+#define RT5651_MB1_OC_CLR_SFT                  3
+#define RT5651_STA_GPIO8                       (0x1)
+#define RT5651_STA_GPIO8_BIT                   0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5651_STA_JD3                         (0x1 << 15)
+#define RT5651_STA_JD3_BIT                     15
+#define RT5651_STA_JD2                         (0x1 << 14)
+#define RT5651_STA_JD2_BIT                     14
+#define RT5651_STA_JD1_2                       (0x1 << 13)
+#define RT5651_STA_JD1_2_BIT                   13
+#define RT5651_STA_JD1_1                       (0x1 << 12)
+#define RT5651_STA_JD1_1_BIT                   12
+#define RT5651_STA_GP7                         (0x1 << 11)
+#define RT5651_STA_GP7_BIT                     11
+#define RT5651_STA_GP6                         (0x1 << 10)
+#define RT5651_STA_GP6_BIT                     10
+#define RT5651_STA_GP5                         (0x1 << 9)
+#define RT5651_STA_GP5_BIT                     9
+#define RT5651_STA_GP1                         (0x1 << 8)
+#define RT5651_STA_GP1_BIT                     8
+#define RT5651_STA_GP2                         (0x1 << 7)
+#define RT5651_STA_GP2_BIT                     7
+#define RT5651_STA_GP3                         (0x1 << 6)
+#define RT5651_STA_GP3_BIT                     6
+#define RT5651_STA_GP4                         (0x1 << 5)
+#define RT5651_STA_GP4_BIT                     5
+#define RT5651_STA_GP_JD                       (0x1 << 4)
+#define RT5651_STA_GP_JD_BIT                   4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5651_GP1_PIN_MASK                    (0x1 << 15)
+#define RT5651_GP1_PIN_SFT                     15
+#define RT5651_GP1_PIN_GPIO1                   (0x0 << 15)
+#define RT5651_GP1_PIN_IRQ                     (0x1 << 15)
+#define RT5651_GP2_PIN_MASK                    (0x1 << 14)
+#define RT5651_GP2_PIN_SFT                     14
+#define RT5651_GP2_PIN_GPIO2                   (0x0 << 14)
+#define RT5651_GP2_PIN_DMIC1_SCL               (0x1 << 14)
+#define RT5651_GPIO_M_MASK                     (0x1 << 9)
+#define RT5651_GPIO_M_SFT                      9
+#define RT5651_GPIO_M_FLT                      (0x0 << 9)
+#define RT5651_GPIO_M_PH                       (0x1 << 9)
+#define RT5651_I2S2_SEL_MASK                   (0x1 << 8)
+#define RT5651_I2S2_SEL_SFT                    8
+#define RT5651_I2S2_SEL_I2S                    (0x0 << 8)
+#define RT5651_I2S2_SEL_GPIO                   (0x1 << 8)
+#define RT5651_GP5_PIN_MASK                    (0x1 << 7)
+#define RT5651_GP5_PIN_SFT                     7
+#define RT5651_GP5_PIN_GPIO5                   (0x0 << 7)
+#define RT5651_GP5_PIN_IRQ                     (0x1 << 7)
+#define RT5651_GP6_PIN_MASK                    (0x1 << 6)
+#define RT5651_GP6_PIN_SFT                     6
+#define RT5651_GP6_PIN_GPIO6                   (0x0 << 6)
+#define RT5651_GP6_PIN_DMIC_SDA                        (0x1 << 6)
+#define RT5651_GP7_PIN_MASK                    (0x1 << 5)
+#define RT5651_GP7_PIN_SFT                     5
+#define RT5651_GP7_PIN_GPIO7                   (0x0 << 5)
+#define RT5651_GP7_PIN_IRQ                     (0x1 << 5)
+#define RT5651_GP8_PIN_MASK                    (0x1 << 4)
+#define RT5651_GP8_PIN_SFT                     4
+#define RT5651_GP8_PIN_GPIO8                   (0x0 << 4)
+#define RT5651_GP8_PIN_DMIC_SDA                        (0x1 << 4)
+#define RT5651_GPIO_PDM_SEL_MASK               (0x1 << 3)
+#define RT5651_GPIO_PDM_SEL_SFT                        3
+#define RT5651_GPIO_PDM_SEL_GPIO               (0x0 << 3)
+#define RT5651_GPIO_PDM_SEL_PDM                        (0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5651_GP5_DR_MASK                     (0x1 << 14)
+#define RT5651_GP5_DR_SFT                      14
+#define RT5651_GP5_DR_IN                       (0x0 << 14)
+#define RT5651_GP5_DR_OUT                      (0x1 << 14)
+#define RT5651_GP5_OUT_MASK                    (0x1 << 13)
+#define RT5651_GP5_OUT_SFT                     13
+#define RT5651_GP5_OUT_LO                      (0x0 << 13)
+#define RT5651_GP5_OUT_HI                      (0x1 << 13)
+#define RT5651_GP5_P_MASK                      (0x1 << 12)
+#define RT5651_GP5_P_SFT                       12
+#define RT5651_GP5_P_NOR                       (0x0 << 12)
+#define RT5651_GP5_P_INV                       (0x1 << 12)
+#define RT5651_GP4_DR_MASK                     (0x1 << 11)
+#define RT5651_GP4_DR_SFT                      11
+#define RT5651_GP4_DR_IN                       (0x0 << 11)
+#define RT5651_GP4_DR_OUT                      (0x1 << 11)
+#define RT5651_GP4_OUT_MASK                    (0x1 << 10)
+#define RT5651_GP4_OUT_SFT                     10
+#define RT5651_GP4_OUT_LO                      (0x0 << 10)
+#define RT5651_GP4_OUT_HI                      (0x1 << 10)
+#define RT5651_GP4_P_MASK                      (0x1 << 9)
+#define RT5651_GP4_P_SFT                       9
+#define RT5651_GP4_P_NOR                       (0x0 << 9)
+#define RT5651_GP4_P_INV                       (0x1 << 9)
+#define RT5651_GP3_DR_MASK                     (0x1 << 8)
+#define RT5651_GP3_DR_SFT                      8
+#define RT5651_GP3_DR_IN                       (0x0 << 8)
+#define RT5651_GP3_DR_OUT                      (0x1 << 8)
+#define RT5651_GP3_OUT_MASK                    (0x1 << 7)
+#define RT5651_GP3_OUT_SFT                     7
+#define RT5651_GP3_OUT_LO                      (0x0 << 7)
+#define RT5651_GP3_OUT_HI                      (0x1 << 7)
+#define RT5651_GP3_P_MASK                      (0x1 << 6)
+#define RT5651_GP3_P_SFT                       6
+#define RT5651_GP3_P_NOR                       (0x0 << 6)
+#define RT5651_GP3_P_INV                       (0x1 << 6)
+#define RT5651_GP2_DR_MASK                     (0x1 << 5)
+#define RT5651_GP2_DR_SFT                      5
+#define RT5651_GP2_DR_IN                       (0x0 << 5)
+#define RT5651_GP2_DR_OUT                      (0x1 << 5)
+#define RT5651_GP2_OUT_MASK                    (0x1 << 4)
+#define RT5651_GP2_OUT_SFT                     4
+#define RT5651_GP2_OUT_LO                      (0x0 << 4)
+#define RT5651_GP2_OUT_HI                      (0x1 << 4)
+#define RT5651_GP2_P_MASK                      (0x1 << 3)
+#define RT5651_GP2_P_SFT                       3
+#define RT5651_GP2_P_NOR                       (0x0 << 3)
+#define RT5651_GP2_P_INV                       (0x1 << 3)
+#define RT5651_GP1_DR_MASK                     (0x1 << 2)
+#define RT5651_GP1_DR_SFT                      2
+#define RT5651_GP1_DR_IN                       (0x0 << 2)
+#define RT5651_GP1_DR_OUT                      (0x1 << 2)
+#define RT5651_GP1_OUT_MASK                    (0x1 << 1)
+#define RT5651_GP1_OUT_SFT                     1
+#define RT5651_GP1_OUT_LO                      (0x0 << 1)
+#define RT5651_GP1_OUT_HI                      (0x1 << 1)
+#define RT5651_GP1_P_MASK                      (0x1)
+#define RT5651_GP1_P_SFT                       0
+#define RT5651_GP1_P_NOR                       (0x0)
+#define RT5651_GP1_P_INV                       (0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5651_GP8_DR_MASK                     (0x1 << 8)
+#define RT5651_GP8_DR_SFT                      8
+#define RT5651_GP8_DR_IN                       (0x0 << 8)
+#define RT5651_GP8_DR_OUT                      (0x1 << 8)
+#define RT5651_GP8_OUT_MASK                    (0x1 << 7)
+#define RT5651_GP8_OUT_SFT                     7
+#define RT5651_GP8_OUT_LO                      (0x0 << 7)
+#define RT5651_GP8_OUT_HI                      (0x1 << 7)
+#define RT5651_GP8_P_MASK                      (0x1 << 6)
+#define RT5651_GP8_P_SFT                       6
+#define RT5651_GP8_P_NOR                       (0x0 << 6)
+#define RT5651_GP8_P_INV                       (0x1 << 6)
+#define RT5651_GP7_DR_MASK                     (0x1 << 5)
+#define RT5651_GP7_DR_SFT                      5
+#define RT5651_GP7_DR_IN                       (0x0 << 5)
+#define RT5651_GP7_DR_OUT                      (0x1 << 5)
+#define RT5651_GP7_OUT_MASK                    (0x1 << 4)
+#define RT5651_GP7_OUT_SFT                     4
+#define RT5651_GP7_OUT_LO                      (0x0 << 4)
+#define RT5651_GP7_OUT_HI                      (0x1 << 4)
+#define RT5651_GP7_P_MASK                      (0x1 << 3)
+#define RT5651_GP7_P_SFT                       3
+#define RT5651_GP7_P_NOR                       (0x0 << 3)
+#define RT5651_GP7_P_INV                       (0x1 << 3)
+#define RT5651_GP6_DR_MASK                     (0x1 << 2)
+#define RT5651_GP6_DR_SFT                      2
+#define RT5651_GP6_DR_IN                       (0x0 << 2)
+#define RT5651_GP6_DR_OUT                      (0x1 << 2)
+#define RT5651_GP6_OUT_MASK                    (0x1 << 1)
+#define RT5651_GP6_OUT_SFT                     1
+#define RT5651_GP6_OUT_LO                      (0x0 << 1)
+#define RT5651_GP6_OUT_HI                      (0x1 << 1)
+#define RT5651_GP6_P_MASK                      (0x1)
+#define RT5651_GP6_P_SFT                       0
+#define RT5651_GP6_P_NOR                       (0x0)
+#define RT5651_GP6_P_INV                       (0x1)
+
+/* Scramble Control (0xce) */
+#define RT5651_SCB_SWAP_MASK                   (0x1 << 15)
+#define RT5651_SCB_SWAP_SFT                    15
+#define RT5651_SCB_SWAP_DIS                    (0x0 << 15)
+#define RT5651_SCB_SWAP_EN                     (0x1 << 15)
+#define RT5651_SCB_MASK                                (0x1 << 14)
+#define RT5651_SCB_SFT                         14
+#define RT5651_SCB_DIS                         (0x0 << 14)
+#define RT5651_SCB_EN                          (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5651_BB_MASK                         (0x1 << 15)
+#define RT5651_BB_SFT                          15
+#define RT5651_BB_DIS                          (0x0 << 15)
+#define RT5651_BB_EN                           (0x1 << 15)
+#define RT5651_BB_CT_MASK                      (0x7 << 12)
+#define RT5651_BB_CT_SFT                       12
+#define RT5651_BB_CT_A                         (0x0 << 12)
+#define RT5651_BB_CT_B                         (0x1 << 12)
+#define RT5651_BB_CT_C                         (0x2 << 12)
+#define RT5651_BB_CT_D                         (0x3 << 12)
+#define RT5651_M_BB_L_MASK                     (0x1 << 9)
+#define RT5651_M_BB_L_SFT                      9
+#define RT5651_M_BB_R_MASK                     (0x1 << 8)
+#define RT5651_M_BB_R_SFT                      8
+#define RT5651_M_BB_HPF_L_MASK                 (0x1 << 7)
+#define RT5651_M_BB_HPF_L_SFT                  7
+#define RT5651_M_BB_HPF_R_MASK                 (0x1 << 6)
+#define RT5651_M_BB_HPF_R_SFT                  6
+#define RT5651_G_BB_BST_MASK                   (0x3f)
+#define RT5651_G_BB_BST_SFT                    0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5651_M_MP3_L_MASK                    (0x1 << 15)
+#define RT5651_M_MP3_L_SFT                     15
+#define RT5651_M_MP3_R_MASK                    (0x1 << 14)
+#define RT5651_M_MP3_R_SFT                     14
+#define RT5651_M_MP3_MASK                      (0x1 << 13)
+#define RT5651_M_MP3_SFT                       13
+#define RT5651_M_MP3_DIS                       (0x0 << 13)
+#define RT5651_M_MP3_EN                                (0x1 << 13)
+#define RT5651_EG_MP3_MASK                     (0x1f << 8)
+#define RT5651_EG_MP3_SFT                      8
+#define RT5651_MP3_HLP_MASK                    (0x1 << 7)
+#define RT5651_MP3_HLP_SFT                     7
+#define RT5651_MP3_HLP_DIS                     (0x0 << 7)
+#define RT5651_MP3_HLP_EN                      (0x1 << 7)
+#define RT5651_M_MP3_ORG_L_MASK                        (0x1 << 6)
+#define RT5651_M_MP3_ORG_L_SFT                 6
+#define RT5651_M_MP3_ORG_R_MASK                        (0x1 << 5)
+#define RT5651_M_MP3_ORG_R_SFT                 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5651_MP3_WT_MASK                     (0x1 << 13)
+#define RT5651_MP3_WT_SFT                      13
+#define RT5651_MP3_WT_1_4                      (0x0 << 13)
+#define RT5651_MP3_WT_1_2                      (0x1 << 13)
+#define RT5651_OG_MP3_MASK                     (0x1f << 8)
+#define RT5651_OG_MP3_SFT                      8
+#define RT5651_HG_MP3_MASK                     (0x3f)
+#define RT5651_HG_MP3_SFT                      0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5651_3D_CF_MASK                      (0x1 << 15)
+#define RT5651_3D_CF_SFT                       15
+#define RT5651_3D_CF_DIS                       (0x0 << 15)
+#define RT5651_3D_CF_EN                                (0x1 << 15)
+#define RT5651_3D_HP_MASK                      (0x1 << 14)
+#define RT5651_3D_HP_SFT                       14
+#define RT5651_3D_HP_DIS                       (0x0 << 14)
+#define RT5651_3D_HP_EN                                (0x1 << 14)
+#define RT5651_3D_BT_MASK                      (0x1 << 13)
+#define RT5651_3D_BT_SFT                       13
+#define RT5651_3D_BT_DIS                       (0x0 << 13)
+#define RT5651_3D_BT_EN                                (0x1 << 13)
+#define RT5651_3D_1F_MIX_MASK                  (0x3 << 11)
+#define RT5651_3D_1F_MIX_SFT                   11
+#define RT5651_3D_HP_M_MASK                    (0x1 << 10)
+#define RT5651_3D_HP_M_SFT                     10
+#define RT5651_3D_HP_M_SUR                     (0x0 << 10)
+#define RT5651_3D_HP_M_FRO                     (0x1 << 10)
+#define RT5651_M_3D_HRTF_MASK                  (0x1 << 9)
+#define RT5651_M_3D_HRTF_SFT                   9
+#define RT5651_M_3D_D2H_MASK                   (0x1 << 8)
+#define RT5651_M_3D_D2H_SFT                    8
+#define RT5651_M_3D_D2R_MASK                   (0x1 << 7)
+#define RT5651_M_3D_D2R_SFT                    7
+#define RT5651_M_3D_REVB_MASK                  (0x1 << 6)
+#define RT5651_M_3D_REVB_SFT                   6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5651_2ND_HPF_MASK                    (0x1 << 15)
+#define RT5651_2ND_HPF_SFT                     15
+#define RT5651_2ND_HPF_DIS                     (0x0 << 15)
+#define RT5651_2ND_HPF_EN                      (0x1 << 15)
+#define RT5651_HPF_CF_L_MASK                   (0x7 << 12)
+#define RT5651_HPF_CF_L_SFT                    12
+#define RT5651_HPF_CF_R_MASK                   (0x7 << 8)
+#define RT5651_HPF_CF_R_SFT                    8
+#define RT5651_ZD_T_MASK                       (0x3 << 6)
+#define RT5651_ZD_T_SFT                                6
+#define RT5651_ZD_F_MASK                       (0x3 << 4)
+#define RT5651_ZD_F_SFT                                4
+#define RT5651_ZD_F_IM                         (0x0 << 4)
+#define RT5651_ZD_F_ZC_IM                      (0x1 << 4)
+#define RT5651_ZD_F_ZC_IOD                     (0x2 << 4)
+#define RT5651_ZD_F_UN                         (0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5651_HPF_CF_L_NUM_MASK               (0x3f << 8)
+#define RT5651_HPF_CF_L_NUM_SFT                        8
+#define RT5651_HPF_CF_R_NUM_MASK               (0x3f)
+#define RT5651_HPF_CF_R_NUM_SFT                        0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5651_SI_DAC_MASK                     (0x1 << 11)
+#define RT5651_SI_DAC_SFT                      11
+#define RT5651_SI_DAC_AUTO                     (0x0 << 11)
+#define RT5651_SI_DAC_TEST                     (0x1 << 11)
+#define RT5651_DC_CAL_M_MASK                   (0x1 << 10)
+#define RT5651_DC_CAL_M_SFT                    10
+#define RT5651_DC_CAL_M_NOR                    (0x0 << 10)
+#define RT5651_DC_CAL_M_CAL                    (0x1 << 10)
+#define RT5651_DC_CAL_MASK                     (0x1 << 9)
+#define RT5651_DC_CAL_SFT                      9
+#define RT5651_DC_CAL_DIS                      (0x0 << 9)
+#define RT5651_DC_CAL_EN                       (0x1 << 9)
+#define RT5651_HPD_RCV_MASK                    (0x7 << 6)
+#define RT5651_HPD_RCV_SFT                     6
+#define RT5651_HPD_PS_MASK                     (0x1 << 5)
+#define RT5651_HPD_PS_SFT                      5
+#define RT5651_HPD_PS_DIS                      (0x0 << 5)
+#define RT5651_HPD_PS_EN                       (0x1 << 5)
+#define RT5651_CAL_M_MASK                      (0x1 << 4)
+#define RT5651_CAL_M_SFT                       4
+#define RT5651_CAL_M_DEP                       (0x0 << 4)
+#define RT5651_CAL_M_CAL                       (0x1 << 4)
+#define RT5651_CAL_MASK                                (0x1 << 3)
+#define RT5651_CAL_SFT                         3
+#define RT5651_CAL_DIS                         (0x0 << 3)
+#define RT5651_CAL_EN                          (0x1 << 3)
+#define RT5651_CAL_TEST_MASK                   (0x1 << 2)
+#define RT5651_CAL_TEST_SFT                    2
+#define RT5651_CAL_TEST_DIS                    (0x0 << 2)
+#define RT5651_CAL_TEST_EN                     (0x1 << 2)
+#define RT5651_CAL_P_MASK                      (0x3)
+#define RT5651_CAL_P_SFT                       0
+#define RT5651_CAL_P_NONE                      (0x0)
+#define RT5651_CAL_P_CAL                       (0x1)
+#define RT5651_CAL_P_DAC_CAL                   (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5651_SV_MASK                         (0x1 << 15)
+#define RT5651_SV_SFT                          15
+#define RT5651_SV_DIS                          (0x0 << 15)
+#define RT5651_SV_EN                           (0x1 << 15)
+#define RT5651_OUT_SV_MASK                     (0x1 << 13)
+#define RT5651_OUT_SV_SFT                      13
+#define RT5651_OUT_SV_DIS                      (0x0 << 13)
+#define RT5651_OUT_SV_EN                       (0x1 << 13)
+#define RT5651_HP_SV_MASK                      (0x1 << 12)
+#define RT5651_HP_SV_SFT                       12
+#define RT5651_HP_SV_DIS                       (0x0 << 12)
+#define RT5651_HP_SV_EN                                (0x1 << 12)
+#define RT5651_ZCD_DIG_MASK                    (0x1 << 11)
+#define RT5651_ZCD_DIG_SFT                     11
+#define RT5651_ZCD_DIG_DIS                     (0x0 << 11)
+#define RT5651_ZCD_DIG_EN                      (0x1 << 11)
+#define RT5651_ZCD_MASK                                (0x1 << 10)
+#define RT5651_ZCD_SFT                         10
+#define RT5651_ZCD_PD                          (0x0 << 10)
+#define RT5651_ZCD_PU                          (0x1 << 10)
+#define RT5651_M_ZCD_MASK                      (0x3f << 4)
+#define RT5651_M_ZCD_SFT                       4
+#define RT5651_M_ZCD_OM_L                      (0x1 << 7)
+#define RT5651_M_ZCD_OM_R                      (0x1 << 6)
+#define RT5651_M_ZCD_RM_L                      (0x1 << 5)
+#define RT5651_M_ZCD_RM_R                      (0x1 << 4)
+#define RT5651_SV_DLY_MASK                     (0xf)
+#define RT5651_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5651_ZCD_HP_MASK                     (0x1 << 15)
+#define RT5651_ZCD_HP_SFT                      15
+#define RT5651_ZCD_HP_DIS                      (0x0 << 15)
+#define RT5651_ZCD_HP_EN                       (0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5651_I2S2_MS_SP_MASK                 (0x1 << 8)
+#define RT5651_I2S2_MS_SP_SEL                  8
+#define RT5651_I2S2_MS_SP_64                   (0x0 << 8)
+#define RT5651_I2S2_MS_SP_50                   (0x1 << 8)
+#define RT5651_CLK_DET_EN                      (0x1 << 3)
+#define RT5651_CLK_DET_EN_SFT                  3
+#define RT5651_AMP_DET_EN                      (0x1 << 1)
+#define RT5651_AMP_DET_EN_SFT                  1
+#define RT5651_D_GATE_EN                       (0x1)
+#define RT5651_D_GATE_EN_SFT                   0
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5651_3D_SPK_MASK                     (0x1 << 15)
+#define RT5651_3D_SPK_SFT                      15
+#define RT5651_3D_SPK_DIS                      (0x0 << 15)
+#define RT5651_3D_SPK_EN                       (0x1 << 15)
+#define RT5651_3D_SPK_M_MASK                   (0x3 << 13)
+#define RT5651_3D_SPK_M_SFT                    13
+#define RT5651_3D_SPK_CG_MASK                  (0x1f << 8)
+#define RT5651_3D_SPK_CG_SFT                   8
+#define RT5651_3D_SPK_SG_MASK                  (0x1f)
+#define RT5651_3D_SPK_SG_SFT                   0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5651_WND_MASK                                (0x1 << 15)
+#define RT5651_WND_SFT                         15
+#define RT5651_WND_DIS                         (0x0 << 15)
+#define RT5651_WND_EN                          (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5651_WND_FC_NW_MASK                  (0x3f << 10)
+#define RT5651_WND_FC_NW_SFT                   10
+#define RT5651_WND_FC_WK_MASK                  (0x3f << 4)
+#define RT5651_WND_FC_WK_SFT                   4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5651_HPF_FC_MASK                     (0x3f << 6)
+#define RT5651_HPF_FC_SFT                      6
+#define RT5651_WND_FC_ST_MASK                  (0x3f)
+#define RT5651_WND_FC_ST_SFT                   0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5651_WND_TH_LO_MASK                  (0x3ff)
+#define RT5651_WND_TH_LO_SFT                   0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5651_WND_TH_HI_MASK                  (0x3ff)
+#define RT5651_WND_TH_HI_SFT                   0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5651_WND_WIND_MASK                   (0x1 << 13) /* Read-Only */
+#define RT5651_WND_WIND_SFT                    13
+#define RT5651_WND_STRONG_MASK                 (0x1 << 12) /* Read-Only */
+#define RT5651_WND_STRONG_SFT                  12
+enum {
+       RT5651_NO_WIND,
+       RT5651_BREEZE,
+       RT5651_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5651_DP_ATT_MASK                     (0x3 << 14)
+#define RT5651_DP_ATT_SFT                      14
+#define RT5651_DP_SPK_MASK                     (0x1 << 10)
+#define RT5651_DP_SPK_SFT                      10
+#define RT5651_DP_SPK_DIS                      (0x0 << 10)
+#define RT5651_DP_SPK_EN                       (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5651_EQ_PRE_VOL_MASK                 (0xffff)
+#define RT5651_EQ_PRE_VOL_SFT                  0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5651_EQ_PST_VOL_MASK                 (0xffff)
+#define RT5651_EQ_PST_VOL_SFT                  0
+
+/* System Clock Source */
+enum {
+       RT5651_SCLK_S_MCLK,
+       RT5651_SCLK_S_PLL1,
+       RT5651_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+       RT5651_PLL1_S_MCLK,
+       RT5651_PLL1_S_BCLK1,
+       RT5651_PLL1_S_BCLK2,
+};
+
+enum {
+       RT5651_AIF1,
+       RT5651_AIF2,
+       RT5651_AIFS,
+};
+
+struct rt5651_pll_code {
+       bool m_bp; /* Indicates bypass m code or not. */
+       int m_code;
+       int n_code;
+       int k_code;
+};
+
+struct rt5651_priv {
+       struct snd_soc_codec *codec;
+       struct rt5651_platform_data pdata;
+       struct regmap *regmap;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5651_AIFS];
+       int bclk[RT5651_AIFS];
+       int master[RT5651_AIFS];
+
+       struct rt5651_pll_code pll_code;
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+       int dmic_en;
+       bool hp_mute;
+};
+
+#endif /* __RT5651_H__ */
index d3ed1be5a186c50fdaab98e0cf725dce53cb4f32..9626ee0417cd42485ecb59089e7f73075f39cf7e 100644 (file)
@@ -296,7 +296,7 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol,
 static int dac_get_volsw(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int reg;
        int l;
        int r;
@@ -349,7 +349,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol,
 static int dac_put_volsw(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int reg;
        int l;
        int r;
@@ -1322,7 +1322,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
                        return ret;
        }
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
+       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
                                 sgtl5000->supplies);
        if (ret)
                goto err_ldo_remove;
@@ -1330,16 +1330,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
        ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
                                        sgtl5000->supplies);
        if (ret)
-               goto err_regulator_free;
+               goto err_ldo_remove;
 
        /* wait for all power rails bring up */
        udelay(10);
 
        return 0;
 
-err_regulator_free:
-       regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
-                               sgtl5000->supplies);
 err_ldo_remove:
        if (!external_vddd)
                ldo_regulator_remove(codec);
@@ -1409,8 +1406,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
 err:
        regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
                                                sgtl5000->supplies);
-       regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
-                               sgtl5000->supplies);
        ldo_regulator_remove(codec);
 
        return ret;
@@ -1424,8 +1419,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
 
        regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
                                                sgtl5000->supplies);
-       regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
-                               sgtl5000->supplies);
        ldo_regulator_remove(codec);
 
        return 0;
index 244c097cd9053948d43b13c77fee6d6a8b6c7342..f26befb0c297d5f4d99040424195d376e7a384ce 100644 (file)
@@ -208,13 +208,6 @@ out:
        return err;
 }
 
-static int si476x_codec_probe(struct snd_soc_codec *codec)
-{
-       struct regmap *regmap = dev_get_regmap(codec->dev->parent, NULL);
-
-       return snd_soc_codec_set_cache_io(codec, regmap);
-}
-
 static struct snd_soc_dai_ops si476x_dai_ops = {
        .hw_params      = si476x_codec_hw_params,
        .set_fmt        = si476x_codec_set_dai_fmt,
@@ -238,8 +231,13 @@ static struct snd_soc_dai_driver si476x_dai = {
        .ops            = &si476x_dai_ops,
 };
 
+static struct regmap *si476x_get_regmap(struct device *dev)
+{
+       return dev_get_regmap(dev->parent, NULL);
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_si476x = {
-       .probe  = si476x_codec_probe,
+       .get_regmap = si476x_get_regmap,
        .dapm_widgets = si476x_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
        .dapm_routes = si476x_dapm_routes,
index 58e7c1f23771463a04bb38116017891c1b633b81..c5177bc5df820948f19f8e9cf909bd88d1aaec5c 100644 (file)
@@ -279,13 +279,63 @@ static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
        {"Mic input mode mux", "Differential", "MICIN1"},
 };
 
+static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
+{
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+               AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
+       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
+       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+               AUDIO_FIFO_START, AUDIO_FIFO_START);
+       regmap_update_bits(sirf_audio_codec->regmap,
+               AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
+}
+
+static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
+{
+       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+       regmap_update_bits(sirf_audio_codec->regmap,
+               AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
+}
+
+static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
+       int channels)
+{
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+               AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
+       regmap_write(sirf_audio_codec->regmap,
+               AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
+       regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+               AUDIO_FIFO_START, AUDIO_FIFO_START);
+       if (channels == 1)
+               regmap_update_bits(sirf_audio_codec->regmap,
+                       AUDIO_PORT_IC_CODEC_RX_CTRL,
+                       IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
+       else
+               regmap_update_bits(sirf_audio_codec->regmap,
+                       AUDIO_PORT_IC_CODEC_RX_CTRL,
+                       IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
+}
+
+static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
+{
+       regmap_update_bits(sirf_audio_codec->regmap,
+                       AUDIO_PORT_IC_CODEC_RX_CTRL,
+                       IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
+}
+
 static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
                int cmd,
                struct snd_soc_dai *dai)
 {
-       int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        struct snd_soc_codec *codec = dai->codec;
-       u32 val = 0;
+       struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
+       int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
        /*
         * This is a workaround, When stop playback,
@@ -295,20 +345,28 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (playback) {
+                       snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+                               IC_HSLEN | IC_HSREN, 0);
+                       sirf_audio_codec_tx_disable(sirf_audio_codec);
+               } else
+                       sirf_audio_codec_rx_disable(sirf_audio_codec);
                break;
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (playback)
-                       val = IC_HSLEN | IC_HSREN;
+               if (playback) {
+                       sirf_audio_codec_tx_enable(sirf_audio_codec);
+                       snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+                               IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
+               } else
+                       sirf_audio_codec_rx_enable(sirf_audio_codec,
+                               substream->runtime->channels);
                break;
        default:
                return -EINVAL;
        }
 
-       if (playback)
-               snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
-                       IC_HSLEN | IC_HSREN, val);
        return 0;
 }
 
@@ -392,7 +450,7 @@ static const struct regmap_config sirf_audio_codec_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
-       .max_register = AUDIO_IC_CODEC_CTRL3,
+       .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
        .cache_type = REGCACHE_NONE,
 };
 
index d4c187b8e54a3887b3df14da608f9fcb74e73788..ba1adc03839f2347d76919c74af7ac6272684c2a 100644 (file)
 #define IC_RXPGAR              0x7B
 #define IC_RXPGAL              0x7B
 
+#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK     0x3F
+#define AUDIO_PORT_TX_FIFO_SC_OFFSET    0
+#define AUDIO_PORT_TX_FIFO_LC_OFFSET    10
+#define AUDIO_PORT_TX_FIFO_HC_OFFSET    20
+
+#define TX_FIFO_SC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_TX_FIFO_HC_OFFSET)
+
+#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK     0x0F
+#define AUDIO_PORT_RX_FIFO_SC_OFFSET    0
+#define AUDIO_PORT_RX_FIFO_LC_OFFSET    10
+#define AUDIO_PORT_RX_FIFO_HC_OFFSET    20
+
+#define RX_FIFO_SC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_RX_FIFO_HC_OFFSET)
+#define AUDIO_PORT_IC_CODEC_TX_CTRL            (0x00F4)
+#define AUDIO_PORT_IC_CODEC_RX_CTRL            (0x00F8)
+
+#define AUDIO_PORT_IC_TXFIFO_OP                        (0x00FC)
+#define AUDIO_PORT_IC_TXFIFO_LEV_CHK           (0x0100)
+#define AUDIO_PORT_IC_TXFIFO_STS               (0x0104)
+#define AUDIO_PORT_IC_TXFIFO_INT               (0x0108)
+#define AUDIO_PORT_IC_TXFIFO_INT_MSK           (0x010C)
+
+#define AUDIO_PORT_IC_RXFIFO_OP                        (0x0110)
+#define AUDIO_PORT_IC_RXFIFO_LEV_CHK           (0x0114)
+#define AUDIO_PORT_IC_RXFIFO_STS               (0x0118)
+#define AUDIO_PORT_IC_RXFIFO_INT               (0x011C)
+#define AUDIO_PORT_IC_RXFIFO_INT_MSK           (0x0120)
+
+#define AUDIO_FIFO_START               (1 << 0)
+#define AUDIO_FIFO_RESET               (1 << 1)
+
+#define AUDIO_FIFO_FULL                        (1 << 0)
+#define AUDIO_FIFO_EMPTY               (1 << 1)
+#define AUDIO_FIFO_OFLOW               (1 << 2)
+#define AUDIO_FIFO_UFLOW               (1 << 3)
+
+#define IC_TX_ENABLE           (0x03)
+#define IC_RX_ENABLE_MONO      (0x01)
+#define IC_RX_ENABLE_STEREO    (0x03)
+
 #endif /*__SIRF_AUDIO_CODEC_H*/
index 12577749b17b3b0c0b0298b66758934ae4e87bdd..0579d187135b1d3932fd20fa19317f5f76cf43c2 100644 (file)
@@ -243,7 +243,7 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
 static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int numcoef = kcontrol->private_value >> 16;
        int index = kcontrol->private_value & 0xffff;
        unsigned int cfud;
@@ -272,7 +272,7 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
 static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        int numcoef = kcontrol->private_value >> 16;
        int index = kcontrol->private_value & 0xffff;
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
new file mode 100644 (file)
index 0000000..12ebbaf
--- /dev/null
@@ -0,0 +1,1266 @@
+/*
+ * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2014 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * based on code from:
+ *     Raumfeld GmbH
+ *       Johannes Stezenbach <js@sig21.net>
+ *     Wolfson Microelectronics PLC.
+ *       Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *     Freescale Semiconductor, Inc.
+ *       Timur Tabi <timur@freescale.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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/sta350.h>
+#include "sta350.h"
+
+#define STA350_RATES (SNDRV_PCM_RATE_32000 | \
+                     SNDRV_PCM_RATE_44100 | \
+                     SNDRV_PCM_RATE_48000 | \
+                     SNDRV_PCM_RATE_88200 | \
+                     SNDRV_PCM_RATE_96000 | \
+                     SNDRV_PCM_RATE_176400 | \
+                     SNDRV_PCM_RATE_192000)
+
+#define STA350_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+        SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+        SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
+        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* Power-up register defaults */
+static const struct reg_default sta350_regs[] = {
+       {  0x0, 0x63 },
+       {  0x1, 0x80 },
+       {  0x2, 0xdf },
+       {  0x3, 0x40 },
+       {  0x4, 0xc2 },
+       {  0x5, 0x5c },
+       {  0x6, 0x00 },
+       {  0x7, 0xff },
+       {  0x8, 0x60 },
+       {  0x9, 0x60 },
+       {  0xa, 0x60 },
+       {  0xb, 0x00 },
+       {  0xc, 0x00 },
+       {  0xd, 0x00 },
+       {  0xe, 0x00 },
+       {  0xf, 0x40 },
+       { 0x10, 0x80 },
+       { 0x11, 0x77 },
+       { 0x12, 0x6a },
+       { 0x13, 0x69 },
+       { 0x14, 0x6a },
+       { 0x15, 0x69 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+       { 0x18, 0x00 },
+       { 0x19, 0x00 },
+       { 0x1a, 0x00 },
+       { 0x1b, 0x00 },
+       { 0x1c, 0x00 },
+       { 0x1d, 0x00 },
+       { 0x1e, 0x00 },
+       { 0x1f, 0x00 },
+       { 0x20, 0x00 },
+       { 0x21, 0x00 },
+       { 0x22, 0x00 },
+       { 0x23, 0x00 },
+       { 0x24, 0x00 },
+       { 0x25, 0x00 },
+       { 0x26, 0x00 },
+       { 0x27, 0x2a },
+       { 0x28, 0xc0 },
+       { 0x29, 0xf3 },
+       { 0x2a, 0x33 },
+       { 0x2b, 0x00 },
+       { 0x2c, 0x0c },
+       { 0x31, 0x00 },
+       { 0x36, 0x00 },
+       { 0x37, 0x00 },
+       { 0x38, 0x00 },
+       { 0x39, 0x01 },
+       { 0x3a, 0xee },
+       { 0x3b, 0xff },
+       { 0x3c, 0x7e },
+       { 0x3d, 0xc0 },
+       { 0x3e, 0x26 },
+       { 0x3f, 0x00 },
+       { 0x48, 0x00 },
+       { 0x49, 0x00 },
+       { 0x4a, 0x00 },
+       { 0x4b, 0x04 },
+       { 0x4c, 0x00 },
+};
+
+static const struct regmap_range sta350_write_regs_range[] = {
+       regmap_reg_range(STA350_CONFA,  STA350_AUTO2),
+       regmap_reg_range(STA350_C1CFG,  STA350_FDRC2),
+       regmap_reg_range(STA350_EQCFG,  STA350_EVOLRES),
+       regmap_reg_range(STA350_NSHAPE, STA350_MISC2),
+};
+
+static const struct regmap_range sta350_read_regs_range[] = {
+       regmap_reg_range(STA350_CONFA,  STA350_AUTO2),
+       regmap_reg_range(STA350_C1CFG,  STA350_STATUS),
+       regmap_reg_range(STA350_EQCFG,  STA350_EVOLRES),
+       regmap_reg_range(STA350_NSHAPE, STA350_MISC2),
+};
+
+static const struct regmap_range sta350_volatile_regs_range[] = {
+       regmap_reg_range(STA350_CFADDR2, STA350_CFUD),
+       regmap_reg_range(STA350_STATUS,  STA350_STATUS),
+};
+
+static const struct regmap_access_table sta350_write_regs = {
+       .yes_ranges =   sta350_write_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta350_write_regs_range),
+};
+
+static const struct regmap_access_table sta350_read_regs = {
+       .yes_ranges =   sta350_read_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta350_read_regs_range),
+};
+
+static const struct regmap_access_table sta350_volatile_regs = {
+       .yes_ranges =   sta350_volatile_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta350_volatile_regs_range),
+};
+
+/* regulator power supply names */
+static const char * const sta350_supply_names[] = {
+       "vdd-dig",      /* digital supply, 3.3V */
+       "vdd-pll",      /* pll supply, 3.3V */
+       "vcc"           /* power amp supply, 5V - 26V */
+};
+
+/* codec private data */
+struct sta350_priv {
+       struct regmap *regmap;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)];
+       struct sta350_platform_data *pdata;
+
+       unsigned int mclk;
+       unsigned int format;
+
+       u32 coef_shadow[STA350_COEF_COUNT];
+       int shutdown;
+
+       struct gpio_desc *gpiod_nreset;
+       struct gpio_desc *gpiod_power_down;
+
+       struct mutex coeff_lock;
+};
+
+static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0);
+
+static const char * const sta350_drc_ac[] = {
+       "Anti-Clipping", "Dynamic Range Compression"
+};
+static const char * const sta350_auto_gc_mode[] = {
+       "User", "AC no clipping", "AC limited clipping (10%)",
+       "DRC nighttime listening mode"
+};
+static const char * const sta350_auto_xo_mode[] = {
+       "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz",
+       "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz",
+       "340Hz", "360Hz"
+};
+static const char * const sta350_binary_output[] = {
+       "FFX 3-state output - normal operation", "Binary output"
+};
+static const char * const sta350_limiter_select[] = {
+       "Limiter Disabled", "Limiter #1", "Limiter #2"
+};
+static const char * const sta350_limiter_attack_rate[] = {
+       "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
+       "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
+       "0.0645", "0.0564", "0.0501", "0.0451"
+};
+static const char * const sta350_limiter_release_rate[] = {
+       "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
+       "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
+       "0.0134", "0.0117", "0.0110", "0.0104"
+};
+static const char * const sta350_noise_shaper_type[] = {
+       "Third order", "Fourth order"
+};
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv,
+       0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+       8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv,
+       0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
+       3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
+       8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv,
+       0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
+       8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
+       14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv,
+       0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+       1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
+       3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
+       5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
+       13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
+);
+
+static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum,
+                           STA350_CONFD, STA350_CONFD_DRC_SHIFT,
+                           sta350_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum,
+                           STA350_CONFE, STA350_CONFE_NSBW_SHIFT,
+                           sta350_noise_shaper_type);
+static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum,
+                           STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT,
+                           sta350_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum,
+                           STA350_AUTO2, STA350_AUTO2_XO_SHIFT,
+                           sta350_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum,
+                           STA350_C1CFG, STA350_CxCFG_BO_SHIFT,
+                           sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum,
+                           STA350_C2CFG, STA350_CxCFG_BO_SHIFT,
+                           sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum,
+                           STA350_C3CFG, STA350_CxCFG_BO_SHIFT,
+                           sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum,
+                           STA350_C1CFG, STA350_CxCFG_LS_SHIFT,
+                           sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum,
+                           STA350_C2CFG, STA350_CxCFG_LS_SHIFT,
+                           sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum,
+                           STA350_C3CFG, STA350_CxCFG_LS_SHIFT,
+                           sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum,
+                           STA350_L1AR, STA350_LxA_SHIFT,
+                           sta350_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum,
+                           STA350_L2AR, STA350_LxA_SHIFT,
+                           sta350_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum,
+                           STA350_L1AR, STA350_LxR_SHIFT,
+                           sta350_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum,
+                           STA350_L2AR, STA350_LxR_SHIFT,
+                           sta350_limiter_release_rate);
+
+/*
+ * byte array controls for setting biquad, mixer, scaling coefficients;
+ * for biquads all five coefficients need to be set in one go,
+ * mixer and pre/postscale coefs can be set individually;
+ * each coef is 24bit, the bytes are ordered in the same way
+ * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0)
+ */
+
+static int sta350_coefficient_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       int numcoef = kcontrol->private_value >> 16;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = 3 * numcoef;
+       return 0;
+}
+
+static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       int numcoef = kcontrol->private_value >> 16;
+       int index = kcontrol->private_value & 0xffff;
+       unsigned int cfud, val;
+       int i, ret = 0;
+
+       mutex_lock(&sta350->coeff_lock);
+
+       /* preserve reserved bits in STA350_CFUD */
+       regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+       cfud &= 0xf0;
+       /*
+        * chip documentation does not say if the bits are self clearing,
+        * so do it explicitly
+        */
+       regmap_write(sta350->regmap, STA350_CFUD, cfud);
+
+       regmap_write(sta350->regmap, STA350_CFADDR2, index);
+       if (numcoef == 1) {
+               regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04);
+       } else if (numcoef == 5) {
+               regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08);
+       } else {
+               ret = -EINVAL;
+               goto exit_unlock;
+       }
+
+       for (i = 0; i < 3 * numcoef; i++) {
+               regmap_read(sta350->regmap, STA350_B1CF1 + i, &val);
+               ucontrol->value.bytes.data[i] = val;
+       }
+
+exit_unlock:
+       mutex_unlock(&sta350->coeff_lock);
+
+       return ret;
+}
+
+static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       int numcoef = kcontrol->private_value >> 16;
+       int index = kcontrol->private_value & 0xffff;
+       unsigned int cfud;
+       int i;
+
+       /* preserve reserved bits in STA350_CFUD */
+       regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+       cfud &= 0xf0;
+       /*
+        * chip documentation does not say if the bits are self clearing,
+        * so do it explicitly
+        */
+       regmap_write(sta350->regmap, STA350_CFUD, cfud);
+
+       regmap_write(sta350->regmap, STA350_CFADDR2, index);
+       for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++)
+               sta350->coef_shadow[index + i] =
+                         (ucontrol->value.bytes.data[3 * i] << 16)
+                       | (ucontrol->value.bytes.data[3 * i + 1] << 8)
+                       | (ucontrol->value.bytes.data[3 * i + 2]);
+       for (i = 0; i < 3 * numcoef; i++)
+               regmap_write(sta350->regmap, STA350_B1CF1 + i,
+                            ucontrol->value.bytes.data[i]);
+       if (numcoef == 1)
+               regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01);
+       else if (numcoef == 5)
+               regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x02);
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int sta350_sync_coef_shadow(struct snd_soc_codec *codec)
+{
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       unsigned int cfud;
+       int i;
+
+       /* preserve reserved bits in STA350_CFUD */
+       regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+       cfud &= 0xf0;
+
+       for (i = 0; i < STA350_COEF_COUNT; i++) {
+               regmap_write(sta350->regmap, STA350_CFADDR2, i);
+               regmap_write(sta350->regmap, STA350_B1CF1,
+                            (sta350->coef_shadow[i] >> 16) & 0xff);
+               regmap_write(sta350->regmap, STA350_B1CF2,
+                            (sta350->coef_shadow[i] >> 8) & 0xff);
+               regmap_write(sta350->regmap, STA350_B1CF3,
+                            (sta350->coef_shadow[i]) & 0xff);
+               /*
+                * chip documentation does not say if the bits are
+                * self-clearing, so do it explicitly
+                */
+               regmap_write(sta350->regmap, STA350_CFUD, cfud);
+               regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01);
+       }
+       return 0;
+}
+
+static int sta350_cache_sync(struct snd_soc_codec *codec)
+{
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       unsigned int mute;
+       int rc;
+
+       /* mute during register sync */
+       regmap_read(sta350->regmap, STA350_CFUD, &mute);
+       regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE);
+       sta350_sync_coef_shadow(codec);
+       rc = regcache_sync(sta350->regmap);
+       regmap_write(sta350->regmap, STA350_MMUTE, mute);
+       return rc;
+}
+
+#define SINGLE_COEF(xname, index) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = sta350_coefficient_info, \
+       .get = sta350_coefficient_get,\
+       .put = sta350_coefficient_put, \
+       .private_value = index | (1 << 16) }
+
+#define BIQUAD_COEFS(xname, index) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = sta350_coefficient_info, \
+       .get = sta350_coefficient_get,\
+       .put = sta350_coefficient_put, \
+       .private_value = index | (5 << 16) }
+
+static const struct snd_kcontrol_new sta350_snd_controls[] = {
+SOC_SINGLE_TLV("Master Volume", STA350_MVOL, 0, 0xff, 1, mvol_tlv),
+/* VOL */
+SOC_SINGLE_TLV("Ch1 Volume", STA350_C1VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch2 Volume", STA350_C2VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch3 Volume", STA350_C3VOL, 0, 0xff, 1, chvol_tlv),
+/* CONFD */
+SOC_SINGLE("High Pass Filter Bypass Switch",
+          STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1),
+SOC_SINGLE("De-emphasis Filter Switch",
+          STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0),
+SOC_SINGLE("DSP Bypass Switch",
+          STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0),
+SOC_SINGLE("Post-scale Link Switch",
+          STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0),
+SOC_SINGLE("Biquad Coefficient Link Switch",
+          STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0),
+SOC_ENUM("Compressor/Limiter Switch", sta350_drc_ac_enum),
+SOC_ENUM("Noise Shaper Bandwidth", sta350_noise_shaper_enum),
+SOC_SINGLE("Zero-detect Mute Enable Switch",
+          STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0),
+SOC_SINGLE("Submix Mode Switch",
+          STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0),
+/* CONFE */
+SOC_SINGLE("Zero Cross Switch", STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0),
+SOC_SINGLE("Soft Ramp Switch", STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0),
+/* MUTE */
+SOC_SINGLE("Master Switch", STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1),
+SOC_SINGLE("Ch1 Switch", STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1),
+SOC_SINGLE("Ch2 Switch", STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1),
+SOC_SINGLE("Ch3 Switch", STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1),
+/* AUTOx */
+SOC_ENUM("Automode GC", sta350_auto_gc_enum),
+SOC_ENUM("Automode XO", sta350_auto_xo_enum),
+/* CxCFG */
+SOC_SINGLE("Ch1 Tone Control Bypass Switch",
+          STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Tone Control Bypass Switch",
+          STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 EQ Bypass Switch",
+          STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 EQ Bypass Switch",
+          STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 Master Volume Bypass Switch",
+          STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Master Volume Bypass Switch",
+          STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch3 Master Volume Bypass Switch",
+          STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_ENUM("Ch1 Binary Output Select", sta350_binary_output_ch1_enum),
+SOC_ENUM("Ch2 Binary Output Select", sta350_binary_output_ch2_enum),
+SOC_ENUM("Ch3 Binary Output Select", sta350_binary_output_ch3_enum),
+SOC_ENUM("Ch1 Limiter Select", sta350_limiter_ch1_enum),
+SOC_ENUM("Ch2 Limiter Select", sta350_limiter_ch2_enum),
+SOC_ENUM("Ch3 Limiter Select", sta350_limiter_ch3_enum),
+/* TONE */
+SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume",
+                    STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv),
+SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume",
+                    STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv),
+SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta350_limiter1_attack_rate_enum),
+SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta350_limiter2_attack_rate_enum),
+SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta350_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta350_limiter2_release_rate_enum),
+
+/*
+ * depending on mode, the attack/release thresholds have
+ * two different enum definitions; provide both
+ */
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)",
+              STA350_L1ATRT, STA350_LxA_SHIFT,
+              16, 0, sta350_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)",
+              STA350_L2ATRT, STA350_LxA_SHIFT,
+              16, 0, sta350_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)",
+              STA350_L1ATRT, STA350_LxR_SHIFT,
+              16, 0, sta350_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)",
+              STA350_L2ATRT, STA350_LxR_SHIFT,
+              16, 0, sta350_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)",
+              STA350_L1ATRT, STA350_LxA_SHIFT,
+              16, 0, sta350_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)",
+              STA350_L2ATRT, STA350_LxA_SHIFT,
+              16, 0, sta350_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)",
+              STA350_L1ATRT, STA350_LxR_SHIFT,
+              16, 0, sta350_limiter_drc_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)",
+              STA350_L2ATRT, STA350_LxR_SHIFT,
+              16, 0, sta350_limiter_drc_release_tlv),
+
+BIQUAD_COEFS("Ch1 - Biquad 1", 0),
+BIQUAD_COEFS("Ch1 - Biquad 2", 5),
+BIQUAD_COEFS("Ch1 - Biquad 3", 10),
+BIQUAD_COEFS("Ch1 - Biquad 4", 15),
+BIQUAD_COEFS("Ch2 - Biquad 1", 20),
+BIQUAD_COEFS("Ch2 - Biquad 2", 25),
+BIQUAD_COEFS("Ch2 - Biquad 3", 30),
+BIQUAD_COEFS("Ch2 - Biquad 4", 35),
+BIQUAD_COEFS("High-pass", 40),
+BIQUAD_COEFS("Low-pass", 45),
+SINGLE_COEF("Ch1 - Prescale", 50),
+SINGLE_COEF("Ch2 - Prescale", 51),
+SINGLE_COEF("Ch1 - Postscale", 52),
+SINGLE_COEF("Ch2 - Postscale", 53),
+SINGLE_COEF("Ch3 - Postscale", 54),
+SINGLE_COEF("Thermal warning - Postscale", 55),
+SINGLE_COEF("Ch1 - Mix 1", 56),
+SINGLE_COEF("Ch1 - Mix 2", 57),
+SINGLE_COEF("Ch2 - Mix 1", 58),
+SINGLE_COEF("Ch2 - Mix 2", 59),
+SINGLE_COEF("Ch3 - Mix 1", 60),
+SINGLE_COEF("Ch3 - Mix 2", 61),
+};
+
+static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LEFT"),
+SND_SOC_DAPM_OUTPUT("RIGHT"),
+SND_SOC_DAPM_OUTPUT("SUB"),
+};
+
+static const struct snd_soc_dapm_route sta350_dapm_routes[] = {
+       { "LEFT", NULL, "DAC" },
+       { "RIGHT", NULL, "DAC" },
+       { "SUB", NULL, "DAC" },
+       { "DAC", NULL, "Playback" },
+};
+
+/* MCLK interpolation ratio per fs */
+static struct {
+       int fs;
+       int ir;
+} interpolation_ratios[] = {
+       { 32000, 0 },
+       { 44100, 0 },
+       { 48000, 0 },
+       { 88200, 1 },
+       { 96000, 1 },
+       { 176400, 2 },
+       { 192000, 2 },
+};
+
+/* MCLK to fs clock ratios */
+static int mcs_ratio_table[3][6] = {
+       { 768, 512, 384, 256, 128, 576 },
+       { 384, 256, 192, 128,  64,   0 },
+       { 192, 128,  96,  64,  32,   0 },
+};
+
+/**
+ * sta350_set_dai_sysclk - configure MCLK
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the STA350, based on the mcs_ratio_table.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ */
+static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "mclk=%u\n", freq);
+       sta350->mclk = freq;
+
+       return 0;
+}
+
+/**
+ * sta350_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
+ * codec accordingly.
+ */
+static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       unsigned int confb = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               confb |= STA350_CONFB_C2IM;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               confb |= STA350_CONFB_C1IM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(sta350->regmap, STA350_CONFB,
+                                 STA350_CONFB_C1IM | STA350_CONFB_C2IM, confb);
+}
+
+/**
+ * sta350_hw_params - program the STA350 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
+ */
+static int sta350_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       int i, mcs = -EINVAL, ir = -EINVAL;
+       unsigned int confa, confb;
+       unsigned int rate, ratio;
+       int ret;
+
+       if (!sta350->mclk) {
+               dev_err(codec->dev,
+                       "sta350->mclk is unset. Unable to determine ratio\n");
+               return -EIO;
+       }
+
+       rate = params_rate(params);
+       ratio = sta350->mclk / rate;
+       dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+       for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
+               if (interpolation_ratios[i].fs == rate) {
+                       ir = interpolation_ratios[i].ir;
+                       break;
+               }
+       }
+
+       if (ir < 0) {
+               dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 6; i++) {
+               if (mcs_ratio_table[ir][i] == ratio) {
+                       mcs = i;
+                       break;
+               }
+       }
+
+       if (mcs < 0) {
+               dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
+               return -EINVAL;
+       }
+
+       confa = (ir << STA350_CONFA_IR_SHIFT) |
+               (mcs << STA350_CONFA_MCS_SHIFT);
+       confb = 0;
+
+       switch (params_width(params)) {
+       case 24:
+               dev_dbg(codec->dev, "24bit\n");
+               /* fall through */
+       case 32:
+               dev_dbg(codec->dev, "24bit or 32bit\n");
+               switch (sta350->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x0;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0x1;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0x2;
+                       break;
+               }
+
+               break;
+       case 20:
+               dev_dbg(codec->dev, "20bit\n");
+               switch (sta350->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x4;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0x5;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0x6;
+                       break;
+               }
+
+               break;
+       case 18:
+               dev_dbg(codec->dev, "18bit\n");
+               switch (sta350->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x8;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0x9;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0xa;
+                       break;
+               }
+
+               break;
+       case 16:
+               dev_dbg(codec->dev, "16bit\n");
+               switch (sta350->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x0;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0xd;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0xe;
+                       break;
+               }
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(sta350->regmap, STA350_CONFA,
+                                STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK,
+                                confa);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(sta350->regmap, STA350_CONFB,
+                                STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB,
+                                confb);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int sta350_startup_sequence(struct sta350_priv *sta350)
+{
+       if (sta350->gpiod_power_down)
+               gpiod_set_value(sta350->gpiod_power_down, 1);
+
+       if (sta350->gpiod_nreset) {
+               gpiod_set_value(sta350->gpiod_nreset, 0);
+               mdelay(1);
+               gpiod_set_value(sta350->gpiod_nreset, 1);
+               mdelay(1);
+       }
+
+       return 0;
+}
+
+/**
+ * sta350_set_bias_level - DAPM callback
+ * @codec: the codec device
+ * @level: DAPM power level
+ *
+ * This is called by ALSA to put the codec into low power mode
+ * or to wake it up.  If the codec is powered off completely
+ * all registers must be restored after power on.
+ */
+static int sta350_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       dev_dbg(codec->dev, "level = %d\n", level);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* Full power on */
+               regmap_update_bits(sta350->regmap, STA350_CONFF,
+                                  STA350_CONFF_PWDN | STA350_CONFF_EAPD,
+                                  STA350_CONFF_PWDN | STA350_CONFF_EAPD);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(
+                               ARRAY_SIZE(sta350->supplies),
+                               sta350->supplies);
+                       if (ret < 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       sta350_startup_sequence(sta350);
+                       sta350_cache_sync(codec);
+               }
+
+               /* Power down */
+               regmap_update_bits(sta350->regmap, STA350_CONFF,
+                                  STA350_CONFF_PWDN | STA350_CONFF_EAPD,
+                                  0);
+
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* The chip runs through the power down sequence for us */
+               regmap_update_bits(sta350->regmap, STA350_CONFF,
+                                  STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0);
+
+               /* power down: low */
+               if (sta350->gpiod_power_down)
+                       gpiod_set_value(sta350->gpiod_power_down, 0);
+
+               if (sta350->gpiod_nreset)
+                       gpiod_set_value(sta350->gpiod_nreset, 0);
+
+               regulator_bulk_disable(ARRAY_SIZE(sta350->supplies),
+                                      sta350->supplies);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static const struct snd_soc_dai_ops sta350_dai_ops = {
+       .hw_params      = sta350_hw_params,
+       .set_sysclk     = sta350_set_dai_sysclk,
+       .set_fmt        = sta350_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver sta350_dai = {
+       .name = "sta350-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = STA350_RATES,
+               .formats = STA350_FORMATS,
+       },
+       .ops = &sta350_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int sta350_suspend(struct snd_soc_codec *codec)
+{
+       sta350_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int sta350_resume(struct snd_soc_codec *codec)
+{
+       sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define sta350_suspend NULL
+#define sta350_resume NULL
+#endif
+
+static int sta350_probe(struct snd_soc_codec *codec)
+{
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+       struct sta350_platform_data *pdata = sta350->pdata;
+       int i, ret = 0, thermal = 0;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies),
+                                   sta350->supplies);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = sta350_startup_sequence(sta350);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to startup device\n");
+               return ret;
+       }
+
+       /* CONFA */
+       if (!pdata->thermal_warning_recovery)
+               thermal |= STA350_CONFA_TWAB;
+       if (!pdata->thermal_warning_adjustment)
+               thermal |= STA350_CONFA_TWRB;
+       if (!pdata->fault_detect_recovery)
+               thermal |= STA350_CONFA_FDRB;
+       regmap_update_bits(sta350->regmap, STA350_CONFA,
+                          STA350_CONFA_TWAB | STA350_CONFA_TWRB |
+                          STA350_CONFA_FDRB,
+                          thermal);
+
+       /* CONFC */
+       regmap_update_bits(sta350->regmap, STA350_CONFC,
+                          STA350_CONFC_OM_MASK,
+                          pdata->ffx_power_output_mode
+                               << STA350_CONFC_OM_SHIFT);
+       regmap_update_bits(sta350->regmap, STA350_CONFC,
+                          STA350_CONFC_CSZ_MASK,
+                          pdata->drop_compensation_ns
+                               << STA350_CONFC_CSZ_SHIFT);
+       regmap_update_bits(sta350->regmap,
+                          STA350_CONFC,
+                          STA350_CONFC_OCRB,
+                          pdata->oc_warning_adjustment ?
+                               STA350_CONFC_OCRB : 0);
+
+       /* CONFE */
+       regmap_update_bits(sta350->regmap, STA350_CONFE,
+                          STA350_CONFE_MPCV,
+                          pdata->max_power_use_mpcc ?
+                               STA350_CONFE_MPCV : 0);
+       regmap_update_bits(sta350->regmap, STA350_CONFE,
+                          STA350_CONFE_MPC,
+                          pdata->max_power_correction ?
+                               STA350_CONFE_MPC : 0);
+       regmap_update_bits(sta350->regmap, STA350_CONFE,
+                          STA350_CONFE_AME,
+                          pdata->am_reduction_mode ?
+                               STA350_CONFE_AME : 0);
+       regmap_update_bits(sta350->regmap, STA350_CONFE,
+                          STA350_CONFE_PWMS,
+                          pdata->odd_pwm_speed_mode ?
+                               STA350_CONFE_PWMS : 0);
+       regmap_update_bits(sta350->regmap, STA350_CONFE,
+                          STA350_CONFE_DCCV,
+                          pdata->distortion_compensation ?
+                               STA350_CONFE_DCCV : 0);
+       /*  CONFF */
+       regmap_update_bits(sta350->regmap, STA350_CONFF,
+                          STA350_CONFF_IDE,
+                          pdata->invalid_input_detect_mute ?
+                               STA350_CONFF_IDE : 0);
+       regmap_update_bits(sta350->regmap, STA350_CONFF,
+                          STA350_CONFF_OCFG_MASK,
+                          pdata->output_conf
+                               << STA350_CONFF_OCFG_SHIFT);
+
+       /* channel to output mapping */
+       regmap_update_bits(sta350->regmap, STA350_C1CFG,
+                          STA350_CxCFG_OM_MASK,
+                          pdata->ch1_output_mapping
+                               << STA350_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta350->regmap, STA350_C2CFG,
+                          STA350_CxCFG_OM_MASK,
+                          pdata->ch2_output_mapping
+                               << STA350_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta350->regmap, STA350_C3CFG,
+                          STA350_CxCFG_OM_MASK,
+                          pdata->ch3_output_mapping
+                               << STA350_CxCFG_OM_SHIFT);
+
+       /* initialize coefficient shadow RAM with reset values */
+       for (i = 4; i <= 49; i += 5)
+               sta350->coef_shadow[i] = 0x400000;
+       for (i = 50; i <= 54; i++)
+               sta350->coef_shadow[i] = 0x7fffff;
+       sta350->coef_shadow[55] = 0x5a9df7;
+       sta350->coef_shadow[56] = 0x7fffff;
+       sta350->coef_shadow[59] = 0x7fffff;
+       sta350->coef_shadow[60] = 0x400000;
+       sta350->coef_shadow[61] = 0x400000;
+
+       sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       /* Bias level configuration will have done an extra enable */
+       regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
+
+       return 0;
+}
+
+static int sta350_remove(struct snd_soc_codec *codec)
+{
+       struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+
+       sta350_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
+
+       return 0;
+}
+
+static const struct snd_soc_codec_driver sta350_codec = {
+       .probe =                sta350_probe,
+       .remove =               sta350_remove,
+       .suspend =              sta350_suspend,
+       .resume =               sta350_resume,
+       .set_bias_level =       sta350_set_bias_level,
+       .controls =             sta350_snd_controls,
+       .num_controls =         ARRAY_SIZE(sta350_snd_controls),
+       .dapm_widgets =         sta350_dapm_widgets,
+       .num_dapm_widgets =     ARRAY_SIZE(sta350_dapm_widgets),
+       .dapm_routes =          sta350_dapm_routes,
+       .num_dapm_routes =      ARRAY_SIZE(sta350_dapm_routes),
+};
+
+static const struct regmap_config sta350_regmap = {
+       .reg_bits =             8,
+       .val_bits =             8,
+       .max_register =         STA350_MISC2,
+       .reg_defaults =         sta350_regs,
+       .num_reg_defaults =     ARRAY_SIZE(sta350_regs),
+       .cache_type =           REGCACHE_RBTREE,
+       .wr_table =             &sta350_write_regs,
+       .rd_table =             &sta350_read_regs,
+       .volatile_table =       &sta350_volatile_regs,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id st350_dt_ids[] = {
+       { .compatible = "st,sta350", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, st350_dt_ids);
+
+static const char * const sta350_ffx_modes[] = {
+       [STA350_FFX_PM_DROP_COMP]               = "drop-compensation",
+       [STA350_FFX_PM_TAPERED_COMP]            = "tapered-compensation",
+       [STA350_FFX_PM_FULL_POWER]              = "full-power-mode",
+       [STA350_FFX_PM_VARIABLE_DROP_COMP]      = "variable-drop-compensation",
+};
+
+static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
+{
+       struct device_node *np = dev->of_node;
+       struct sta350_platform_data *pdata;
+       const char *ffx_power_mode;
+       u16 tmp;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       of_property_read_u8(np, "st,output-conf",
+                           &pdata->output_conf);
+       of_property_read_u8(np, "st,ch1-output-mapping",
+                           &pdata->ch1_output_mapping);
+       of_property_read_u8(np, "st,ch2-output-mapping",
+                           &pdata->ch2_output_mapping);
+       of_property_read_u8(np, "st,ch3-output-mapping",
+                           &pdata->ch3_output_mapping);
+
+       if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+               pdata->thermal_warning_recovery = 1;
+       if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+               pdata->thermal_warning_adjustment = 1;
+       if (of_get_property(np, "st,fault-detect-recovery", NULL))
+               pdata->fault_detect_recovery = 1;
+
+       pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP;
+       if (!of_property_read_string(np, "st,ffx-power-output-mode",
+                                    &ffx_power_mode)) {
+               int i, mode = -EINVAL;
+
+               for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++)
+                       if (!strcasecmp(ffx_power_mode, sta350_ffx_modes[i]))
+                               mode = i;
+
+               if (mode < 0)
+                       dev_warn(dev, "Unsupported ffx output mode: %s\n",
+                                ffx_power_mode);
+               else
+                       pdata->ffx_power_output_mode = mode;
+       }
+
+       tmp = 140;
+       of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+       pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+       if (of_get_property(np, "st,overcurrent-warning-adjustment", NULL))
+               pdata->oc_warning_adjustment = 1;
+
+       /* CONFE */
+       if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+               pdata->max_power_use_mpcc = 1;
+
+       if (of_get_property(np, "st,max-power-correction", NULL))
+               pdata->max_power_correction = 1;
+
+       if (of_get_property(np, "st,am-reduction-mode", NULL))
+               pdata->am_reduction_mode = 1;
+
+       if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+               pdata->odd_pwm_speed_mode = 1;
+
+       if (of_get_property(np, "st,distortion-compensation", NULL))
+               pdata->distortion_compensation = 1;
+
+       /* CONFF */
+       if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+               pdata->invalid_input_detect_mute = 1;
+
+       sta350->pdata = pdata;
+
+       return 0;
+}
+#endif
+
+static int sta350_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct device *dev = &i2c->dev;
+       struct sta350_priv *sta350;
+       int ret, i;
+
+       sta350 = devm_kzalloc(dev, sizeof(struct sta350_priv), GFP_KERNEL);
+       if (!sta350)
+               return -ENOMEM;
+
+       mutex_init(&sta350->coeff_lock);
+       sta350->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+       if (dev->of_node) {
+               ret = sta350_probe_dt(dev, sta350);
+               if (ret < 0)
+                       return ret;
+       }
+#endif
+
+       /* GPIOs */
+       sta350->gpiod_nreset = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(sta350->gpiod_nreset)) {
+               ret = PTR_ERR(sta350->gpiod_nreset);
+               if (ret != -ENOENT && ret != -ENOSYS)
+                       return ret;
+
+               sta350->gpiod_nreset = NULL;
+       } else {
+               gpiod_direction_output(sta350->gpiod_nreset, 0);
+       }
+
+       sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down");
+       if (IS_ERR(sta350->gpiod_power_down)) {
+               ret = PTR_ERR(sta350->gpiod_power_down);
+               if (ret != -ENOENT && ret != -ENOSYS)
+                       return ret;
+
+               sta350->gpiod_power_down = NULL;
+       } else {
+               gpiod_direction_output(sta350->gpiod_power_down, 0);
+       }
+
+       /* regulators */
+       for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
+               sta350->supplies[i].supply = sta350_supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies),
+                                     sta350->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap);
+       if (IS_ERR(sta350->regmap)) {
+               ret = PTR_ERR(sta350->regmap);
+               dev_err(dev, "Failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, sta350);
+
+       ret = snd_soc_register_codec(dev, &sta350_codec, &sta350_dai, 1);
+       if (ret < 0)
+               dev_err(dev, "Failed to register codec (%d)\n", ret);
+
+       return ret;
+}
+
+static int sta350_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id sta350_i2c_id[] = {
+       { "sta350", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sta350_i2c_id);
+
+static struct i2c_driver sta350_i2c_driver = {
+       .driver = {
+               .name = "sta350",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(st350_dt_ids),
+       },
+       .probe =    sta350_i2c_probe,
+       .remove =   sta350_i2c_remove,
+       .id_table = sta350_i2c_id,
+};
+
+module_i2c_driver(sta350_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC STA350 driver");
+MODULE_AUTHOR("Sven Brandau <info@brandau.biz>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h
new file mode 100644 (file)
index 0000000..c3248f0
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * based on code from:
+ *      Raumfeld GmbH
+ *        Johannes Stezenbach <js@sig21.net>
+ *     Wolfson Microelectronics PLC.
+ *       Mark Brown <broonie@opensource.wolfsonmicro.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 _ASOC_STA_350_H
+#define _ASOC_STA_350_H
+
+/* STA50 register addresses */
+
+#define STA350_REGISTER_COUNT  0x4D
+#define STA350_COEF_COUNT 62
+
+#define STA350_CONFA   0x00
+#define STA350_CONFB    0x01
+#define STA350_CONFC    0x02
+#define STA350_CONFD    0x03
+#define STA350_CONFE    0x04
+#define STA350_CONFF    0x05
+#define STA350_MMUTE    0x06
+#define STA350_MVOL     0x07
+#define STA350_C1VOL    0x08
+#define STA350_C2VOL    0x09
+#define STA350_C3VOL    0x0a
+#define STA350_AUTO1    0x0b
+#define STA350_AUTO2    0x0c
+#define STA350_AUTO3    0x0d
+#define STA350_C1CFG    0x0e
+#define STA350_C2CFG    0x0f
+#define STA350_C3CFG    0x10
+#define STA350_TONE     0x11
+#define STA350_L1AR     0x12
+#define STA350_L1ATRT   0x13
+#define STA350_L2AR     0x14
+#define STA350_L2ATRT   0x15
+#define STA350_CFADDR2  0x16
+#define STA350_B1CF1    0x17
+#define STA350_B1CF2    0x18
+#define STA350_B1CF3    0x19
+#define STA350_B2CF1    0x1a
+#define STA350_B2CF2    0x1b
+#define STA350_B2CF3    0x1c
+#define STA350_A1CF1    0x1d
+#define STA350_A1CF2    0x1e
+#define STA350_A1CF3    0x1f
+#define STA350_A2CF1    0x20
+#define STA350_A2CF2    0x21
+#define STA350_A2CF3    0x22
+#define STA350_B0CF1    0x23
+#define STA350_B0CF2    0x24
+#define STA350_B0CF3    0x25
+#define STA350_CFUD     0x26
+#define STA350_MPCC1    0x27
+#define STA350_MPCC2    0x28
+#define STA350_DCC1     0x29
+#define STA350_DCC2     0x2a
+#define STA350_FDRC1    0x2b
+#define STA350_FDRC2    0x2c
+#define STA350_STATUS   0x2d
+/* reserved: 0x2d - 0x30 */
+#define STA350_EQCFG    0x31
+#define STA350_EATH1    0x32
+#define STA350_ERTH1    0x33
+#define STA350_EATH2    0x34
+#define STA350_ERTH2    0x35
+#define STA350_CONFX    0x36
+#define STA350_SVCA     0x37
+#define STA350_SVCB     0x38
+#define STA350_RMS0A    0x39
+#define STA350_RMS0B    0x3a
+#define STA350_RMS0C    0x3b
+#define STA350_RMS1A    0x3c
+#define STA350_RMS1B    0x3d
+#define STA350_RMS1C    0x3e
+#define STA350_EVOLRES  0x3f
+/* reserved: 0x40 - 0x47 */
+#define STA350_NSHAPE   0x48
+#define STA350_CTXB4B1  0x49
+#define STA350_CTXB7B5  0x4a
+#define STA350_MISC1    0x4b
+#define STA350_MISC2    0x4c
+
+/* 0x00 CONFA */
+#define STA350_CONFA_MCS_MASK  0x03
+#define STA350_CONFA_MCS_SHIFT 0
+#define STA350_CONFA_IR_MASK   0x18
+#define STA350_CONFA_IR_SHIFT  3
+#define STA350_CONFA_TWRB      BIT(5)
+#define STA350_CONFA_TWAB      BIT(6)
+#define STA350_CONFA_FDRB      BIT(7)
+
+/* 0x01 CONFB */
+#define STA350_CONFB_SAI_MASK  0x0f
+#define STA350_CONFB_SAI_SHIFT 0
+#define STA350_CONFB_SAIFB     BIT(4)
+#define STA350_CONFB_DSCKE     BIT(5)
+#define STA350_CONFB_C1IM      BIT(6)
+#define STA350_CONFB_C2IM      BIT(7)
+
+/* 0x02 CONFC */
+#define STA350_CONFC_OM_MASK   0x03
+#define STA350_CONFC_OM_SHIFT  0
+#define STA350_CONFC_CSZ_MASK  0x3c
+#define STA350_CONFC_CSZ_SHIFT 2
+#define STA350_CONFC_OCRB      BIT(7)
+
+/* 0x03 CONFD */
+#define STA350_CONFD_HPB_SHIFT 0
+#define STA350_CONFD_DEMP_SHIFT        1
+#define STA350_CONFD_DSPB_SHIFT        2
+#define STA350_CONFD_PSL_SHIFT 3
+#define STA350_CONFD_BQL_SHIFT 4
+#define STA350_CONFD_DRC_SHIFT 5
+#define STA350_CONFD_ZDE_SHIFT 6
+#define STA350_CONFD_SME_SHIFT 7
+
+/* 0x04 CONFE */
+#define STA350_CONFE_MPCV      BIT(0)
+#define STA350_CONFE_MPCV_SHIFT        0
+#define STA350_CONFE_MPC       BIT(1)
+#define STA350_CONFE_MPC_SHIFT 1
+#define STA350_CONFE_NSBW      BIT(2)
+#define STA350_CONFE_NSBW_SHIFT        2
+#define STA350_CONFE_AME       BIT(3)
+#define STA350_CONFE_AME_SHIFT 3
+#define STA350_CONFE_PWMS      BIT(4)
+#define STA350_CONFE_PWMS_SHIFT        4
+#define STA350_CONFE_DCCV      BIT(5)
+#define STA350_CONFE_DCCV_SHIFT        5
+#define STA350_CONFE_ZCE       BIT(6)
+#define STA350_CONFE_ZCE_SHIFT 6
+#define STA350_CONFE_SVE       BIT(7)
+#define STA350_CONFE_SVE_SHIFT 7
+
+/* 0x05 CONFF */
+#define STA350_CONFF_OCFG_MASK 0x03
+#define STA350_CONFF_OCFG_SHIFT        0
+#define STA350_CONFF_IDE       BIT(2)
+#define STA350_CONFF_BCLE      BIT(3)
+#define STA350_CONFF_LDTE      BIT(4)
+#define STA350_CONFF_ECLE      BIT(5)
+#define STA350_CONFF_PWDN      BIT(6)
+#define STA350_CONFF_EAPD      BIT(7)
+
+/* 0x06 MMUTE */
+#define STA350_MMUTE_MMUTE             0x01
+#define STA350_MMUTE_MMUTE_SHIFT       0
+#define STA350_MMUTE_C1M               0x02
+#define STA350_MMUTE_C1M_SHIFT         1
+#define STA350_MMUTE_C2M               0x04
+#define STA350_MMUTE_C2M_SHIFT         2
+#define STA350_MMUTE_C3M               0x08
+#define STA350_MMUTE_C3M_SHIFT         3
+#define STA350_MMUTE_LOC_MASK          0xC0
+#define STA350_MMUTE_LOC_SHIFT         6
+
+/* 0x0b AUTO1 */
+#define STA350_AUTO1_AMGC_MASK 0x30
+#define STA350_AUTO1_AMGC_SHIFT        4
+
+/* 0x0c AUTO2 */
+#define STA350_AUTO2_AMAME     0x01
+#define STA350_AUTO2_AMAM_MASK 0x0e
+#define STA350_AUTO2_AMAM_SHIFT        1
+#define STA350_AUTO2_XO_MASK   0xf0
+#define STA350_AUTO2_XO_SHIFT  4
+
+/* 0x0d AUTO3 */
+#define STA350_AUTO3_PEQ_MASK  0x1f
+#define STA350_AUTO3_PEQ_SHIFT 0
+
+/* 0x0e 0x0f 0x10 CxCFG */
+#define STA350_CxCFG_TCB_SHIFT 0
+#define STA350_CxCFG_EQBP_SHIFT        1
+#define STA350_CxCFG_VBP_SHIFT 2
+#define STA350_CxCFG_BO_SHIFT  3
+#define STA350_CxCFG_LS_SHIFT  4
+#define STA350_CxCFG_OM_MASK   0xc0
+#define STA350_CxCFG_OM_SHIFT  6
+
+/* 0x11 TONE */
+#define STA350_TONE_BTC_SHIFT  0
+#define STA350_TONE_TTC_SHIFT  4
+
+/* 0x12 0x13 0x14 0x15 limiter attack/release */
+#define STA350_LxA_SHIFT       0
+#define STA350_LxR_SHIFT       4
+
+/* 0x26 CFUD */
+#define STA350_CFUD_W1         0x01
+#define STA350_CFUD_WA         0x02
+#define STA350_CFUD_R1         0x04
+#define STA350_CFUD_RA         0x08
+
+
+/* biquad filter coefficient table offsets */
+#define STA350_C1_BQ_BASE      0
+#define STA350_C2_BQ_BASE      20
+#define STA350_CH_BQ_NUM       4
+#define STA350_BQ_NUM_COEF     5
+#define STA350_XO_HP_BQ_BASE   40
+#define STA350_XO_LP_BQ_BASE   45
+#define STA350_C1_PRESCALE     50
+#define STA350_C2_PRESCALE     51
+#define STA350_C1_POSTSCALE    52
+#define STA350_C2_POSTSCALE    53
+#define STA350_C3_POSTSCALE    54
+#define STA350_TW_POSTSCALE    55
+#define STA350_C1_MIX1         56
+#define STA350_C1_MIX2         57
+#define STA350_C2_MIX1         58
+#define STA350_C2_MIX2         59
+#define STA350_C3_MIX1         60
+#define STA350_C3_MIX2         61
+
+#endif /* _ASOC_STA_350_H */
index a895a5e4bdf207eee6387bc00e8452ae2385233d..d48491a4a19db93d8b496d6f8899d88dd44fa3c0 100644 (file)
@@ -272,7 +272,7 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec)
 static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = priv->deemph;
@@ -283,7 +283,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
 static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
        priv->deemph = ucontrol->value.enumerated.item[0];
index b73c94ebcc2a0de02710b5e9f69c2cbbfdd8b814..f137019954828f2a4d56e9d4c0ad3bd320867faa 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 
index 20864ee8793b5e24be689f6686a2217d9c5c13b9..686b8b85b95696008da32492f9b2108da2f63b1d 100644 (file)
@@ -82,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
 static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        u16 val, reg;
 
        val = (ucontrol->value.integer.value[0] & 0x07);
@@ -105,7 +105,7 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
 static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        u16 val;
 
        val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0);
index fa158cfe9b32d396d09bdb266727c57203c7e62d..23419109ecac10982489fa8b283498dfbea79447 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -376,7 +377,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
                reg = AIC31XX_ADCFLAG;
                break;
        default:
-               dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
+               dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n",
                        w->name, __func__);
                return -EINVAL;
        }
index b1835103e9b4002ab44429d40bb16da8372f65aa..d7349bc89ad3085430b57eb0b67a14ea8b3886e6 100644 (file)
@@ -1399,7 +1399,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
        }
 
        aic3x_add_widgets(codec);
-       list_add(&aic3x->list, &reset_list);
 
        return 0;
 
@@ -1569,7 +1568,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_aic3x, &aic3x_dai, 1);
-       return ret;
+
+       if (ret != 0)
+               goto err_gpio;
+
+       list_add(&aic3x->list, &reset_list);
+
+       return 0;
 
 err_gpio:
        if (gpio_is_valid(aic3x->gpio_reset) &&
index 6bfc8a17331b05c887a80199f05fa4fb38baac31..df3a7506c023b53787d9fa1d8d76d6c0ffb1403b 100644 (file)
@@ -442,7 +442,7 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,
 static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = dac33->fifo_mode;
@@ -453,7 +453,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
 static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
@@ -1540,7 +1540,7 @@ static int dac33_i2c_probe(struct i2c_client *client,
        for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
                dac33->supplies[i].supply = dac33_supply_names[i];
 
-       ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
+       ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
                                 dac33->supplies);
 
        if (ret != 0) {
@@ -1551,11 +1551,9 @@ static int dac33_i2c_probe(struct i2c_client *client,
        ret = snd_soc_register_codec(&client->dev,
                        &soc_codec_dev_tlv320dac33, &dac33_dai, 1);
        if (ret < 0)
-               goto err_register;
+               goto err_get;
 
        return ret;
-err_register:
-       regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
 err_get:
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
@@ -1573,8 +1571,6 @@ static int dac33_i2c_remove(struct i2c_client *client)
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
 
-       regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
-
        snd_soc_unregister_codec(&client->dev);
        return 0;
 }
index b27c396037d4af1c03007b296f9c21b77957265a..8fc5a647453b61c8c7636db58dcd9c182d818a60 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/tpa6130a2-plat.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 
 #include "tpa6130a2.h"
index 975e0f760ac1b74d01289fed1016278ae5c66f8e..69e12a311ba20009fe489960800f95798eecbbc3 100644 (file)
@@ -830,7 +830,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
@@ -859,7 +859,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
@@ -888,7 +888,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -915,7 +915,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -956,7 +956,7 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
 static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->configured) {
index bd3a20647fdff04c0071bc9f77061eea457e77de..0f6067f04e291fa0b323db8ae77bcd31ea420c51 100644 (file)
@@ -484,7 +484,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
 static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
@@ -495,7 +495,7 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
 static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int high_perf = ucontrol->value.enumerated.item[0];
        int ret = 0;
@@ -512,7 +512,7 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
 static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
@@ -523,7 +523,7 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
 static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        priv->pll_power_mode = ucontrol->value.enumerated.item[0];
index 6be5f80b65f1ad632eeab797bfa6349c1ae800dc..4ead0dc02b87428e15e160032e3b9ef8fab6f925 100644 (file)
@@ -172,7 +172,7 @@ out:
 static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = wl1273->mode;
@@ -190,7 +190,7 @@ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
 static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
        if (wl1273->mode == ucontrol->value.integer.value[0])
@@ -214,7 +214,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
 static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
        dev_dbg(codec->dev, "%s: enter.\n", __func__);
@@ -227,7 +227,7 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
 static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
        int val, r = 0;
 
@@ -251,7 +251,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
 static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
        dev_dbg(codec->dev, "%s: enter.\n", __func__);
@@ -264,7 +264,7 @@ static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
 static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
        int r;
 
index 83a2c872925c4bbd9a844ea36f8b5127fd72fd41..a4c352cc3464959bc8be67066ae41fe321e698ab 100644 (file)
@@ -607,7 +607,7 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
 static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
        ucontrol->value.enumerated.item[0] = wm2000->anc_active;
@@ -618,7 +618,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
 static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
        int anc_active = ucontrol->value.enumerated.item[0];
        int ret;
@@ -640,7 +640,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
        ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
@@ -651,7 +651,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
 static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
        int val = ucontrol->value.enumerated.item[0];
        int ret;
index 2e721e06671bd26c7dc65c7f7a546567d3c6d54c..cdea9d9c16317fe3035ac635548eef91fbc365b4 100644 (file)
@@ -1083,7 +1083,7 @@ static int wm2200_mixer_values[] = {
 
 #define WM2200_MUX_CTL_DECL(name) \
        const struct snd_kcontrol_new name##_mux =      \
-               SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+               SOC_DAPM_ENUM("Route", name##_enum)
 
 #define WM2200_MIXER_ENUMS(name, base_reg) \
        static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg);      \
@@ -1207,7 +1207,7 @@ WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
 WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
 
 #define WM2200_MUX(name, ctrl) \
-       SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+       SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
 
 #define WM2200_MIXER_WIDGETS(name, name_str)   \
        WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
index eca983fad8918e2599b5c990eada31b2147ddc17..91a9ea2a205679e451ab4ddf9258404a54322a2a 100644 (file)
@@ -390,7 +390,7 @@ static int wm5100_mixer_values[] = {
 
 #define WM5100_MUX_CTL_DECL(name) \
        const struct snd_kcontrol_new name##_mux =      \
-               SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+               SOC_DAPM_ENUM("Route", name##_enum)
 
 #define WM5100_MIXER_ENUMS(name, base_reg) \
        static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg);      \
@@ -448,7 +448,7 @@ WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE);
 WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);
 
 #define WM5100_MUX(name, ctrl) \
-       SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+       SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
 
 #define WM5100_MIXER_WIDGETS(name, name_str)   \
        WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
index dcf1d12cfef8f7bd5cb835d995eef1cb71e1ad93..289b64d89abd464b562d7dbd56756169ddebaba4 100644 (file)
@@ -764,8 +764,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
-SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
-SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
 
 ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
@@ -814,9 +814,9 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
                 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
                 0xbf, 0, digital_tlv),
 
-SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
-SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
-SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
+SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
+SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
+SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
 
 SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
           ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
@@ -970,7 +970,7 @@ static const struct soc_enum wm5102_aec_loopback =
                              wm5102_aec_loopback_values);
 
 static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
-       SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback);
+       SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback);
 
 static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@ -1204,7 +1204,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
 
 ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
 
-SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
                       &wm5102_aec_loopback_mux),
 
@@ -1760,10 +1760,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
-       if (ret != 0)
-               return ret;
-
        ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
        if (ret != 0)
                return ret;
@@ -1802,9 +1798,17 @@ static unsigned int wm5102_digital_vu[] = {
        ARIZONA_DAC_DIGITAL_VOLUME_5R,
 };
 
+static struct regmap *wm5102_get_regmap(struct device *dev)
+{
+       struct wm5102_priv *priv = dev_get_drvdata(dev);
+
+       return priv->core.arizona->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
        .probe = wm5102_codec_probe,
        .remove = wm5102_codec_remove,
+       .get_regmap = wm5102_get_regmap,
 
        .idle_bias_off = true,
 
index df5a38dd8328db5922a4db96758b50d81e6255ee..2e5fcb559e9000892c59dea01b3b6ee54c1a166a 100644 (file)
@@ -324,13 +324,13 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
-SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
-SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
-SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
-SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
-SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
-SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
-SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
 
 ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
@@ -367,6 +367,11 @@ SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL,
 SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL,
           ARIZONA_HP3_SC_ENA_SHIFT, 1, 0),
 
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+          ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L,
+          ARIZONA_OUT6_OSR_SHIFT, 1, 0),
+
 SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
             ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -592,7 +597,7 @@ static const struct soc_enum wm5110_aec_loopback =
                              wm5110_aec_loopback_values);
 
 static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
-       SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback);
+       SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
 
 static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@ -774,7 +779,7 @@ SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
 SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
                 ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
 
-SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
                       &wm5110_aec_loopback_mux),
 
@@ -1589,10 +1594,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
 
        priv->core.arizona->dapm = &codec->dapm;
 
-       ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
-       if (ret != 0)
-               return ret;
-
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
 
@@ -1633,9 +1634,17 @@ static unsigned int wm5110_digital_vu[] = {
        ARIZONA_DAC_DIGITAL_VOLUME_6R,
 };
 
+static struct regmap *wm5110_get_regmap(struct device *dev)
+{
+       struct wm5110_priv *priv = dev_get_drvdata(dev);
+
+       return priv->core.arizona->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
        .probe = wm5110_codec_probe,
        .remove = wm5110_codec_remove,
+       .get_regmap = wm5110_get_regmap,
 
        .idle_bias_off = true,
 
index 757256bf7672ef9a44d156d895ca0537018ab852..392285edb59545787f336bdc59babdbb5e15e69f 100644 (file)
@@ -302,7 +302,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
 static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out = NULL;
        struct soc_mixer_control *mc =
@@ -345,7 +345,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
 static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out1 = &wm8350_priv->out1;
        struct wm8350_output *out2 = &wm8350_priv->out2;
@@ -1505,8 +1505,6 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        if (ret != 0)
                return ret;
 
-       snd_soc_codec_set_cache_io(codec, wm8350->regmap);
-
        /* Put the codec into reset if it wasn't already */
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
@@ -1608,11 +1606,19 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static struct regmap *wm8350_get_regmap(struct device *dev)
+{
+       struct wm8350 *wm8350 = dev_get_platdata(dev);
+
+       return wm8350->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
        .probe =        wm8350_codec_probe,
        .remove =       wm8350_codec_remove,
        .suspend =      wm8350_suspend,
        .resume =       wm8350_resume,
+       .get_regmap =   wm8350_get_regmap,
        .set_bias_level = wm8350_set_bias_level,
 
        .controls = wm8350_snd_controls,
index 146564feaea04156d8d0d2fe5608390047b4cad0..06e913d3fea15bbfb231fb87b46ee8571e0c7ea8 100644 (file)
@@ -93,7 +93,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
         struct snd_ctl_elem_value *ucontrol)
 {
-        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        int reg = mc->reg;
@@ -1318,8 +1318,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
        priv->wm8400 = wm8400;
        priv->codec = codec;
 
-       snd_soc_codec_set_cache_io(codec, wm8400->regmap);
-
        ret = devm_regulator_bulk_get(wm8400->dev,
                                 ARRAY_SIZE(power), &power[0]);
        if (ret != 0) {
@@ -1361,11 +1359,19 @@ static int  wm8400_codec_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static struct regmap *wm8400_get_regmap(struct device *dev)
+{
+       struct wm8400 *wm8400 = dev_get_platdata(dev);
+
+       return wm8400->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
        .probe =        wm8400_codec_probe,
        .remove =       wm8400_codec_remove,
        .suspend =      wm8400_suspend,
        .resume =       wm8400_resume,
+       .get_regmap =   wm8400_get_regmap,
        .set_bias_level = wm8400_set_bias_level,
 
        .controls = wm8400_snd_controls,
index af7ed8b5d4e187e5b85dc6f3d47b9f7711ca86b2..7665ff6aea6de913081ea1b5ad52c28f518a5cde 100644 (file)
@@ -252,7 +252,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
index d74f43975b90fb3e90a5b7b36b0239e4f6e52aeb..5ada616113240ec8a43075771277d1ca31b030ce 100644 (file)
@@ -119,7 +119,7 @@ static int wm8731_set_deemph(struct snd_soc_codec *codec)
 static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8731->deemph;
@@ -130,7 +130,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
        int ret = 0;
@@ -586,7 +586,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)
        for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
                wm8731->supplies[i].supply = wm8731_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
                                 wm8731->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -597,7 +597,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)
                                    wm8731->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_regulator_get;
+               return ret;
        }
 
        ret = wm8731_reset(codec);
@@ -624,8 +624,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
 
 err_regulator_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-err_regulator_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
        return ret;
 }
@@ -638,7 +636,6 @@ static int wm8731_remove(struct snd_soc_codec *codec)
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-       regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
        return 0;
 }
index cbb8d55052a44a56bcfc22c00d1b64beeeb47da9..53e57b4049a8f559da49621b1d333d6898d10157 100644 (file)
@@ -234,7 +234,7 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
 static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = wm8753->dai_func;
@@ -244,7 +244,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
 static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 ioctl;
 
index ee76f0fb429967c4f563450a111d3ce651540fd0..bbcad9ff3c989d8b907af9109114383202fa8f2a 100644 (file)
@@ -106,7 +106,7 @@ static int txsrc_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec;
        unsigned int src;
 
-       codec = snd_kcontrol_chip(kcontrol);
+       codec = snd_soc_kcontrol_codec(kcontrol);
        src = snd_soc_read(codec, WM8804_SPDTX4);
        if (src & 0x40)
                ucontrol->value.integer.value[0] = 1;
@@ -122,7 +122,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec;
        unsigned int src, txpwr;
 
-       codec = snd_kcontrol_chip(kcontrol);
+       codec = snd_soc_kcontrol_codec(kcontrol);
 
        if (ucontrol->value.integer.value[0] != 0
                        && ucontrol->value.integer.value[0] != 1)
@@ -535,7 +535,6 @@ static int wm8804_remove(struct snd_soc_codec *codec)
        for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
                regulator_unregister_notifier(wm8804->supplies[i].consumer,
                                              &wm8804->disable_nb[i]);
-       regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
        return 0;
 }
 
@@ -549,7 +548,7 @@ static int wm8804_probe(struct snd_soc_codec *codec)
        for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
                wm8804->supplies[i].supply = wm8804_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
+       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
                                 wm8804->supplies);
        if (ret) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -574,7 +573,7 @@ static int wm8804_probe(struct snd_soc_codec *codec)
                                    wm8804->supplies);
        if (ret) {
                dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_reg_get;
+               return ret;
        }
 
        id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
@@ -619,8 +618,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)
 
 err_reg_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
-err_reg_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
        return ret;
 }
 
index b0084a127d18c6214636ed96ef40f3ae8b4b56ae..b84940c359a127fd1330146b21ef50cda605ac0d 100644 (file)
@@ -439,7 +439,7 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec)
 static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8903->deemph;
@@ -450,7 +450,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
        int ret = 0;
index 49c35c36935e45ed478191ac063c8816fd618a27..f7c549949c542203c954cb89b2a1f8552212e98a 100644 (file)
@@ -391,7 +391,7 @@ static void wm8904_set_drc(struct snd_soc_codec *codec)
 static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int value = ucontrol->value.integer.value[0];
@@ -409,7 +409,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
 static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
@@ -462,7 +462,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
 static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int value = ucontrol->value.integer.value[0];
@@ -480,7 +480,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
@@ -520,7 +520,7 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec)
 static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8904->deemph;
@@ -530,7 +530,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
 
@@ -570,7 +570,7 @@ static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
 static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int val;
        int ret;
 
index fecd4e4f4c5731c6d9cbeefaa782bbef632e1daa..2a35108f233dee347317b23c925fc0c50f799976 100644 (file)
@@ -390,7 +390,7 @@ static int wm8955_set_deemph(struct snd_soc_codec *codec)
 static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8955->deemph;
@@ -400,7 +400,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
 
@@ -898,7 +898,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
        for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
                wm8955->supplies[i].supply = wm8955_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
+       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
                                 wm8955->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -909,7 +909,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
                                    wm8955->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
+               return ret;
        }
 
        ret = wm8955_reset(codec);
@@ -961,17 +961,12 @@ static int wm8955_probe(struct snd_soc_codec *codec)
 
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
        return ret;
 }
 
 static int wm8955_remove(struct snd_soc_codec *codec)
 {
-       struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-
        wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
        return 0;
 }
 
index 7ac2e511403ce595963bd38cd9ce48401555f88d..b2ebb104d8794fb14c289b798f6b7b7a7bbcf588 100644 (file)
@@ -456,7 +456,7 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
 static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        int value = ucontrol->value.integer.value[0];
@@ -478,7 +478,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
@@ -500,7 +500,7 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int mbc = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
@@ -512,7 +512,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int mbc = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
@@ -546,7 +546,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        int value = ucontrol->value.integer.value[0];
@@ -568,7 +568,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
@@ -579,7 +579,7 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        int value = ucontrol->value.integer.value[0];
@@ -601,7 +601,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
@@ -623,7 +623,7 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int vss = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
@@ -635,7 +635,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int vss = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
@@ -684,7 +684,7 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int hpf = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        if (hpf < 3)
@@ -699,7 +699,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int hpf = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        if (hpf < 3) {
@@ -746,7 +746,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        int value = ucontrol->value.integer.value[0];
@@ -768,7 +768,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
@@ -790,7 +790,7 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int eq = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
@@ -802,7 +802,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        int eq = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
index d04e9cad445c391046f0d586005668e62d1e997b..a145d0431b63dbc11c975f8b226a6f250ed17008 100644 (file)
@@ -178,7 +178,7 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
 static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.enumerated.item[0] = wm8960->deemph;
@@ -188,7 +188,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
 
index 5522d2566c6742d5ee19f91b4358b30f51276b62..b77e4c3e8484db210ba79e696dd16259fd0c1f3b 100644 (file)
@@ -74,11 +74,9 @@ struct wm8962_priv {
        struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
        struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
 
-#if IS_ENABLED(CONFIG_INPUT)
        struct input_dev *beep;
        struct work_struct beep_work;
        int beep_rate;
-#endif
 
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip gpio_chip;
@@ -1552,7 +1550,7 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
        int shift = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 
        ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
@@ -1564,7 +1562,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
        int shift = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        int old = wm8962->dsp2_ena;
        int ret = 0;
@@ -1602,7 +1600,7 @@ out:
 static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int ret;
 
        /* Apply the update (if any) */
@@ -1632,7 +1630,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
 static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int ret;
 
        /* Apply the update (if any) */
@@ -3145,7 +3143,6 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 }
 EXPORT_SYMBOL_GPL(wm8962_mic_detect);
 
-#if IS_ENABLED(CONFIG_INPUT)
 static int beep_rates[] = {
        500, 1000, 2000, 4000,
 };
@@ -3277,15 +3274,6 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
 
        snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
 }
-#else
-static void wm8962_init_beep(struct snd_soc_codec *codec)
-{
-}
-
-static void wm8962_free_beep(struct snd_soc_codec *codec)
-{
-}
-#endif
 
 static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
 {
index 2b9bfa53efbfeea53d4d8033f10b0d50e4074f38..19d5baa38f5c15e7f53b3430618620ca260f0471 100644 (file)
@@ -552,7 +552,7 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = {
 static int eqmode_get(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg;
 
        reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
@@ -567,7 +567,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
 static int eqmode_put(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int regpwr2, regpwr3;
        unsigned int reg_eq;
 
index 5473dc969585de3852feb6cbbdca7d09b4ace49f..0f5780c09f3a9ad479fd38cc9f78412d46632550 100644 (file)
@@ -526,7 +526,7 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = {
 static int eqmode_get(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg;
 
        reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
@@ -541,7 +541,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
 static int eqmode_put(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int regpwr2, regpwr3;
        unsigned int reg_eq;
 
@@ -984,7 +984,6 @@ static int wm8985_remove(struct snd_soc_codec *codec)
 
        wm8985 = snd_soc_codec_get_drvdata(codec);
        wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
        return 0;
 }
 
@@ -999,7 +998,7 @@ static int wm8985_probe(struct snd_soc_codec *codec)
        for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
                wm8985->supplies[i].supply = wm8985_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
                                 wm8985->supplies);
        if (ret) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -1010,7 +1009,7 @@ static int wm8985_probe(struct snd_soc_codec *codec)
                                    wm8985->supplies);
        if (ret) {
                dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_reg_get;
+               return ret;
        }
 
        ret = wm8985_reset(codec);
@@ -1032,8 +1031,6 @@ static int wm8985_probe(struct snd_soc_codec *codec)
 
 err_reg_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
-err_reg_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
        return ret;
 }
 
index 3a1ae4f5164df1272a517906ed873fc7ff7b2cd0..d3fea46d58e85cb382a7c59a89361850bbd79b9f 100644 (file)
@@ -268,7 +268,7 @@ static const struct soc_enum wm8988_lline_enum =
                              wm8988_line_texts,
                              wm8988_line_values);
 static const struct snd_kcontrol_new wm8988_left_line_controls =
-       SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+       SOC_DAPM_ENUM("Route", wm8988_lline_enum);
 
 static const struct soc_enum wm8988_rline_enum =
        SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7,
@@ -276,7 +276,7 @@ static const struct soc_enum wm8988_rline_enum =
                              wm8988_line_texts,
                              wm8988_line_values);
 static const struct snd_kcontrol_new wm8988_right_line_controls =
-       SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+       SOC_DAPM_ENUM("Route", wm8988_lline_enum);
 
 /* Left Mixer */
 static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = {
@@ -304,7 +304,7 @@ static const struct soc_enum wm8988_lpga_enum =
                              wm8988_pga_sel,
                              wm8988_pga_val);
 static const struct snd_kcontrol_new wm8988_left_pga_controls =
-       SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum);
+       SOC_DAPM_ENUM("Route", wm8988_lpga_enum);
 
 /* Right PGA Mux */
 static const struct soc_enum wm8988_rpga_enum =
@@ -313,7 +313,7 @@ static const struct soc_enum wm8988_rpga_enum =
                              wm8988_pga_sel,
                              wm8988_pga_val);
 static const struct snd_kcontrol_new wm8988_right_pga_controls =
-       SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum);
+       SOC_DAPM_ENUM("Route", wm8988_rpga_enum);
 
 /* Differential Mux */
 static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
index c413c19914534c4fe34e55778a474691743e156f..b5c1f0f070585bd8238178a4187d9b8e567135d4 100644 (file)
@@ -132,7 +132,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        int reg = mc->reg;
index 844cc4a60d667ef8f67dd7b35f29b3834c07b938..b8fd284fc0c023bdb83ea4f87dbc87656608e5d5 100644 (file)
@@ -154,7 +154,7 @@ static const unsigned int out_sidetone_tlv[] = {
 static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int reg = kcontrol->private_value & 0xff;
        int ret;
        u16 val;
index 6303537f54c6d0dde224f7f1c2ee028a7c5c930b..247b39013fba682efa253924a178285e2f7e43ce 100644 (file)
@@ -298,7 +298,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        int mask, ret;
 
        /* Can't enable both ADC and DAC paths simultaneously */
@@ -355,7 +355,7 @@ static int wm8994_get_drc(const char *name)
 static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        struct wm8994_pdata *pdata = &control->pdata;
@@ -378,7 +378,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
 static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int drc = wm8994_get_drc(kcontrol->id.name);
 
@@ -462,7 +462,7 @@ static int wm8994_get_retune_mobile_block(const char *name)
 static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        struct wm8994_pdata *pdata = &control->pdata;
@@ -485,7 +485,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
 
@@ -1347,10 +1347,10 @@ static const char *adc_mux_text[] = {
 static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
 
 static const struct snd_kcontrol_new adcl_mux =
-       SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
+       SOC_DAPM_ENUM("ADCL Mux", adc_enum);
 
 static const struct snd_kcontrol_new adcr_mux =
-       SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum);
+       SOC_DAPM_ENUM("ADCR Mux", adc_enum);
 
 static const struct snd_kcontrol_new left_speaker_mixer[] = {
 SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0),
@@ -1651,15 +1651,15 @@ SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
 };
 
 static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = {
-SND_SOC_DAPM_VIRT_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
+SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
                        adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_VIRT_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
+SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
                        adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
 };
 
 static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = {
-SND_SOC_DAPM_VIRT_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
-SND_SOC_DAPM_VIRT_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
+SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
+SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
@@ -3999,8 +3999,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        wm8994->hubs.codec = codec;
 
-       snd_soc_codec_set_cache_io(codec, control->regmap);
-
        mutex_init(&wm8994->accdet_lock);
        INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
                          wm1811_jackdet_bootstrap);
@@ -4434,11 +4432,19 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static struct regmap *wm8994_get_regmap(struct device *dev)
+{
+       struct wm8994 *control = dev_get_drvdata(dev->parent);
+
+       return control->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
        .probe =        wm8994_codec_probe,
        .remove =       wm8994_codec_remove,
        .suspend =      wm8994_codec_suspend,
        .resume =       wm8994_codec_resume,
+       .get_regmap =   wm8994_get_regmap,
        .set_bias_level = wm8994_set_bias_level,
 };
 
index d3152cf5bd5607490f34b7fe3fdb49915343e4da..863a2c38bcb5934ccd1b98fc393f5d61589c88c7 100644 (file)
@@ -885,10 +885,10 @@ static const char *adc_mux_text[] = {
 static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
 
 static const struct snd_kcontrol_new adcl_mux =
-       SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
+       SOC_DAPM_ENUM("ADCL Mux", adc_enum);
 
 static const struct snd_kcontrol_new adcr_mux =
-       SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum);
+       SOC_DAPM_ENUM("ADCR Mux", adc_enum);
 
 static const char *spk_src_text[] = {
        "DAC1L", "DAC1R", "DAC2L", "DAC2R"
@@ -948,10 +948,8 @@ static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
                0, WM8995_POWER_MANAGEMENT_3, 10, 0),
 
-       SND_SOC_DAPM_VIRT_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0,
-               &adcl_mux),
-       SND_SOC_DAPM_VIRT_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
-               &adcr_mux),
+       SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, &adcl_mux),
+       SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
 
        SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0),
        SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0),
index c6cbb3b8ace96a8d462159d975ae5525b5ac7ed4..69266332760ebad71bed763449afa2f8eb8079a9 100644 (file)
@@ -412,7 +412,7 @@ static int wm8996_get_retune_mobile_block(const char *name)
 static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        struct wm8996_pdata *pdata = &wm8996->pdata;
        int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
@@ -434,7 +434,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
 
index 004186b6bd48131932ac8fceca088548b9df9eb5..bb9b47b956aa519f1b5becb9c2ccc6a75e84fe13 100644 (file)
@@ -245,8 +245,8 @@ SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
 SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
 SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
 
-SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
-SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
 
 ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
@@ -286,8 +286,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
                 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
                 0xbf, 0, digital_tlv),
 
-SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
-SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
+SOC_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
+SOC_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
 
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -405,7 +405,7 @@ static const struct soc_enum wm8997_aec_loopback =
                              wm8997_aec_loopback_values);
 
 static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
-       SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback);
+       SOC_DAPM_ENUM("AEC Loopback", wm8997_aec_loopback);
 
 static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@ -604,7 +604,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
                    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
                    ARIZONA_SLIMRX8_ENA_SHIFT, 0),
 
-SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
                       &wm8997_aec_loopback_mux),
 
@@ -1051,11 +1051,6 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
 static int wm8997_codec_probe(struct snd_soc_codec *codec)
 {
        struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
-       if (ret != 0)
-               return ret;
 
        arizona_init_spk(codec);
 
@@ -1086,9 +1081,17 @@ static unsigned int wm8997_digital_vu[] = {
        ARIZONA_DAC_DIGITAL_VOLUME_5R,
 };
 
+static struct regmap *wm8997_get_regmap(struct device *dev)
+{
+       struct wm8997_priv *priv = dev_get_drvdata(dev);
+
+       return priv->core.arizona->regmap;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
        .probe = wm8997_codec_probe,
        .remove = wm8997_codec_remove,
+       .get_regmap =   wm8997_get_regmap,
 
        .idle_bias_off = true,
 
index d18eff31fbbc618243a9b0db38e603e7af92bb30..185eb97769e730d3a4c7d40ac7abbd8b3046ae32 100644 (file)
@@ -340,7 +340,7 @@ static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
 static int speaker_mode_get(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg;
 
        reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
@@ -361,7 +361,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,
 static int speaker_mode_put(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
        unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
 
index bb5f7b4e3ebbfe016146343c9c1178f568c93517..ff15eec3ab2fc8ebe6f5b674ae5b386997eeffad 100644 (file)
@@ -242,7 +242,7 @@ struct wm_coeff_ctl {
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
 
@@ -254,7 +254,7 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
 
@@ -1625,7 +1625,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
                break;
        default:
                break;
-       };
+       }
 
        return 0;
 }
index b6209662ab13f8c5031908a0408494064d7b5299..916817fe6632f573848f5a7a69bf95aa87072313 100644 (file)
@@ -337,7 +337,7 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
 static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        int ret;
 
index a8ec1fc3e4d09a72ad1e36dca4859208d56e5e7e..50a098749b9e2104d8451a16352b855938ae8366 100644 (file)
@@ -18,7 +18,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM
 
 config SND_AM33XX_SOC_EVM
        tristate "SoC Audio for the AM33XX chip based boards"
-       depends on SND_DAVINCI_SOC && SOC_AM33XX
+       depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
          Say Y or M if you want to add support for SoC audio on AM33XX
@@ -28,7 +28,7 @@ config SND_AM33XX_SOC_EVM
 
 config SND_DAVINCI_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
-       depends on SND_DAVINCI_SOC
+       depends on SND_DAVINCI_SOC && I2C
        depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
@@ -56,7 +56,7 @@ endchoice
 
 config  SND_DM6467_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6467 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
+       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        select SND_SOC_SPDIF
 
@@ -65,7 +65,7 @@ config  SND_DM6467_SOC_EVM
 
 config  SND_DA830_SOC_EVM
        tristate "SoC Audio support for DA830/OMAP-L137 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
+       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
 
        help
@@ -74,7 +74,7 @@ config  SND_DA830_SOC_EVM
 
 config  SND_DA850_SOC_EVM
        tristate "SoC Audio support for DA850/OMAP-L138 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
+       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
          Say Y if you want to add support for SoC audio on TI
index ebe82947bab36d4be3e97c4e2c48552119d2528b..7682af31d6e6f6f4d6dc47ed281f8259962e50a5 100644 (file)
@@ -757,7 +757,6 @@ static int davinci_i2s_remove(struct platform_device *pdev)
        struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_component(&pdev->dev);
-       davinci_soc_platform_unregister(&pdev->dev);
 
        clk_disable(dev->clk);
        clk_put(dev->clk);
index 4f75cac462d1578eed311a0952b305302b369b95..14058dc6eaf8a94194226cfe415fd221e1b43ff4 100644 (file)
@@ -36,6 +36,9 @@
 
 #include "davinci-pcm.h"
 #include "davinci-mcasp.h"
+#include "../omap/omap-pcm.h"
+
+#define MCASP_MAX_AFIFO_DEPTH  64
 
 struct davinci_mcasp_context {
        u32     txfmtctl;
@@ -269,25 +272,51 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
        int ret = 0;
+       u32 data_delay;
+       bool fs_pol_rising;
+       bool inv_fs = false;
 
        pm_runtime_get_sync(mcasp->dev);
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* 1st data bit occur one ACLK cycle after the frame sync */
+               data_delay = 1;
+               break;
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_AC97:
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* No delay after FS */
+               data_delay = 0;
                break;
-       default:
+       case SND_SOC_DAIFMT_I2S:
                /* configure a full-word SYNC pulse (LRCLK) */
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-
-               /* make 1st data bit occur one ACLK cycle after the frame sync */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
+               /* 1st data bit occur one ACLK cycle after the frame sync */
+               data_delay = 1;
+               /* FS need to be inverted */
+               inv_fs = true;
                break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /* configure a full-word SYNC pulse (LRCLK) */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* No delay after FS */
+               data_delay = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
        }
 
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
+                      FSXDLY(3));
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
+                      FSRDLY(3));
+
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
                /* codec is clock and frame slave */
@@ -325,7 +354,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                               ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
                mcasp->bclk_master = 0;
                break;
-
        default:
                ret = -EINVAL;
                goto out;
@@ -334,39 +362,38 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_IB_NF:
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               fs_pol_rising = true;
                break;
-
        case SND_SOC_DAIFMT_NB_IF:
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               fs_pol_rising = false;
                break;
-
        case SND_SOC_DAIFMT_IB_IF:
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               fs_pol_rising = false;
                break;
-
        case SND_SOC_DAIFMT_NB_NF:
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               fs_pol_rising = true;
                break;
-
        default:
                ret = -EINVAL;
-               break;
+               goto out;
+       }
+
+       if (inv_fs)
+               fs_pol_rising = !fs_pol_rising;
+
+       if (fs_pol_rising) {
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+       } else {
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
        }
 out:
        pm_runtime_put_sync(mcasp->dev);
@@ -464,17 +491,19 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
 }
 
 static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
-                                   int channels)
+                                int period_words, int channels)
 {
+       struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
+       struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
        int i;
        u8 tx_ser = 0;
        u8 rx_ser = 0;
-       u8 ser;
        u8 slots = mcasp->tdm_slots;
        u8 max_active_serializers = (channels + slots - 1) / slots;
+       int active_serializers, numevt, n;
        u32 reg;
        /* Default configuration */
-       if (mcasp->version != MCASP_VERSION_4)
+       if (mcasp->version < MCASP_VERSION_3)
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 
        /* All PINS as McASP */
@@ -505,37 +534,71 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                }
        }
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               ser = tx_ser;
-       else
-               ser = rx_ser;
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               active_serializers = tx_ser;
+               numevt = mcasp->txnumevt;
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+       } else {
+               active_serializers = rx_ser;
+               numevt = mcasp->rxnumevt;
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+       }
 
-       if (ser < max_active_serializers) {
+       if (active_serializers < max_active_serializers) {
                dev_warn(mcasp->dev, "stream has more channels (%d) than are "
-                       "enabled in mcasp (%d)\n", channels, ser * slots);
+                        "enabled in mcasp (%d)\n", channels,
+                        active_serializers * slots);
                return -EINVAL;
        }
 
-       if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (mcasp->txnumevt * tx_ser > 64)
-                       mcasp->txnumevt = 1;
-
-               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
-               mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK);
-               mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8),
-                              NUMEVT_MASK);
+       /* AFIFO is not in use */
+       if (!numevt) {
+               /* Configure the burst size for platform drivers */
+               if (active_serializers > 1) {
+                       /*
+                        * If more than one serializers are in use we have one
+                        * DMA request to provide data for all serializers.
+                        * For example if three serializers are enabled the DMA
+                        * need to transfer three words per DMA request.
+                        */
+                       dma_params->fifo_level = active_serializers;
+                       dma_data->maxburst = active_serializers;
+               } else {
+                       dma_params->fifo_level = 0;
+                       dma_data->maxburst = 0;
+               }
+               return 0;
        }
 
-       if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
-               if (mcasp->rxnumevt * rx_ser > 64)
-                       mcasp->rxnumevt = 1;
-
-               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
-               mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK);
-               mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8),
-                              NUMEVT_MASK);
+       if (period_words % active_serializers) {
+               dev_err(mcasp->dev, "Invalid combination of period words and "
+                       "active serializers: %d, %d\n", period_words,
+                       active_serializers);
+               return -EINVAL;
        }
 
+       /*
+        * Calculate the optimal AFIFO depth for platform side:
+        * The number of words for numevt need to be in steps of active
+        * serializers.
+        */
+       n = numevt % active_serializers;
+       if (n)
+               numevt += (active_serializers - n);
+       while (period_words % numevt && numevt > 0)
+               numevt -= active_serializers;
+       if (numevt <= 0)
+               numevt = active_serializers;
+
+       mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
+       mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
+
+       /* Configure the burst size for platform drivers */
+       if (numevt == 1)
+               numevt = 0;
+       dma_params->fifo_level = numevt;
+       dma_data->maxburst = numevt;
+
        return 0;
 }
 
@@ -607,27 +670,24 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
        struct davinci_pcm_dma_params *dma_params =
                                        &mcasp->dma_params[substream->stream];
-       struct snd_dmaengine_dai_dma_data *dma_data =
-                                       &mcasp->dma_data[substream->stream];
        int word_length;
-       u8 fifo_level;
-       u8 slots = mcasp->tdm_slots;
-       u8 active_serializers;
        int channels = params_channels(params);
+       int period_size = params_period_size(params);
        int ret;
 
        /* If mcasp is BCLK master we need to set BCLK divider */
        if (mcasp->bclk_master) {
                unsigned int bclk_freq = snd_soc_params_to_bclk(params);
                if (mcasp->sysclk_freq % bclk_freq != 0) {
-                       dev_err(mcasp->dev, "Can't produce requred BCLK\n");
+                       dev_err(mcasp->dev, "Can't produce required BCLK\n");
                        return -EINVAL;
                }
                davinci_mcasp_set_clkdiv(
                        cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
        }
 
-       ret = mcasp_common_hw_param(mcasp, substream->stream, channels);
+       ret = mcasp_common_hw_param(mcasp, substream->stream,
+                                   period_size * channels, channels);
        if (ret)
                return ret;
 
@@ -671,21 +731,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* Calculate FIFO level */
-       active_serializers = (channels + slots - 1) / slots;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_level = mcasp->txnumevt * active_serializers;
-       else
-               fifo_level = mcasp->rxnumevt * active_serializers;
-
-       if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
+       if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
                dma_params->acnt = 4;
        else
                dma_params->acnt = dma_params->data_type;
 
-       dma_params->fifo_level = fifo_level;
-       dma_data->maxburst = fifo_level;
-
        davinci_config_channel_size(mcasp, word_length);
 
        return 0;
@@ -716,22 +766,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
-                                struct snd_soc_dai *dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
-       if (mcasp->version == MCASP_VERSION_4)
-               snd_soc_dai_set_dma_data(dai, substream,
-                                       &mcasp->dma_data[substream->stream]);
-       else
-               snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params);
-
-       return 0;
-}
-
 static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
-       .startup        = davinci_mcasp_startup,
        .trigger        = davinci_mcasp_trigger,
        .hw_params      = davinci_mcasp_hw_params,
        .set_fmt        = davinci_mcasp_set_dai_fmt,
@@ -739,6 +774,25 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .set_sysclk     = davinci_mcasp_set_sysclk,
 };
 
+static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       if (mcasp->version == MCASP_VERSION_4) {
+               /* Using dmaengine PCM */
+               dai->playback_dma_data =
+                               &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+               dai->capture_dma_data =
+                               &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+       } else {
+               /* Using davinci-pcm */
+               dai->playback_dma_data = mcasp->dma_params;
+               dai->capture_dma_data = mcasp->dma_params;
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
 {
@@ -792,6 +846,7 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
 static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        {
                .name           = "davinci-mcasp.0",
+               .probe          = davinci_mcasp_dai_probe,
                .suspend        = davinci_mcasp_suspend,
                .resume         = davinci_mcasp_resume,
                .playback       = {
@@ -811,6 +866,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        },
        {
                .name           = "davinci-mcasp.1",
+               .probe          = davinci_mcasp_dai_probe,
                .playback       = {
                        .channels_min   = 1,
                        .channels_max   = 384,
@@ -1078,7 +1134,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (!mcasp->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err_release_clk;
+               goto err;
        }
 
        mcasp->op_mode = pdata->op_mode;
@@ -1159,25 +1215,37 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        mcasp_reparent_fck(pdev);
 
-       ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
-                                        &davinci_mcasp_dai[pdata->op_mode], 1);
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                       &davinci_mcasp_component,
+                                       &davinci_mcasp_dai[pdata->op_mode], 1);
 
        if (ret != 0)
-               goto err_release_clk;
+               goto err;
 
-       if (mcasp->version != MCASP_VERSION_4) {
+       switch (mcasp->version) {
+       case MCASP_VERSION_1:
+       case MCASP_VERSION_2:
+       case MCASP_VERSION_3:
                ret = davinci_soc_platform_register(&pdev->dev);
-               if (ret) {
-                       dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-                       goto err_unregister_component;
-               }
+               break;
+       case MCASP_VERSION_4:
+               ret = omap_pcm_platform_register(&pdev->dev);
+               break;
+       default:
+               dev_err(&pdev->dev, "Invalid McASP version: %d\n",
+                       mcasp->version);
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               goto err;
        }
 
        return 0;
 
-err_unregister_component:
-       snd_soc_unregister_component(&pdev->dev);
-err_release_clk:
+err:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return ret;
@@ -1185,12 +1253,6 @@ err_release_clk:
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev);
-
-       snd_soc_unregister_component(&pdev->dev);
-       if (mcasp->version != MCASP_VERSION_4)
-               davinci_soc_platform_unregister(&pdev->dev);
-
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
index 8fed757d60876310ea4138e69a5575feed7cea60..98fbc451892a5e94d851d53001ac89551ed1e3e8 100644 (file)
  */
 #define FIFO_ENABLE    BIT(16)
 #define NUMEVT_MASK    (0xFF << 8)
+#define NUMEVT(x)      (((x) & 0xFF) << 8)
 #define NUMDMA_MASK    (0xFF)
 
 #endif /* DAVINCI_MCASP_H */
index 14145cdf8a11397494af3ac9d09454b88e774163..7809e9d935fc9ca3b0cd3a36abaffac5a15c3a2b 100644 (file)
@@ -852,16 +852,10 @@ static struct snd_soc_platform_driver davinci_soc_platform = {
 
 int davinci_soc_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(dev, &davinci_soc_platform);
+       return devm_snd_soc_register_platform(dev, &davinci_soc_platform);
 }
 EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
 
-void davinci_soc_platform_unregister(struct device *dev)
-{
-       snd_soc_unregister_platform(dev);
-}
-EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister);
-
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
 MODULE_LICENSE("GPL");
index fbb710c76c083ef90b9c442e1776ec00fcb8aa08..0fe2346a9aa29e3064c2d13a86f62add8b0804d1 100644 (file)
@@ -29,7 +29,13 @@ struct davinci_pcm_dma_params {
        unsigned int fifo_level;
 };
 
+#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC)
 int davinci_soc_platform_register(struct device *dev);
-void davinci_soc_platform_unregister(struct device *dev);
+#else
+static inline int davinci_soc_platform_register(struct device *dev)
+{
+       return 0;
+}
+#endif /* CONFIG_SND_DAVINCI_SOC */
 
 #endif
index 30587c0cdbd2cbdd5d876f9d4e1a7e7c266d36a4..77aef05588c3ddcf4641c8ca2139318204a6ef2a 100644 (file)
@@ -258,7 +258,6 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_component(&pdev->dev);
-       davinci_soc_platform_unregister(&pdev->dev);
 
        return 0;
 }
index 338a91642471846fd424a99aa6760406a39532d6..d262ec0653d3709c7e56e9ebce2c2a4bc3796f45 100644 (file)
@@ -1,30 +1,77 @@
+menu "SoC Audio for Freescale CPUs"
+
+comment "Common SoC Audio options for Freescale CPUs:"
+
 config SND_SOC_FSL_SAI
-       tristate
+       tristate "Synchronous Audio Interface (SAI) module support"
        select REGMAP_MMIO
        select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y if you want to add Synchronous Audio Interface (SAI)
+         support for the Freescale CPUs.
+         This option is only useful for out-of-tree drivers since
+         in-tree drivers select it automatically.
 
 config SND_SOC_FSL_SSI
-       tristate
+       tristate "Synchronous Serial Interface module support"
+       select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+       select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC
+       help
+         Say Y if you want to add Synchronous Serial Interface (SSI)
+         support for the Freescale CPUs.
+         This option is only useful for out-of-tree drivers since
+         in-tree drivers select it automatically.
 
 config SND_SOC_FSL_SPDIF
-       tristate
+       tristate "Sony/Philips Digital Interface module support"
        select REGMAP_MMIO
+       select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+       select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC
+       help
+         Say Y if you want to add Sony/Philips Digital Interface (SPDIF)
+         support for the Freescale CPUs.
+         This option is only useful for out-of-tree drivers since
+         in-tree drivers select it automatically.
 
 config SND_SOC_FSL_ESAI
-       tristate
+       tristate "Enhanced Serial Audio Interface (ESAI) module support"
        select REGMAP_MMIO
        select SND_SOC_FSL_UTILS
+       help
+         Say Y if you want to add Enhanced Synchronous Audio Interface
+         (ESAI) support for the Freescale CPUs.
+         This option is only useful for out-of-tree drivers since
+         in-tree drivers select it automatically.
 
 config SND_SOC_FSL_UTILS
        tristate
 
-menuconfig SND_POWERPC_SOC
+config SND_SOC_IMX_PCM_DMA
+       tristate
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_IMX_AUDMUX
+       tristate "Digital Audio Mux module support"
+       help
+         Say Y if you want to add Digital Audio Mux (AUDMUX) support
+         for the ARM i.MX CPUs.
+         This option is only useful for out-of-tree drivers since
+         in-tree drivers select it automatically.
+
+config SND_POWERPC_SOC
        tristate "SoC Audio for Freescale PowerPC CPUs"
        depends on FSL_SOC || PPC_MPC52xx
        help
          Say Y or M if you want to add support for codecs attached to
          the PowerPC CPUs.
 
+config SND_IMX_SOC
+       tristate "SoC Audio for Freescale i.MX CPUs"
+       depends on ARCH_MXC || COMPILE_TEST
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the i.MX CPUs.
+
 if SND_POWERPC_SOC
 
 config SND_MPC52xx_DMA
@@ -33,6 +80,8 @@ config SND_MPC52xx_DMA
 config SND_SOC_POWERPC_DMA
        tristate
 
+comment "SoC Audio support for Freescale PPC boards:"
+
 config SND_SOC_MPC8610_HPCD
        tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
        # I2C is necessary for the CS4270 driver
@@ -110,13 +159,6 @@ config SND_MPC52xx_SOC_EFIKA
 
 endif # SND_POWERPC_SOC
 
-menuconfig SND_IMX_SOC
-       tristate "SoC Audio for Freescale i.MX CPUs"
-       depends on ARCH_MXC || COMPILE_TEST
-       help
-         Say Y or M if you want to add support for codecs attached to
-         the i.MX CPUs.
-
 if SND_IMX_SOC
 
 config SND_SOC_IMX_SSI
@@ -127,12 +169,7 @@ config SND_SOC_IMX_PCM_FIQ
        tristate
        select FIQ
 
-config SND_SOC_IMX_PCM_DMA
-       tristate
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_SOC_IMX_AUDMUX
-       tristate
+comment "SoC Audio support for Freescale i.MX boards:"
 
 config SND_MXC_SOC_WM1133_EV1
        tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
@@ -187,7 +224,7 @@ config SND_SOC_EUKREA_TLV320
 
 config SND_SOC_IMX_WM8962
        tristate "SoC Audio support for i.MX boards with wm8962"
-       depends on OF && I2C
+       depends on OF && I2C && INPUT
        select SND_SOC_WM8962
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_IMX_AUDMUX
@@ -225,3 +262,5 @@ config SND_SOC_IMX_MC13783
        select SND_SOC_IMX_PCM_DMA
 
 endif # SND_IMX_SOC
+
+endmenu
index c8e5db1414d7e75f4077728765a210877f4b3cd9..b49b78df2f5b0ac875a410238262e68329eca1ef 100644 (file)
@@ -209,8 +209,9 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
        struct clk *clksrc = esai_priv->extalclk;
        bool tx = clk_id <= ESAI_HCKT_EXTAL;
        bool in = dir == SND_SOC_CLOCK_IN;
-       u32 ret, ratio, ecr = 0;
+       u32 ratio, ecr = 0;
        unsigned long clk_rate;
+       int ret;
 
        /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
        esai_priv->sck_div[tx] = true;
@@ -432,8 +433,8 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int fsl_esai_startup(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
-       int ret;
        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       int ret;
 
        /*
         * Some platforms might use the same bit to gate all three or two of
@@ -491,7 +492,8 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        u32 width = snd_pcm_format_width(params_format(params));
        u32 channels = params_channels(params);
-       u32 bclk, mask, val, ret;
+       u32 bclk, mask, val;
+       int ret;
 
        bclk = params_rate(params) * esai_priv->slot_width * 2;
 
@@ -816,6 +818,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
 
 static const struct of_device_id fsl_esai_dt_ids[] = {
        { .compatible = "fsl,imx35-esai", },
+       { .compatible = "fsl,vf610-esai", },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
index 56da8c8c5960bd0ef99b405560081580a2bd0571..c5a0e8af8226147bd8b35a3f523756cec69490c8 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/pcm_params.h>
 
 #include "fsl_sai.h"
+#include "imx-pcm.h"
 
 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
                       FSL_SAI_CSR_FEIE)
@@ -30,78 +31,96 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
 {
        struct fsl_sai *sai = (struct fsl_sai *)devid;
        struct device *dev = &sai->pdev->dev;
-       u32 xcsr, mask;
+       u32 flags, xcsr, mask;
+       bool irq_none = true;
 
-       /* Only handle those what we enabled */
+       /*
+        * Both IRQ status bits and IRQ mask bits are in the xCSR but
+        * different shifts. And we here create a mask only for those
+        * IRQs that we activated.
+        */
        mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
 
        /* Tx IRQ */
        regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
-       xcsr &= mask;
+       flags = xcsr & mask;
+
+       if (flags)
+               irq_none = false;
+       else
+               goto irq_rx;
 
-       if (xcsr & FSL_SAI_CSR_WSF)
+       if (flags & FSL_SAI_CSR_WSF)
                dev_dbg(dev, "isr: Start of Tx word detected\n");
 
-       if (xcsr & FSL_SAI_CSR_SEF)
+       if (flags & FSL_SAI_CSR_SEF)
                dev_warn(dev, "isr: Tx Frame sync error detected\n");
 
-       if (xcsr & FSL_SAI_CSR_FEF) {
+       if (flags & FSL_SAI_CSR_FEF) {
                dev_warn(dev, "isr: Transmit underrun detected\n");
                /* FIFO reset for safety */
                xcsr |= FSL_SAI_CSR_FR;
        }
 
-       if (xcsr & FSL_SAI_CSR_FWF)
+       if (flags & FSL_SAI_CSR_FWF)
                dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
 
-       if (xcsr & FSL_SAI_CSR_FRF)
+       if (flags & FSL_SAI_CSR_FRF)
                dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
 
-       regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
-                          FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+       flags &= FSL_SAI_CSR_xF_W_MASK;
+       xcsr &= ~FSL_SAI_CSR_xF_MASK;
+
+       if (flags)
+               regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
 
+irq_rx:
        /* Rx IRQ */
        regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
-       xcsr &= mask;
+       flags = xcsr & mask;
 
-       if (xcsr & FSL_SAI_CSR_WSF)
+       if (flags)
+               irq_none = false;
+       else
+               goto out;
+
+       if (flags & FSL_SAI_CSR_WSF)
                dev_dbg(dev, "isr: Start of Rx word detected\n");
 
-       if (xcsr & FSL_SAI_CSR_SEF)
+       if (flags & FSL_SAI_CSR_SEF)
                dev_warn(dev, "isr: Rx Frame sync error detected\n");
 
-       if (xcsr & FSL_SAI_CSR_FEF) {
+       if (flags & FSL_SAI_CSR_FEF) {
                dev_warn(dev, "isr: Receive overflow detected\n");
                /* FIFO reset for safety */
                xcsr |= FSL_SAI_CSR_FR;
        }
 
-       if (xcsr & FSL_SAI_CSR_FWF)
+       if (flags & FSL_SAI_CSR_FWF)
                dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
 
-       if (xcsr & FSL_SAI_CSR_FRF)
+       if (flags & FSL_SAI_CSR_FRF)
                dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
 
-       regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
-                          FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+       flags &= FSL_SAI_CSR_xF_W_MASK;
+       xcsr &= ~FSL_SAI_CSR_xF_MASK;
+
+       if (flags)
+               regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
 
-       return IRQ_HANDLED;
+out:
+       if (irq_none)
+               return IRQ_NONE;
+       else
+               return IRQ_HANDLED;
 }
 
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int fsl_dir)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 val_cr2, reg_cr2;
-
-       if (fsl_dir == FSL_FMT_TRANSMITTER)
-               reg_cr2 = FSL_SAI_TCR2;
-       else
-               reg_cr2 = FSL_SAI_RCR2;
-
-       regmap_read(sai->regmap, reg_cr2, &val_cr2);
-
-       val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+       bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+       u32 val_cr2 = 0;
 
        switch (clk_id) {
        case FSL_SAI_CLK_BUS:
@@ -120,7 +139,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                return -EINVAL;
        }
 
-       regmap_write(sai->regmap, reg_cr2, val_cr2);
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
+                          FSL_SAI_CR2_MSEL_MASK, val_cr2);
 
        return 0;
 }
@@ -152,22 +172,10 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                                unsigned int fmt, int fsl_dir)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
-
-       if (fsl_dir == FSL_FMT_TRANSMITTER) {
-               reg_cr2 = FSL_SAI_TCR2;
-               reg_cr4 = FSL_SAI_TCR4;
-       } else {
-               reg_cr2 = FSL_SAI_RCR2;
-               reg_cr4 = FSL_SAI_RCR4;
-       }
+       bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+       u32 val_cr2 = 0, val_cr4 = 0;
 
-       regmap_read(sai->regmap, reg_cr2, &val_cr2);
-       regmap_read(sai->regmap, reg_cr4, &val_cr4);
-
-       if (sai->big_endian_data)
-               val_cr4 &= ~FSL_SAI_CR4_MF;
-       else
+       if (!sai->big_endian_data)
                val_cr4 |= FSL_SAI_CR4_MF;
 
        /* DAI mode */
@@ -188,7 +196,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * frame sync asserts with the first bit of the frame.
                 */
                val_cr2 |= FSL_SAI_CR2_BCP;
-               val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
                break;
        case SND_SOC_DAIFMT_DSP_A:
                /*
@@ -198,7 +205,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * data word.
                 */
                val_cr2 |= FSL_SAI_CR2_BCP;
-               val_cr4 &= ~FSL_SAI_CR4_FSP;
                val_cr4 |= FSL_SAI_CR4_FSE;
                sai->is_dsp_mode = true;
                break;
@@ -208,7 +214,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * frame sync asserts with the first bit of the frame.
                 */
                val_cr2 |= FSL_SAI_CR2_BCP;
-               val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
                sai->is_dsp_mode = true;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
@@ -246,23 +251,22 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
-               val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
-               val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
                break;
        case SND_SOC_DAIFMT_CBS_CFM:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
-               val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
-               val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                break;
        default:
                return -EINVAL;
        }
 
-       regmap_write(sai->regmap, reg_cr2, val_cr2);
-       regmap_write(sai->regmap, reg_cr4, val_cr4);
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
+                          FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+                          FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
+                          FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
 
        return 0;
 }
@@ -289,29 +293,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        unsigned int channels = params_channels(params);
        u32 word_width = snd_pcm_format_width(params_format(params));
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               reg_cr4 = FSL_SAI_TCR4;
-               reg_cr5 = FSL_SAI_TCR5;
-               reg_mr = FSL_SAI_TMR;
-       } else {
-               reg_cr4 = FSL_SAI_RCR4;
-               reg_cr5 = FSL_SAI_RCR5;
-               reg_mr = FSL_SAI_RMR;
-       }
-
-       regmap_read(sai->regmap, reg_cr4, &val_cr4);
-       regmap_read(sai->regmap, reg_cr4, &val_cr5);
-
-       val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
-       val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
-
-       val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
-       val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
-       val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+       u32 val_cr4 = 0, val_cr5 = 0;
 
        if (!sai->is_dsp_mode)
                val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
@@ -319,18 +304,20 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        val_cr5 |= FSL_SAI_CR5_WNW(word_width);
        val_cr5 |= FSL_SAI_CR5_W0W(word_width);
 
-       val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
        if (sai->big_endian_data)
                val_cr5 |= FSL_SAI_CR5_FBT(0);
        else
                val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
 
        val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
-       val_mr = ~0UL - ((1 << channels) - 1);
 
-       regmap_write(sai->regmap, reg_cr4, val_cr4);
-       regmap_write(sai->regmap, reg_cr5, val_cr5);
-       regmap_write(sai->regmap, reg_mr, val_mr);
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                          val_cr4);
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx),
+                          FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                          FSL_SAI_CR5_FBT_MASK, val_cr5);
+       regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
 
        return 0;
 }
@@ -339,6 +326,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        u32 tcsr, rcsr;
 
        /*
@@ -353,14 +341,6 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
        regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
        regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               tcsr |= FSL_SAI_CSR_FRDE;
-               rcsr &= ~FSL_SAI_CSR_FRDE;
-       } else {
-               rcsr |= FSL_SAI_CSR_FRDE;
-               tcsr &= ~FSL_SAI_CSR_FRDE;
-       }
-
        /*
         * It is recommended that the transmitter is the last enabled
         * and the first disabled.
@@ -369,22 +349,33 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               tcsr |= FSL_SAI_CSR_TERE;
-               rcsr |= FSL_SAI_CSR_TERE;
+               if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                                          FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                                          FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               }
 
-               regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
-               regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
-                       tcsr &= ~FSL_SAI_CSR_TERE;
-                       rcsr &= ~FSL_SAI_CSR_TERE;
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_FRDE, 0);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_xIE_MASK, 0);
+
+               /* Check if the opposite FRDE is also disabled */
+               if (!(tx ? rcsr & FSL_SAI_CSR_FRDE : tcsr & FSL_SAI_CSR_FRDE)) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                                          FSL_SAI_CSR_TERE, 0);
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                                          FSL_SAI_CSR_TERE, 0);
                }
-
-               regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
-               regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
                break;
        default:
                return -EINVAL;
@@ -397,14 +388,17 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 reg;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       struct device *dev = &sai->pdev->dev;
+       int ret;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               reg = FSL_SAI_TCR3;
-       else
-               reg = FSL_SAI_RCR3;
+       ret = clk_prepare_enable(sai->bus_clk);
+       if (ret) {
+               dev_err(dev, "failed to enable bus clock: %d\n", ret);
+               return ret;
+       }
 
-       regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
                           FSL_SAI_CR3_TRCE);
 
        return 0;
@@ -414,15 +408,11 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 reg;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               reg = FSL_SAI_TCR3;
-       else
-               reg = FSL_SAI_RCR3;
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
 
-       regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
-                          ~FSL_SAI_CR3_TRCE);
+       clk_disable_unprepare(sai->bus_clk);
 }
 
 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -438,8 +428,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
-       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
        regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
                           FSL_SAI_MAXBURST_TX * 2);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -555,7 +545,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
        struct fsl_sai *sai;
        struct resource *res;
        void __iomem *base;
-       int irq, ret;
+       char tmp[8];
+       int irq, ret, i;
 
        sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
        if (!sai)
@@ -563,6 +554,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
        sai->pdev = pdev;
 
+       if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
+               sai->sai_on_imx = true;
+
        sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
        if (sai->big_endian_regs)
                fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -575,12 +569,35 @@ static int fsl_sai_probe(struct platform_device *pdev)
                return PTR_ERR(base);
 
        sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
-                       "sai", base, &fsl_sai_regmap_config);
+                       "bus", base, &fsl_sai_regmap_config);
+
+       /* Compatible with old DTB cases */
+       if (IS_ERR(sai->regmap))
+               sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                               "sai", base, &fsl_sai_regmap_config);
        if (IS_ERR(sai->regmap)) {
                dev_err(&pdev->dev, "regmap init failed\n");
                return PTR_ERR(sai->regmap);
        }
 
+       /* No error out for old DTB cases but only mark the clock NULL */
+       sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       if (IS_ERR(sai->bus_clk)) {
+               dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
+                               PTR_ERR(sai->bus_clk));
+               sai->bus_clk = NULL;
+       }
+
+       for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
+               sprintf(tmp, "mclk%d", i + 1);
+               sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+               if (IS_ERR(sai->mclk_clk[i])) {
+                       dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
+                                       i + 1, PTR_ERR(sai->mclk_clk[i]));
+                       sai->mclk_clk[i] = NULL;
+               }
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
@@ -605,12 +622,16 @@ static int fsl_sai_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
-                       SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+       if (sai->sai_on_imx)
+               return imx_pcm_dma_init(pdev);
+       else
+               return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+                               SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
 }
 
 static const struct of_device_id fsl_sai_ids[] = {
        { .compatible = "fsl,vf610-sai", },
+       { .compatible = "fsl,imx6sx-sai", },
        { /* sentinel */ }
 };
 
index a264185c7138508451b602e7ece7d89d354b2ff1..0e6c9f595d7550957eabc534174b7a14b2056422 100644 (file)
 #define FSL_SAI_RFR    0xc0 /* SAI Receive FIFO */
 #define FSL_SAI_RMR    0xe0 /* SAI Receive Mask */
 
+#define FSL_SAI_xCSR(tx)       (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR)
+#define FSL_SAI_xCR1(tx)       (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1)
+#define FSL_SAI_xCR2(tx)       (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2)
+#define FSL_SAI_xCR3(tx)       (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3)
+#define FSL_SAI_xCR4(tx)       (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4)
+#define FSL_SAI_xCR5(tx)       (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5)
+#define FSL_SAI_xDR(tx)                (tx ? FSL_SAI_TDR : FSL_SAI_RDR)
+#define FSL_SAI_xFR(tx)                (tx ? FSL_SAI_TFR : FSL_SAI_RFR)
+#define FSL_SAI_xMR(tx)                (tx ? FSL_SAI_TMR : FSL_SAI_RMR)
+
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE       BIT(31)
 #define FSL_SAI_CSR_FR         BIT(25)
@@ -48,6 +58,7 @@
 #define FSL_SAI_CSR_FWF                BIT(17)
 #define FSL_SAI_CSR_FRF                BIT(16)
 #define FSL_SAI_CSR_xIE_SHIFT  8
+#define FSL_SAI_CSR_xIE_MASK   (0x1f << FSL_SAI_CSR_xIE_SHIFT)
 #define FSL_SAI_CSR_WSIE       BIT(12)
 #define FSL_SAI_CSR_SEIE       BIT(11)
 #define FSL_SAI_CSR_FEIE       BIT(10)
 #define FSL_SAI_CLK_MAST2      2
 #define FSL_SAI_CLK_MAST3      3
 
+#define FSL_SAI_MCLK_MAX       3
+
 /* SAI data transfer numbers per DMA request */
 #define FSL_SAI_MAXBURST_TX 6
 #define FSL_SAI_MAXBURST_RX 6
 struct fsl_sai {
        struct platform_device *pdev;
        struct regmap *regmap;
+       struct clk *bus_clk;
+       struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
 
        bool big_endian_regs;
        bool big_endian_data;
        bool is_dsp_mode;
+       bool sai_on_imx;
 
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
index 6452ca83d8893eb35cdc842b8991366c4684c6e2..e7be6b3214e55aa34e81b1e6331e88c706dd0eaf 100644 (file)
  * kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/bitrev.h>
 #include <linux/clk.h>
 #include <linux/clk-private.h>
-#include <linux/bitrev.h>
-#include <linux/regmap.h>
+#include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/regmap.h>
 
 #include <sound/asoundef.h>
-#include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
 
 #include "fsl_spdif.h"
 #include "imx-pcm.h"
@@ -80,6 +80,8 @@ struct fsl_spdif_priv {
        u8 rxclk_src;
        struct clk *txclk[SPDIF_TXRATE_MAX];
        struct clk *rxclk;
+       struct clk *coreclk;
+       struct clk *sysclk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
 
@@ -423,10 +425,16 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
 
        /* Reset module and interrupts only for first initialization */
        if (!cpu_dai->active) {
+               ret = clk_prepare_enable(spdif_priv->coreclk);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to enable core clock\n");
+                       return ret;
+               }
+
                ret = spdif_softreset(spdif_priv);
                if (ret) {
                        dev_err(&pdev->dev, "failed to soft reset\n");
-                       return ret;
+                       goto err;
                }
 
                /* Disable all the interrupts */
@@ -454,6 +462,11 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
        regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
 
        return 0;
+
+err:
+       clk_disable_unprepare(spdif_priv->coreclk);
+
+       return ret;
 }
 
 static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
@@ -484,6 +497,7 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
                spdif_intr_status_clear(spdif_priv);
                regmap_update_bits(regmap, REG_SPDIF_SCR,
                                SCR_LOW_POWER, SCR_LOW_POWER);
+               clk_disable_unprepare(spdif_priv->coreclk);
        }
 }
 
@@ -754,7 +768,7 @@ static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
        clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
        if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
                /* Get bus clock from system */
-               busclk_freq = clk_get_rate(spdif_priv->rxclk);
+               busclk_freq = clk_get_rate(spdif_priv->sysclk);
        }
 
        /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
@@ -1134,6 +1148,20 @@ static int fsl_spdif_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* Get system clock for rx clock rate calculation */
+       spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5");
+       if (IS_ERR(spdif_priv->sysclk)) {
+               dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n");
+               return PTR_ERR(spdif_priv->sysclk);
+       }
+
+       /* Get core clock for data register access via DMA */
+       spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+       if (IS_ERR(spdif_priv->coreclk)) {
+               dev_err(&pdev->dev, "no core clock in devicetree\n");
+               return PTR_ERR(spdif_priv->coreclk);
+       }
+
        /* Select clock source for rx/tx clock */
        spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
        if (IS_ERR(spdif_priv->rxclk)) {
@@ -1186,6 +1214,7 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 
 static const struct of_device_id fsl_spdif_dt_ids[] = {
        { .compatible = "fsl,imx35-spdif", },
+       { .compatible = "fsl,vf610-spdif", },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
index b1266790d1174a74497e81d1848436300894b5ea..605a10b2112b3808e8d5a95e282e51daf69eec62 100644 (file)
@@ -144,8 +144,8 @@ enum spdif_gainsel {
 
 /* SPDIF Clock register */
 #define STC_SYSCLK_DIV_OFFSET          11
-#define STC_SYSCLK_DIV_MASK            (0x1ff << STC_TXCLK_SRC_OFFSET)
-#define STC_SYSCLK_DIV(x)              ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK)
+#define STC_SYSCLK_DIV_MASK            (0x1ff << STC_SYSCLK_DIV_OFFSET)
+#define STC_SYSCLK_DIV(x)              ((((x) - 1) << STC_SYSCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK)
 #define STC_TXCLK_SRC_OFFSET           8
 #define STC_TXCLK_SRC_MASK             (0x7 << STC_TXCLK_SRC_OFFSET)
 #define STC_TXCLK_SRC_SET(x)           ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK)
index 5428a1fda2603850349fa2fb11680df9b63386eb..25865d8f2efd1d91e9132bded7d5afdd36148c07 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
@@ -642,96 +643,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
        write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
 }
 
-static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
-{
-       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-       u8 wm;
-       int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
-
-       fsl_ssi_setup_reg_vals(ssi_private);
-
-       if (ssi_private->imx_ac97)
-               ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
-       else
-               ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
-
-       /*
-        * Section 16.5 of the MPC8610 reference manual says that the SSI needs
-        * to be disabled before updating the registers we set here.
-        */
-       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-
-       /*
-        * Program the SSI into I2S Slave Non-Network Synchronous mode. Also
-        * enable the transmit and receive FIFO.
-        *
-        * FIXME: Little-endian samples require a different shift dir
-        */
-       write_ssi_mask(&ssi->scr,
-               CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
-               CCSR_SSI_SCR_TFR_CLK_DIS |
-               ssi_private->i2s_mode |
-               (synchronous ? CCSR_SSI_SCR_SYN : 0));
-
-       write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFSI |
-                       CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr);
-
-       write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFSI |
-                       CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
-
-       /*
-        * The DC and PM bits are only used if the SSI is the clock master.
-        */
-
-       /*
-        * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
-        * use FIFO 1. We program the transmit water to signal a DMA transfer
-        * if there are only two (or fewer) elements left in the FIFO. Two
-        * elements equals one frame (left channel, right channel). This value,
-        * however, depends on the depth of the transmit buffer.
-        *
-        * We set the watermark on the same level as the DMA burstsize.  For
-        * fiq it is probably better to use the biggest possible watermark
-        * size.
-        */
-       if (ssi_private->use_dma)
-               wm = ssi_private->fifo_depth - 2;
-       else
-               wm = ssi_private->fifo_depth;
-
-       write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
-               CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
-               &ssi->sfcsr);
-
-       /*
-        * For ac97 interrupts are enabled with the startup of the substream
-        * because it is also running without an active substream. Normally SSI
-        * is only enabled when there is a substream.
-        */
-       if (ssi_private->imx_ac97)
-               fsl_ssi_setup_ac97(ssi_private);
-
-       /*
-        * Set a default slot number so that there is no need for those common
-        * cases like I2S mode to call the extra set_tdm_slot() any more.
-        */
-       if (!ssi_private->imx_ac97) {
-               write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
-                               CCSR_SSI_SxCCR_DC(2));
-               write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
-                               CCSR_SSI_SxCCR_DC(2));
-       }
-
-       if (ssi_private->use_dual_fifo) {
-               write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
-               write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
-               write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
-       }
-
-       return 0;
-}
-
-
 /**
  * fsl_ssi_startup: create a new substream
  *
@@ -748,12 +659,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                snd_soc_dai_get_drvdata(rtd->cpu_dai);
        unsigned long flags;
 
-       /* First, we only do fsl_ssi_setup() when SSI is going to be active.
-        * Second, fsl_ssi_setup was already called by ac97_init earlier if
-        * the driver is in ac97 mode.
-        */
        if (!dai->active && !ssi_private->imx_ac97) {
-               fsl_ssi_setup(ssi_private);
                spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
                ssi_private->baudclk_locked = false;
                spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
@@ -835,9 +741,11 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
        u32 strcr = 0, stcr, srcr, scr, mask;
+       u8 wm;
+
+       fsl_ssi_setup_reg_vals(ssi_private);
 
        scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
-       scr |= CCSR_SSI_SCR_NET;
 
        mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
                CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
@@ -845,19 +753,19 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        stcr = read_ssi(&ssi->stcr) & ~mask;
        srcr = read_ssi(&ssi->srcr) & ~mask;
 
+       ssi_private->i2s_mode = CCSR_SSI_SCR_NET;
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
                case SND_SOC_DAIFMT_CBS_CFS:
-                       ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_MASTER;
+                       ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
                        break;
                case SND_SOC_DAIFMT_CBM_CFM:
-                       ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+                       ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE;
                        break;
                default:
                        return -EINVAL;
                }
-               scr |= ssi_private->i2s_mode;
 
                /* Data on rising edge of bclk, frame low, 1clk before data */
                strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
@@ -877,9 +785,13 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
                strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
                        CCSR_SSI_STCR_TXBIT0;
                break;
+       case SND_SOC_DAIFMT_AC97:
+               ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL;
+               break;
        default:
                return -EINVAL;
        }
+       scr |= ssi_private->i2s_mode;
 
        /* DAI clock inversion */
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -929,6 +841,38 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        write_ssi(srcr, &ssi->srcr);
        write_ssi(scr, &ssi->scr);
 
+       /*
+        * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
+        * use FIFO 1. We program the transmit water to signal a DMA transfer
+        * if there are only two (or fewer) elements left in the FIFO. Two
+        * elements equals one frame (left channel, right channel). This value,
+        * however, depends on the depth of the transmit buffer.
+        *
+        * We set the watermark on the same level as the DMA burstsize.  For
+        * fiq it is probably better to use the biggest possible watermark
+        * size.
+        */
+       if (ssi_private->use_dma)
+               wm = ssi_private->fifo_depth - 2;
+       else
+               wm = ssi_private->fifo_depth;
+
+       write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
+                       CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
+                       &ssi->sfcsr);
+
+       if (ssi_private->use_dual_fifo) {
+               write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1,
+                               CCSR_SSI_SRCR_RFEN1);
+               write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1,
+                               CCSR_SSI_STCR_TFEN1);
+               write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN,
+                               CCSR_SSI_SCR_TCH_EN);
+       }
+
+       if (fmt & SND_SOC_DAIFMT_AC97)
+               fsl_ssi_setup_ac97(ssi_private);
+
        return 0;
 }
 
@@ -1184,11 +1128,6 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
 
 static struct fsl_ssi_private *fsl_ac97_data;
 
-static void fsl_ssi_ac97_init(void)
-{
-       fsl_ssi_setup(fsl_ac97_data);
-}
-
 static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                unsigned short val)
 {
@@ -1547,9 +1486,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
 done:
-       if (ssi_private->imx_ac97)
-               fsl_ssi_ac97_init();
-
        return 0;
 
 error_dai:
index ac869931d7f16c9c4049aefaffb4a7d416417e49..267717aa96c14e971329cfe2f728d1f141de72c3 100644 (file)
@@ -145,7 +145,7 @@ static const struct file_operations audmux_debugfs_fops = {
        .llseek = default_llseek,
 };
 
-static void __init audmux_debugfs_init(void)
+static void audmux_debugfs_init(void)
 {
        int i;
        char buf[20];
index 2585ae44e634feb6bab623b6afdf93c58c3b288f..0849b7b83f0a7df054bb62229d2afd742d7b2624 100644 (file)
@@ -40,7 +40,6 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_PAUSE |
                SNDRV_PCM_INFO_RESUME,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE,
        .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
        .period_bytes_min = 128,
        .period_bytes_max = 65535, /* Limited by SDMA engine */
index 21f1ccbdf58299624816d312a61aff0b8ffa53fb..98f97e543c2943e66867b2db75272be8c866ab5a 100644 (file)
@@ -66,8 +66,7 @@ err:
 
 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct simple_card_data *priv =
-                               snd_soc_card_get_drvdata(rtd->card);
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_dai *codec = rtd->codec_dai;
        struct snd_soc_dai *cpu = rtd->cpu_dai;
        struct simple_dai_props *dai_props;
@@ -88,7 +87,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 
 static int
 asoc_simple_card_sub_parse_of(struct device_node *np,
-                             unsigned int daifmt,
                              struct asoc_simple_dai *dai,
                              const struct device_node **p_node,
                              const char **name)
@@ -116,14 +114,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
        if (ret)
                return ret;
 
-       /*
-        * bitclock-inversion, frame-inversion
-        * bitclock-master,    frame-master
-        * and specific "format" if it has
-        */
-       dai->fmt = snd_soc_of_parse_daifmt(np, NULL);
-       dai->fmt |= daifmt;
-
        /*
         * dai->sysclk come from
         *  "clocks = <&xxx>" (if system has common clock)
@@ -151,37 +141,132 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
        return 0;
 }
 
-static int simple_card_cpu_codec_of(struct device_node *node,
-                               int daifmt,
-                               struct snd_soc_dai_link *dai_link,
-                               struct simple_dai_props *dai_props)
+static int simple_card_dai_link_of(struct device_node *node,
+                                  struct device *dev,
+                                  struct snd_soc_dai_link *dai_link,
+                                  struct simple_dai_props *dai_props)
 {
-       struct device_node *np;
+       struct device_node *np = NULL;
+       struct device_node *bitclkmaster = NULL;
+       struct device_node *framemaster = NULL;
+       unsigned int daifmt;
+       char *name;
+       char prop[128];
+       char *prefix = "";
        int ret;
 
-       /* CPU sub-node */
-       ret = -EINVAL;
-       np = of_get_child_by_name(node, "simple-audio-card,cpu");
-       if (np) {
-               ret = asoc_simple_card_sub_parse_of(np, daifmt,
-                                               &dai_props->cpu_dai,
-                                               &dai_link->cpu_of_node,
-                                               &dai_link->cpu_dai_name);
-               of_node_put(np);
+       prefix = "simple-audio-card,";
+
+       daifmt = snd_soc_of_parse_daifmt(node, prefix,
+                                        &bitclkmaster, &framemaster);
+       daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+       snprintf(prop, sizeof(prop), "%scpu", prefix);
+       np = of_get_child_by_name(node, prop);
+       if (!np) {
+               ret = -EINVAL;
+               dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+               goto dai_link_of_err;
        }
+
+       ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
+                                           &dai_link->cpu_of_node,
+                                           &dai_link->cpu_dai_name);
        if (ret < 0)
-               return ret;
+               goto dai_link_of_err;
+
+       dai_props->cpu_dai.fmt = daifmt;
+       switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
+       case 0x11:
+               dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
+               break;
+       case 0x10:
+               dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
+               break;
+       case 0x01:
+               dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
+               break;
+       default:
+               dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       }
 
-       /* CODEC sub-node */
-       ret = -EINVAL;
-       np = of_get_child_by_name(node, "simple-audio-card,codec");
-       if (np) {
-               ret = asoc_simple_card_sub_parse_of(np, daifmt,
-                                               &dai_props->codec_dai,
-                                               &dai_link->codec_of_node,
-                                               &dai_link->codec_dai_name);
-               of_node_put(np);
+       of_node_put(np);
+       snprintf(prop, sizeof(prop), "%scodec", prefix);
+       np = of_get_child_by_name(node, prop);
+       if (!np) {
+               ret = -EINVAL;
+               dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+               goto dai_link_of_err;
        }
+
+       ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
+                                           &dai_link->codec_of_node,
+                                           &dai_link->codec_dai_name);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       if (strlen(prefix) && !bitclkmaster && !framemaster) {
+               /* No dai-link level and master setting was not found from
+                  sound node level, revert back to legacy DT parsing and
+                  take the settings from codec node. */
+               dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
+                       __func__);
+               dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
+                       snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) |
+                       (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
+       } else {
+               dai_props->codec_dai.fmt = daifmt;
+               switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
+               case 0x11:
+                       dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
+                       break;
+               case 0x10:
+                       dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
+                       break;
+               case 0x01:
+                       dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
+                       break;
+               default:
+                       dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
+                       break;
+               }
+       }
+
+       if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
+               ret = -EINVAL;
+               goto dai_link_of_err;
+       }
+
+       /* simple-card assumes platform == cpu */
+       dai_link->platform_of_node = dai_link->cpu_of_node;
+
+       /* Link name is created from CPU/CODEC dai name */
+       name = devm_kzalloc(dev,
+                           strlen(dai_link->cpu_dai_name)   +
+                           strlen(dai_link->codec_dai_name) + 2,
+                           GFP_KERNEL);
+       sprintf(name, "%s-%s", dai_link->cpu_dai_name,
+                               dai_link->codec_dai_name);
+       dai_link->name = dai_link->stream_name = name;
+
+       dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
+       dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
+               dai_link->cpu_dai_name,
+               dai_props->cpu_dai.fmt,
+               dai_props->cpu_dai.sysclk);
+       dev_dbg(dev, "\tcodec : %s / %04x / %d\n",
+               dai_link->codec_dai_name,
+               dai_props->codec_dai.fmt,
+               dai_props->codec_dai.sysclk);
+
+dai_link_of_err:
+       if (np)
+               of_node_put(np);
+       if (bitclkmaster)
+               of_node_put(bitclkmaster);
+       if (framemaster)
+               of_node_put(framemaster);
        return ret;
 }
 
@@ -192,18 +277,11 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 {
        struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
        struct simple_dai_props *dai_props = priv->dai_props;
-       struct device_node *np;
-       char *name;
-       unsigned int daifmt;
        int ret;
 
        /* parsing the card name from DT */
        snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
 
-       /* get CPU/CODEC common format via simple-audio-card,format */
-       daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
-               (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
-
        /* off-codec widgets */
        if (of_property_read_bool(node, "simple-audio-card,widgets")) {
                ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
@@ -220,71 +298,31 @@ static int asoc_simple_card_parse_of(struct device_node *node,
                        return ret;
        }
 
-       /* loop on the DAI links */
-       np = NULL;
-       for (;;) {
-               if (multi) {
-                       np = of_get_next_child(node, np);
-                       if (!np)
-                               break;
+       dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
+               priv->snd_card.name : "");
+
+       if (multi) {
+               struct device_node *np = NULL;
+               int i;
+               for (i = 0; (np = of_get_next_child(node, np)); i++) {
+                       dev_dbg(dev, "\tlink %d:\n", i);
+                       ret = simple_card_dai_link_of(np, dev, dai_link + i,
+                                                     dai_props + i);
+                       if (ret < 0) {
+                               of_node_put(np);
+                               return ret;
+                       }
                }
-
-               ret = simple_card_cpu_codec_of(multi ? np : node,
-                                       daifmt, dai_link, dai_props);
+       } else {
+               ret = simple_card_dai_link_of(node, dev, dai_link, dai_props);
                if (ret < 0)
-                       goto err;
-
-               /*
-                * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
-                * while the other bits should be identical unless buggy SW/HW design.
-                */
-               dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
-
-               if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               /* simple-card assumes platform == cpu */
-               dai_link->platform_of_node = dai_link->cpu_of_node;
-
-               name = devm_kzalloc(dev,
-                                   strlen(dai_link->cpu_dai_name)   +
-                                   strlen(dai_link->codec_dai_name) + 2,
-                                   GFP_KERNEL);
-               sprintf(name, "%s-%s", dai_link->cpu_dai_name,
-                                       dai_link->codec_dai_name);
-               dai_link->name = dai_link->stream_name = name;
-
-               if (!multi)
-                       break;
-
-               dai_link++;
-               dai_props++;
+                       return ret;
        }
 
-       /* card name is created from CPU/CODEC dai name */
-       dai_link = priv->snd_card.dai_link;
        if (!priv->snd_card.name)
-               priv->snd_card.name = dai_link->name;
-
-       dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
-       dev_dbg(dev, "platform : %04x\n", daifmt);
-       dai_props = priv->dai_props;
-       dev_dbg(dev, "cpu : %s / %04x / %d\n",
-               dai_link->cpu_dai_name,
-               dai_props->cpu_dai.fmt,
-               dai_props->cpu_dai.sysclk);
-       dev_dbg(dev, "codec : %s / %04x / %d\n",
-               dai_link->codec_dai_name,
-               dai_props->codec_dai.fmt,
-               dai_props->codec_dai.sysclk);
+               priv->snd_card.name = priv->snd_card.dai_link->name;
 
        return 0;
-
-err:
-       of_node_put(np);
-       return ret;
 }
 
 /* update the reference count of the devices nodes at end of probe */
@@ -378,10 +416,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                        return -EINVAL;
                }
 
-               if (!cinfo->name        ||
-                   !cinfo->codec_dai.name      ||
-                   !cinfo->codec       ||
-                   !cinfo->platform    ||
+               if (!cinfo->name ||
+                   !cinfo->codec_dai.name ||
+                   !cinfo->codec ||
+                   !cinfo->platform ||
                    !cinfo->cpu_dai.name) {
                        dev_err(dev, "insufficient asoc_simple_card_info settings\n");
                        return -EINVAL;
@@ -425,11 +463,11 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
 
 static struct platform_driver asoc_simple_card = {
        .driver = {
-               .name   = "asoc-simple-card",
+               .name = "asoc-simple-card",
                .owner = THIS_MODULE,
                .of_match_table = asoc_simple_of_match,
        },
-       .probe          = asoc_simple_card_probe,
+       .probe = asoc_simple_card_probe,
 };
 
 module_platform_driver(asoc_simple_card);
index 5d06eecb61986da272fcda4858db56c91d285153..18aee77f8d4a55276194542c41464feb363784d3 100644 (file)
@@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
 
        sst_pdata = &sst_acpi->sst_pdata;
        sst_pdata->id = desc->sst_id;
+       sst_pdata->dma_dev = dev;
        sst_acpi->desc = desc;
        sst_acpi->mach = mach;
 
index d0eaeee21be4c634ae88e984cf964c5067b5cae6..0d31dbbf480652e773243dca639f042a4c531bc0 100644 (file)
@@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
        void *data)
 {
        struct sst_byt_stream *stream;
+       struct sst_dsp *sst = byt->dsp;
+       unsigned long flags;
 
        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
        if (stream == NULL)
                return NULL;
 
+       spin_lock_irqsave(&sst->spinlock, flags);
        list_add(&stream->node, &byt->stream_list);
        stream->notify_position = notify_position;
        stream->pdata = data;
        stream->byt = byt;
        stream->str_id = id;
+       spin_unlock_irqrestore(&sst->spinlock, flags);
 
        return stream;
 }
@@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
 {
        u64 header;
        int ret = 0;
+       struct sst_dsp *sst = byt->dsp;
+       unsigned long flags;
 
        if (!stream->commited)
                goto out;
@@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
 
        stream->commited = false;
 out:
+       spin_lock_irqsave(&sst->spinlock, flags);
        list_del(&stream->node);
        kfree(stream);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
 
        return ret;
 }
index fe8e81aad6461faf545b179f6d1a912369872e6a..401213455497258111dcf939c7d963fbbbeb3e37 100644 (file)
@@ -136,7 +136,7 @@ struct sst_module_data {
        enum sst_data_type data_type;   /* type of module data */
 
        u32 size;               /* size in bytes */
-       u32 offset;             /* offset in FW file */
+       int32_t offset;         /* offset in FW file */
        u32 data_offset;        /* offset in ADSP memory space */
        void *data;             /* module data */
 };
@@ -228,6 +228,7 @@ struct sst_dsp {
        spinlock_t spinlock;    /* IPC locking */
        struct mutex mutex;     /* DSP FW lock */
        struct device *dev;
+       struct device *dma_dev;
        void *thread_context;
        int irq;
        u32 id;
index 0c129fd85ecf8a37b3758dfc924a9e5091c9e01e..0b715b20a2d7d46b9f06189de1ee57d9aacc28ab 100644 (file)
@@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
        spin_lock_init(&sst->spinlock);
        mutex_init(&sst->mutex);
        sst->dev = dev;
+       sst->dma_dev = pdata->dma_dev;
        sst->thread_context = sst_dev->thread_context;
        sst->sst_dev = sst_dev;
        sst->id = pdata->id;
index 74052b59485ca1ce942444d0a3871ed8a6051672..e44423be66c459ba721249d0efe21bccdaeea4b5 100644 (file)
@@ -169,6 +169,7 @@ struct sst_pdata {
        u32 dma_base;
        u32 dma_size;
        int dma_engine;
+       struct device *dma_dev;
 
        /* DSP */
        u32 id;
index f7687107cf7f51f19a95992b79819270e3dd4734..65d7e8e7c74fb037a579b3a4967c71e250d72086 100644 (file)
@@ -57,14 +57,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
        sst_fw->private = private;
        sst_fw->size = fw->size;
 
-       err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
-       if (err < 0) {
-               kfree(sst_fw);
-               return NULL;
-       }
-
        /* allocate DMA buffer to store FW data */
-       sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size,
+       sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,
                                &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
        if (!sst_fw->dma_buf) {
                dev_err(dsp->dev, "error: DMA alloc failed\n");
@@ -106,7 +100,7 @@ void sst_fw_free(struct sst_fw *sst_fw)
        list_del(&sst_fw->list);
        mutex_unlock(&dsp->mutex);
 
-       dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+       dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
                        sst_fw->dmable_fw_paddr);
        kfree(sst_fw);
 }
@@ -202,6 +196,9 @@ static int block_alloc_contiguous(struct sst_module *module,
                size -= block->size;
        }
 
+       list_for_each_entry(block, &tmp, list)
+               list_add(&block->module_list, &module->block_list);
+
        list_splice(&tmp, &dsp->used_block_list);
        return 0;
 }
@@ -247,8 +244,7 @@ static int block_alloc(struct sst_module *module,
                /* do we span > 1 blocks */
                if (data->size > block->size) {
                        ret = block_alloc_contiguous(module, data,
-                               block->offset + block->size,
-                               data->size - block->size);
+                               block->offset, data->size);
                        if (ret == 0)
                                return ret;
                }
@@ -344,7 +340,7 @@ static int block_alloc_fixed(struct sst_module *module,
 
                        err = block_alloc_contiguous(module, data,
                                block->offset + block->size,
-                               data->size - block->size + data->offset - block->offset);
+                               data->size - block->size);
                        if (err < 0)
                                return -ENOMEM;
 
@@ -371,15 +367,10 @@ static int block_alloc_fixed(struct sst_module *module,
                if (data->offset >= block->offset && data->offset < block_end) {
 
                        err = block_alloc_contiguous(module, data,
-                               block->offset + block->size,
-                               data->size - block->size);
+                               block->offset, data->size);
                        if (err < 0)
                                return -ENOMEM;
 
-                       /* add block */
-                       block->data_type = data->data_type;
-                       list_move(&block->list, &dsp->used_block_list);
-                       list_add(&block->module_list, &module->block_list);
                        return 0;
                }
 
@@ -505,9 +496,7 @@ struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
 
        /* calculate required scratch size */
        list_for_each_entry(sst_module, &dsp->module_list, list) {
-               if (scratch->s.size > sst_module->s.size)
-                       scratch->s.size = scratch->s.size;
-               else
+               if (scratch->s.size < sst_module->s.size)
                        scratch->s.size = sst_module->s.size;
        }
 
index f5ebf36af8898d8a94d4a46886bfcfe0964d0567..535f517629fd608fb7c4bd3eb79a05a67d98a518 100644 (file)
@@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
        int ret = -ENODEV, i, j, region_count;
        u32 offset, size;
 
-       dev = sst->dev;
+       dev = sst->dma_dev;
 
        switch (sst->id) {
        case SST_DEV_ID_LYNX_POINT:
@@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
                return ret;
        }
 
-       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
        if (ret)
                return ret;
 
index f46bb4ddde6fc7550573e5fdd0235afda429044a..e7996b39a48480a8577ac26d6cad28e3392259aa 100644 (file)
@@ -617,7 +617,7 @@ static void hsw_notification_work(struct work_struct *work)
        case IPC_POSITION_CHANGED:
                trace_ipc_notification("DSP stream position changed for",
                        stream->reply.stream_hw_id);
-               sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos));
+               sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos));
 
                if (stream->notify_position)
                        stream->notify_position(stream, stream->pdata);
@@ -991,7 +991,8 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream
                return -EINVAL;
 
        sst_dsp_read(hsw->dsp, volume,
-               stream->reply.volume_register_address[channel], sizeof(volume));
+               stream->reply.volume_register_address[channel],
+               sizeof(*volume));
 
        return 0;
 }
@@ -1158,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
        void *data)
 {
        struct sst_hsw_stream *stream;
+       struct sst_dsp *sst = hsw->dsp;
+       unsigned long flags;
 
        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
        if (stream == NULL)
                return NULL;
 
+       spin_lock_irqsave(&sst->spinlock, flags);
        list_add(&stream->node, &hsw->stream_list);
        stream->notify_position = notify_position;
        stream->pdata = data;
@@ -1171,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
 
        /* work to process notification messages */
        INIT_WORK(&stream->notify_work, hsw_notification_work);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
 
        return stream;
 }
@@ -1179,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
 {
        u32 header;
        int ret = 0;
+       struct sst_dsp *sst = hsw->dsp;
+       unsigned long flags;
 
        /* dont free DSP streams that are not commited */
        if (!stream->commited)
@@ -1200,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        trace_hsw_stream_free_req(stream, &stream->free_req);
 
 out:
+       cancel_work_sync(&stream->notify_work);
+       spin_lock_irqsave(&sst->spinlock, flags);
        list_del(&stream->node);
        kfree(stream);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
 
        return ret;
 }
@@ -1537,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
 }
 
 /* Stream pointer positions */
-int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
 {
-       return stream->rpos.position;
+       u32 rpos;
+
+       sst_dsp_read(hsw->dsp, &rpos,
+               stream->reply.read_position_register_address, sizeof(rpos));
+
+       return rpos;
+}
+
+/* Stream presentation (monotonic) positions */
+u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       u64 ppos;
+
+       sst_dsp_read(hsw->dsp, &ppos,
+               stream->reply.presentation_position_register_address,
+               sizeof(ppos));
+
+       return ppos;
 }
 
 int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
@@ -1609,7 +1637,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw,
        trace_ipc_request("PM enter Dx state", state);
 
        ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_),
-               dx, sizeof(dx));
+               dx, sizeof(*dx));
        if (ret < 0) {
                dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
                return ret;
index d517929ccc389e2aaca3321106b6088250929482..2ac194a6d04b226eb86cb42c2361c643f7400635 100644 (file)
@@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 *position);
 int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 stage_id, u32 position);
-int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream);
 
 /* HW port config */
index 0a32dd13a23d28ab96282b75592c20d5b133ee9f..447740cdba7a2d4ff07498a6339dde0b478535e7 100644 (file)
@@ -99,6 +99,7 @@ struct hsw_pcm_data {
        struct snd_compr_stream *cstream;
        unsigned int wpos;
        struct mutex mutex;
+       bool allocated;
 };
 
 /* private data for the driver */
@@ -107,12 +108,14 @@ struct hsw_priv_data {
        struct sst_hsw *hsw;
 
        /* page tables */
-       unsigned char *pcm_pg[HSW_PCM_COUNT][2];
+       struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
 
        /* DAI data */
        struct hsw_pcm_data pcm[HSW_PCM_COUNT];
 };
 
+static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
+
 static inline u32 hsw_mixer_to_ipc(unsigned int value)
 {
        if (value >= ARRAY_SIZE(volume_map))
@@ -136,7 +139,7 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
 static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        struct hsw_priv_data *pdata =
@@ -174,7 +177,7 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
 static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        struct hsw_priv_data *pdata =
@@ -206,7 +209,7 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
 static int hsw_volume_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
        struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
@@ -231,7 +234,7 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
 static int hsw_volume_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
        struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
        struct sst_hsw *hsw = pdata->hsw;
        unsigned int volume = 0;
@@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
 };
 
 /* Create DMA buffer page table for DSP */
-static int create_adsp_page_table(struct hsw_priv_data *pdata,
-       struct snd_soc_pcm_runtime *rtd,
-       unsigned char *dma_area, size_t size, int pcm, int stream)
+static int create_adsp_page_table(struct snd_pcm_substream *substream,
+       struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
+       unsigned char *dma_area, size_t size, int pcm)
 {
-       int i, pages;
+       struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
+       int i, pages, stream = substream->stream;
 
-       if (size % PAGE_SIZE)
-               pages = (size / PAGE_SIZE) + 1;
-       else
-               pages = size / PAGE_SIZE;
+       pages = snd_sgbuf_aligned_pages(size);
 
        dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
                dma_area, size, pages);
 
        for (i = 0; i < pages; i++) {
                u32 idx = (((i << 2) + i)) >> 1;
-               u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT;
+               u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
                u32 *pg_table;
 
                dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
 
-               pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx);
+               pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
 
                if (i & 1)
                        *pg_table |= (pfn << 4);
@@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
        struct sst_hsw *hsw = pdata->hsw;
        struct sst_module *module_data;
        struct sst_dsp *dsp;
+       struct snd_dma_buffer *dmab;
        enum sst_hsw_stream_type stream_type;
        enum sst_hsw_stream_path_id path_id;
        u32 rate, bits, map, pages, module_id;
        u8 channels;
        int ret;
 
+       /* check if we are being called a subsequent time */
+       if (pcm_data->allocated) {
+               ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
+               if (ret < 0)
+                       dev_dbg(rtd->dev, "error: reset stream failed %d\n",
+                               ret);
+
+               ret = sst_hsw_stream_free(hsw, pcm_data->stream);
+               if (ret < 0) {
+                       dev_dbg(rtd->dev, "error: free stream failed %d\n",
+                               ret);
+                       return ret;
+               }
+               pcm_data->allocated = false;
+
+               pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
+                       hsw_notify_pointer, pcm_data);
+               if (pcm_data->stream == NULL) {
+                       dev_err(rtd->dev, "error: failed to create stream\n");
+                       return -EINVAL;
+               }
+       }
+
        /* stream direction */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
@@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
-               runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
+       dmab = snd_pcm_get_dma_buf(substream);
+
+       ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
+               runtime->dma_bytes, rtd->cpu_dai->id);
        if (ret < 0)
                return ret;
 
@@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
                pages = runtime->dma_bytes / PAGE_SIZE;
 
        ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
-               virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
+               pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
                pages, runtime->dma_bytes, 0,
-               (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
+               snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
        if (ret < 0) {
                dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
                return ret;
@@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
                dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
                return ret;
        }
+       pcm_data->allocated = true;
 
        ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
        if (ret < 0)
@@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
        struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
        struct sst_hsw *hsw = pdata->hsw;
        snd_pcm_uframes_t offset;
+       uint64_t ppos;
+       u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
 
-       offset = bytes_to_frames(runtime,
-               sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+       offset = bytes_to_frames(runtime, position);
+       ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
 
-       dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
-               frames_to_bytes(runtime, (u32)offset));
+       dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
+               position, ppos);
        return offset;
 }
 
@@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
                dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
                goto out;
        }
+       pcm_data->allocated = 0;
        pcm_data->stream = NULL;
 
 out:
@@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = {
        .hw_free        = hsw_pcm_hw_free,
        .trigger        = hsw_pcm_trigger,
        .pointer        = hsw_pcm_pointer,
-       .mmap           = snd_pcm_lib_default_mmap,
+       .page           = snd_pcm_sgbuf_ops_page,
 };
 
 static void hsw_pcm_free(struct snd_pcm *pcm)
@@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm)
 static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+       struct device *dev = pdata->dma_dev;
        int ret = 0;
 
-       ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
        if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
                        pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                       SNDRV_DMA_TYPE_DEV,
-                       rtd->card->dev,
+                       SNDRV_DMA_TYPE_DEV_SG,
+                       dev,
                        hsw_pcm_hardware.buffer_bytes_max,
                        hsw_pcm_hardware.buffer_bytes_max);
                if (ret) {
@@ -742,7 +772,8 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 {
        struct sst_pdata *pdata = dev_get_platdata(platform->dev);
        struct hsw_priv_data *priv_data;
-       int i;
+       struct device *dma_dev = pdata->dma_dev;
+       int i, ret = 0;
 
        if (!pdata)
                return -ENODEV;
@@ -758,15 +789,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 
                /* playback */
                if (hsw_dais[i].playback.channels_min) {
-                       priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA);
-                       if (priv_data->pcm_pg[i][0] == NULL)
+                       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
+                               PAGE_SIZE, &priv_data->dmab[i][0]);
+                       if (ret < 0)
                                goto err;
                }
 
                /* capture */
                if (hsw_dais[i].capture.channels_min) {
-                       priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA);
-                       if (priv_data->pcm_pg[i][1] == NULL)
+                       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
+                               PAGE_SIZE, &priv_data->dmab[i][1]);
+                       if (ret < 0)
                                goto err;
                }
        }
@@ -776,11 +809,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 err:
        for (;i >= 0; i--) {
                if (hsw_dais[i].playback.channels_min)
-                       kfree(priv_data->pcm_pg[i][0]);
+                       snd_dma_free_pages(&priv_data->dmab[i][0]);
                if (hsw_dais[i].capture.channels_min)
-                       kfree(priv_data->pcm_pg[i][1]);
+                       snd_dma_free_pages(&priv_data->dmab[i][1]);
        }
-       return -ENOMEM;
+       return ret;
 }
 
 static int hsw_pcm_remove(struct snd_soc_platform *platform)
@@ -791,9 +824,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
 
        for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
                if (hsw_dais[i].playback.channels_min)
-                       kfree(priv_data->pcm_pg[i][0]);
+                       snd_dma_free_pages(&priv_data->dmab[i][0]);
                if (hsw_dais[i].capture.channels_min)
-                       kfree(priv_data->pcm_pg[i][1]);
+                       snd_dma_free_pages(&priv_data->dmab[i][1]);
        }
 
        return 0;
index 29f76af5d963c2fca31366e7140c21239d18a0f0..1a354a6b6e870e03982ccdd3335c036f614d459e 100644 (file)
@@ -1,24 +1,29 @@
 config SND_JZ4740_SOC
        tristate "SoC Audio for Ingenic JZ4740 SoC"
-       depends on MACH_JZ4740 && SND_SOC
+       depends on MACH_JZ4740 || COMPILE_TEST
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
          the JZ4740 I2S interface. You will also need to select the audio
          interfaces to support below.
 
+if SND_JZ4740_SOC
+
 config SND_JZ4740_SOC_I2S
-       depends on SND_JZ4740_SOC
        tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
+       depends on HAS_IOMEM
        help
          Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
          based boards.
 
 config SND_JZ4740_SOC_QI_LB60
        tristate "SoC Audio support for Qi LB60"
-       depends on SND_JZ4740_SOC && JZ4740_QI_LB60
+       depends on HAS_IOMEM
+       depends on JZ4740_QI_LB60 || COMPILE_TEST
        select SND_JZ4740_SOC_I2S
     select SND_SOC_JZ4740_CODEC
        help
          Say Y if you want to add support for ASoC audio on the Qi LB60 board
          a.k.a Qi Ben NanoNote.
+
+endif
index be873c1b0c204f4f902bfc7e2edad8c10d623e15..d32c540555c41b6c3f9b8f5817a5baa09b5ca47b 100644 (file)
@@ -1,10 +1,8 @@
 #
 # Jz4740 Platform Support
 #
-snd-soc-jz4740-objs := jz4740-pcm.o
 snd-soc-jz4740-i2s-objs := jz4740-i2s.o
 
-obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
 obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
 
 # Jz4740 Machine Support
index 8f220009e0f616e0572777c19a15c3a44c658ed8..3f9c3a9ae36fbadd276fd98eec62dcd073136232 100644 (file)
 #include <sound/initval.h>
 #include <sound/dmaengine_pcm.h>
 
-#include <asm/mach-jz4740/dma.h>
-
 #include "jz4740-i2s.h"
 
+#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
+#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
+
 #define JZ_REG_AIC_CONF                0x00
 #define JZ_REG_AIC_CTRL                0x04
 #define JZ_REG_AIC_I2S_FMT     0x10
index 82b5f37cd2c78ab16be9eda44b751201d8b9f09d..5cb91f9e86261b03afcb70583cd83f17ec3e4729 100644 (file)
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 
-#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
-#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
+struct qi_lb60 {
+       struct gpio_desc *snd_gpio;
+       struct gpio_desc *amp_gpio;
+};
 
 static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
                             struct snd_kcontrol *ctrl, int event)
 {
+       struct qi_lb60 *qi_lb60 = snd_soc_card_get_drvdata(widget->dapm->card);
        int on = !SND_SOC_DAPM_EVENT_OFF(event);
 
-       gpio_set_value(QI_LB60_SND_GPIO, on);
-       gpio_set_value(QI_LB60_AMP_GPIO, on);
+       gpiod_set_value_cansleep(qi_lb60->snd_gpio, on);
+       gpiod_set_value_cansleep(qi_lb60->amp_gpio, on);
 
        return 0;
 }
@@ -46,29 +49,6 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = {
        {"Speaker", NULL, "ROUT"},
 };
 
-#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \
-                       SND_SOC_DAIFMT_NB_NF | \
-                       SND_SOC_DAIFMT_CBM_CFM)
-
-static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       snd_soc_dapm_nc_pin(dapm, "LIN");
-       snd_soc_dapm_nc_pin(dapm, "RIN");
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
 static struct snd_soc_dai_link qi_lb60_dai = {
        .name = "jz4740",
        .stream_name = "jz4740",
@@ -76,10 +56,11 @@ static struct snd_soc_dai_link qi_lb60_dai = {
        .platform_name = "jz4740-i2s",
        .codec_dai_name = "jz4740-hifi",
        .codec_name = "jz4740-codec",
-       .init = qi_lb60_codec_init,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM,
 };
 
-static struct snd_soc_card qi_lb60 = {
+static struct snd_soc_card qi_lb60_card = {
        .name = "QI LB60",
        .owner = THIS_MODULE,
        .dai_link = &qi_lb60_dai,
@@ -89,40 +70,38 @@ static struct snd_soc_card qi_lb60 = {
        .num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets),
        .dapm_routes = qi_lb60_routes,
        .num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
-};
-
-static const struct gpio qi_lb60_gpios[] = {
-       { QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
-       { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
+       .fully_routed = true,
 };
 
 static int qi_lb60_probe(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = &qi_lb60;
+       struct qi_lb60 *qi_lb60;
+       struct snd_soc_card *card = &qi_lb60_card;
        int ret;
 
-       ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
+       qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL);
+       if (!qi_lb60)
+               return -ENOMEM;
+
+       qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd");
+       if (IS_ERR(qi_lb60->snd_gpio))
+               return PTR_ERR(qi_lb60->snd_gpio);
+       ret = gpiod_direction_output(qi_lb60->snd_gpio, 0);
        if (ret)
                return ret;
 
-       card->dev = &pdev->dev;
+       qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp");
+       if (IS_ERR(qi_lb60->amp_gpio))
+               return PTR_ERR(qi_lb60->amp_gpio);
+       ret = gpiod_direction_output(qi_lb60->amp_gpio, 0);
+       if (ret)
+               return ret;
 
-       ret = snd_soc_register_card(card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
-                       ret);
-               gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
-       }
-       return ret;
-}
+       card->dev = &pdev->dev;
 
-static int qi_lb60_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       snd_soc_card_set_drvdata(card, qi_lb60);
 
-       snd_soc_unregister_card(card);
-       gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static struct platform_driver qi_lb60_driver = {
@@ -131,7 +110,6 @@ static struct platform_driver qi_lb60_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = qi_lb60_probe,
-       .remove         = qi_lb60_remove,
 };
 
 module_platform_driver(qi_lb60_driver);
index a0ed1c618f6080a3c3536ebcd42e9dd0e1213687..7f0c954dff6f148b5eb4df78d6029b12543d74e6 100644 (file)
@@ -4,6 +4,7 @@
 config SND_SOC_NUC900
        tristate "SoC Audio for NUC900 series"
        depends on ARCH_W90X900
+       select SND_SOC_NUC900_AC97
        help
          This option enables support for AC97 mode on the NUC900 SoC.
 
index 8987bf987e584f6ba7a53b93516056dfbf5bc9b5..f2f67942b2294798fdcee596d5ed82142c7d09c1 100644 (file)
@@ -28,6 +28,7 @@
 
 static DEFINE_MUTEX(ac97_mutex);
 struct nuc900_audio *nuc900_ac97_data;
+EXPORT_SYMBOL_GPL(nuc900_ac97_data);
 
 static int nuc900_checkready(void)
 {
index e00659351a4e2279a539a0a26a1117fa196419bb..d44463a7b0faed8faef4565657962111604daa2c 100644 (file)
@@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810
 
 config SND_OMAP_SOC_RX51
        tristate "SoC Audio support for Nokia RX-51"
-       depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
+       depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && I2C
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TLV320AIC3X
        select SND_SOC_TPA6130A2
@@ -37,7 +37,7 @@ config SND_OMAP_SOC_RX51
 
 config SND_OMAP_SOC_AMS_DELTA
        tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
-       depends on SND_OMAP_SOC && MACH_AMS_DELTA
+       depends on SND_OMAP_SOC && MACH_AMS_DELTA && TTY
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_CX20442
        help
index 994dcf345975b73ca1b8cd0989ae787a4e941081..25a33e9d417a7ddcb4d99f7366f66f65232aee2e 100644 (file)
@@ -77,7 +77,7 @@ static struct snd_soc_dai_link am3517evm_dai = {
        .stream_name = "AIC23",
        .cpu_dai_name = "omap-mcbsp.1",
        .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name = "omap-pcm-audio",
+       .platform_name = "omap-mcbsp.1",
        .codec_name = "tlv320aic23-codec.2-001a",
        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBM_CFM,
index 56a5219c0a00587fc412caf76927adf4d11799a5..b0f8dbc1f635a7d5d7c93407b098c29ba969abcd 100644 (file)
@@ -38,7 +38,6 @@
 #include "omap-mcbsp.h"
 #include "../codecs/cx20442.h"
 
-
 /* Board specific DAPM widgets */
 static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
        /* Handset */
@@ -90,17 +89,23 @@ static const unsigned short ams_delta_audio_mode_pins[] = {
 
 static unsigned short ams_delta_audio_agc;
 
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_codec *cx20442_codec;
+
 static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &card->dapm;
        struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
        unsigned short pins;
        int pin, changed = 0;
 
        /* Refuse any mode changes if we are not able to control the codec. */
-       if (!codec->hw_write)
+       if (!cx20442_codec->hw_write)
                return -EUNATCH;
 
        if (ucontrol->value.enumerated.item[0] >= control->items)
@@ -166,8 +171,8 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
 static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &card->dapm;
        unsigned short pins, mode;
 
        pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
@@ -270,12 +275,6 @@ static void cx81801_timeout(unsigned long data)
                ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
 }
 
-/*
- * Used for passing a codec structure pointer
- * from the board initialization code to the tty line discipline.
- */
-static struct snd_soc_codec *cx20442_codec;
-
 /* Line discipline .open() */
 static int cx81801_open(struct tty_struct *tty)
 {
@@ -302,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty)
 static void cx81801_close(struct tty_struct *tty)
 {
        struct snd_soc_codec *codec = tty->disc_data;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = &codec->card->dapm;
 
        del_timer_sync(&cx81801_timer);
 
@@ -475,15 +474,14 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
 
 static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_card *card = rtd->card;
+       struct snd_soc_dapm_context *dapm = &card->dapm;
        int ret;
        /* Codec is ready, now add/activate board specific controls */
 
        /* Store a pointer to the codec structure for tty ldisc use */
-       cx20442_codec = codec;
+       cx20442_codec = rtd->codec;
 
        /* Set up digital mute if not provided by the codec */
        if (!codec_dai->driver->ops) {
@@ -520,25 +518,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
                return 0;
        }
 
-       /* Add board specific DAPM widgets and routes */
-       ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets,
-                                       ARRAY_SIZE(ams_delta_dapm_widgets));
-       if (ret) {
-               dev_warn(card->dev,
-                               "Failed to register DAPM controls, "
-                               "will continue without any.\n");
-               return 0;
-       }
-
-       ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map,
-                                       ARRAY_SIZE(ams_delta_audio_map));
-       if (ret) {
-               dev_warn(card->dev,
-                               "Failed to set up DAPM routes, "
-                               "will continue with codec default map.\n");
-               return 0;
-       }
-
        /* Set up initial pin constellation */
        snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
        snd_soc_dapm_enable_pin(dapm, "Earpiece");
@@ -547,14 +526,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_disable_pin(dapm, "AGCIN");
        snd_soc_dapm_disable_pin(dapm, "AGCOUT");
 
-       /* Add virtual switch */
-       ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls,
-                                       ARRAY_SIZE(ams_delta_audio_controls));
-       if (ret)
-               dev_warn(card->dev,
-                               "Failed to register audio mode control, "
-                               "will continue without it.\n");
-
        return 0;
 }
 
@@ -565,7 +536,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
        .cpu_dai_name = "omap-mcbsp.1",
        .codec_dai_name = "cx20442-voice",
        .init = ams_delta_cx20442_init,
-       .platform_name = "omap-pcm-audio",
+       .platform_name = "omap-mcbsp.1",
        .codec_name = "cx20442-codec",
        .ops = &ams_delta_ops,
 };
@@ -576,6 +547,13 @@ static struct snd_soc_card ams_delta_audio_card = {
        .owner = THIS_MODULE,
        .dai_link = &ams_delta_dai_link,
        .num_links = 1,
+
+       .controls = ams_delta_audio_controls,
+       .num_controls = ARRAY_SIZE(ams_delta_audio_controls),
+       .dapm_widgets = ams_delta_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets),
+       .dapm_routes = ams_delta_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map),
 };
 
 /* Module init/exit */
index fd4d9c809e50a45b1b36168add18352e343992fe..5d7f9cebe04142fd9faf0974030ff4e41ccd2664 100644 (file)
@@ -278,7 +278,7 @@ static struct snd_soc_dai_link n810_dai = {
        .name = "TLV320AIC33",
        .stream_name = "AIC33",
        .cpu_dai_name = "omap-mcbsp.2",
-       .platform_name = "omap-pcm-audio",
+       .platform_name = "omap-mcbsp.2",
        .codec_name = "tlv320aic3x-codec.2-0018",
        .codec_dai_name = "tlv320aic3x-hifi",
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
index 024dafc3e2981b752c6d9526a35644f984076f61..1a89e5b1be163bc07e35cc6d8ea274c437f18e11 100644 (file)
@@ -214,9 +214,7 @@ static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
        {
                .name = "TWL6040",
                .stream_name = "TWL6040",
-               .cpu_dai_name = "omap-mcpdm",
                .codec_dai_name = "twl6040-legacy",
-               .platform_name = "omap-pcm-audio",
                .codec_name = "twl6040-codec",
                .init = omap_abe_twl6040_init,
                .ops = &omap_abe_ops,
@@ -224,9 +222,7 @@ static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
        {
                .name = "DMIC",
                .stream_name = "DMIC Capture",
-               .cpu_dai_name = "omap-dmic",
                .codec_dai_name = "dmic-hifi",
-               .platform_name = "omap-pcm-audio",
                .codec_name = "dmic-codec",
                .init = omap_abe_dmic_init,
                .ops = &omap_abe_dmic_ops,
@@ -281,14 +277,14 @@ static int omap_abe_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "McPDM node is not provided\n");
                return -EINVAL;
        }
-       abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
        abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+       abe_twl6040_dai_links[0].platform_of_node = dai_node;
 
        dai_node = of_parse_phandle(node, "ti,dmic", 0);
        if (dai_node) {
                num_links = 2;
-               abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
                abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+               abe_twl6040_dai_links[1].platform_of_node = dai_node;
 
                priv->dmic_codec_dev = platform_device_register_simple(
                                                "dmic-codec", -1, NULL, 0);
index 1bd531d718f953c3a2cd0e533e0f4340d3713892..53da041896c4305aaa055750de1efdc00ec0862d 100644 (file)
@@ -42,6 +42,7 @@
 #include <sound/dmaengine_pcm.h>
 
 #include "omap-dmic.h"
+#include "omap-pcm.h"
 
 struct omap_dmic {
        struct device *dev;
@@ -113,7 +114,6 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
 
        mutex_unlock(&dmic->mutex);
 
-       snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
        return ret;
 }
 
@@ -417,6 +417,9 @@ static int omap_dmic_probe(struct snd_soc_dai *dai)
 
        /* Configure DMIC threshold value */
        dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
+
+       snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data);
+
        return 0;
 }
 
@@ -492,6 +495,10 @@ static int asoc_dmic_probe(struct platform_device *pdev)
        if (ret)
                goto err_put_clk;
 
+       ret = omap_pcm_platform_register(&pdev->dev);
+       if (ret)
+               goto err_put_clk;
+
        return 0;
 
 err_put_clk:
index 7e66e9cba5a8770ca2a77abbb1c3be2b3aab5a29..f649fe84b629ff1e38d8b353c6bc99bc709dc7de 100644 (file)
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link omap_hdmi_dai = {
        .name = "HDMI",
        .stream_name = "HDMI",
        .cpu_dai_name = "omap-hdmi-audio-dai",
-       .platform_name = "omap-pcm-audio",
+       .platform_name = "omap-hdmi-audio-dai",
        .codec_name = "hdmi-audio-codec",
        .codec_dai_name = "hdmi-hifi",
 };
index ced3b88b44d4380880aa7a719f5d1eee4e31e70a..537a1ec8ad61ab0b0a721fb15b608c9254c514f4 100644 (file)
@@ -36,6 +36,7 @@
 #include <video/omapdss.h>
 
 #include "omap-hdmi.h"
+#include "omap-pcm.h"
 
 #define DRV_NAME "omap-hdmi-audio-dai"
 
@@ -324,7 +325,10 @@ static int omap_hdmi_probe(struct platform_device *pdev)
        ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
                                         &omap_hdmi_dai, 1);
 
-       return ret;
+       if (ret)
+               return ret;
+
+       return omap_pcm_platform_register(&pdev->dev);
 }
 
 static int omap_hdmi_remove(struct platform_device *pdev)
index 6c19bba2357004903477a7300582d193b26f2962..71d226626f7cb88204cfbe3d60fb19fe3c2006f4 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
+#include "omap-pcm.h"
 
 #define OMAP_MCBSP_RATES       (SNDRV_PCM_RATE_8000_96000)
 
@@ -149,9 +150,6 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
                                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
        }
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream,
-                                &mcbsp->dma_data[substream->stream]);
-
        return err;
 }
 
@@ -559,6 +557,10 @@ static int omap_mcbsp_probe(struct snd_soc_dai *dai)
 
        pm_runtime_enable(mcbsp->dev);
 
+       snd_soc_dai_init_dma_data(dai,
+                                 &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+                                 &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
        return 0;
 }
 
@@ -691,7 +693,7 @@ OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
 OMAP_MCBSP_ST_CONTROLS(2);
 OMAP_MCBSP_ST_CONTROLS(3);
 
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
 {
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
@@ -701,7 +703,7 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
                return 0;
        }
 
-       switch (mcbsp->id) {
+       switch (port_id) {
        case 2: /* McBSP 2 */
                return snd_soc_add_dai_controls(cpu_dai,
                                        omap_mcbsp2_st_controls,
@@ -711,6 +713,7 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
                                        omap_mcbsp3_st_controls,
                                        ARRAY_SIZE(omap_mcbsp3_st_controls));
        default:
+               dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
                break;
        }
 
@@ -799,11 +802,15 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, mcbsp);
 
        ret = omap_mcbsp_init(pdev);
-       if (!ret)
-               return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
-                                                 &omap_mcbsp_dai, 1);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
+                                        &omap_mcbsp_dai, 1);
+       if (ret)
+               return ret;
 
-       return ret;
+       return omap_pcm_platform_register(&pdev->dev);
 }
 
 static int asoc_mcbsp_remove(struct platform_device *pdev)
index ba8386a0d8dc511c9f9b14febf9714bfa9488a30..2e3369c27be37814c0bed7e077653db63920b302 100644 (file)
@@ -39,6 +39,6 @@ enum omap_mcbsp_div {
        OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
 
 #endif
index 2f5b1536477e8895238d21f400f21370a14f3041..d8ebb52645a996b915a7986ceca61cef342b096b 100644 (file)
@@ -42,6 +42,7 @@
 #include <sound/dmaengine_pcm.h>
 
 #include "omap-mcpdm.h"
+#include "omap-pcm.h"
 
 struct mcpdm_link_config {
        u32 link_mask; /* channel mask for the direction */
@@ -265,9 +266,6 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
        }
        mutex_unlock(&mcpdm->mutex);
 
-       snd_soc_dai_set_dma_data(dai, substream,
-                                &mcpdm->dma_data[substream->stream]);
-
        return 0;
 }
 
@@ -406,6 +404,11 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
        mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
        mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
                                                        MCPDM_UP_THRES_MAX - 3;
+
+       snd_soc_dai_init_dma_data(dai,
+                                 &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+                                 &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
        return ret;
 }
 
@@ -460,6 +463,7 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 {
        struct omap_mcpdm *mcpdm;
        struct resource *res;
+       int ret;
 
        mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
        if (!mcpdm)
@@ -490,9 +494,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 
        mcpdm->dev = &pdev->dev;
 
-       return devm_snd_soc_register_component(&pdev->dev,
+       ret =  devm_snd_soc_register_component(&pdev->dev,
                                               &omap_mcpdm_component,
                                               &omap_mcpdm_dai, 1);
+       if (ret)
+               return ret;
+
+       return omap_pcm_platform_register(&pdev->dev);
 }
 
 static const struct of_device_id omap_mcpdm_of_match[] = {
index 07b8b7bc9d20f4e3cceebcb3dbb16492f51ddc46..8d809f8509c8e8867a0ddfb28e46d423dd71c19e 100644 (file)
@@ -232,31 +232,12 @@ static struct snd_soc_platform_driver omap_soc_platform = {
        .pcm_free       = omap_pcm_free_dma_buffers,
 };
 
-static int omap_pcm_probe(struct platform_device *pdev)
+int omap_pcm_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(&pdev->dev,
-                       &omap_soc_platform);
+       return devm_snd_soc_register_platform(dev, &omap_soc_platform);
 }
-
-static int omap_pcm_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver omap_pcm_driver = {
-       .driver = {
-                       .name = "omap-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = omap_pcm_probe,
-       .remove = omap_pcm_remove,
-};
-
-module_platform_driver(omap_pcm_driver);
+EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:omap-pcm-audio");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
new file mode 100644 (file)
index 0000000..c1d2f31
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * omap-pcm.h - OMAP PCM driver
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __OMAP_PCM_H__
+#define __OMAP_PCM_H__
+
+#if IS_ENABLED(CONFIG_SND_OMAP_SOC)
+int omap_pcm_platform_register(struct device *dev);
+#else
+static inline int omap_pcm_platform_register(struct device *dev)
+{
+       return 0;
+}
+#endif /* CONFIG_SND_OMAP_SOC */
+
+#endif /* __OMAP_PCM_H__ */
index 6a8d6b5f160debac623f79ad72b91dd5c77b1550..0c83e206e957423ee640309b7eeaace31113bc03 100644 (file)
@@ -239,7 +239,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
                .stream_name = "TWL4030 HiFi",
                .cpu_dai_name = "omap-mcbsp.2",
                .codec_dai_name = "twl4030-hifi",
-               .platform_name = "omap-pcm-audio",
+               .platform_name = "omap-mcbsp.2",
                .codec_name = "twl4030-codec",
                .init = omap_twl4030_init,
                .ops = &omap_twl4030_ops,
@@ -249,7 +249,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
                .stream_name = "TWL4030 Voice",
                .cpu_dai_name = "omap-mcbsp.3",
                .codec_dai_name = "twl4030-voice",
-               .platform_name = "omap-pcm-audio",
+               .platform_name = "omap-mcbsp.2",
                .codec_name = "twl4030-codec",
                .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
                           SND_SOC_DAIFMT_CBM_CFM,
@@ -299,12 +299,18 @@ static int omap_twl4030_probe(struct platform_device *pdev)
                omap_twl4030_dai_links[0].cpu_dai_name  = NULL;
                omap_twl4030_dai_links[0].cpu_of_node = dai_node;
 
+               omap_twl4030_dai_links[0].platform_name  = NULL;
+               omap_twl4030_dai_links[0].platform_of_node = dai_node;
+
                dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
                if (!dai_node) {
                        card->num_links = 1;
                } else {
                        omap_twl4030_dai_links[1].cpu_dai_name  = NULL;
                        omap_twl4030_dai_links[1].cpu_of_node = dai_node;
+
+                       omap_twl4030_dai_links[1].platform_name  = NULL;
+                       omap_twl4030_dai_links[1].platform_of_node = dai_node;
                }
 
                priv->jack_detect = of_get_named_gpio(node,
index cf604a2faa1809fe426baaa827a85020b70ef7a2..076bec606d78aabbdecd4e398522fcc03bb2e197 100644 (file)
@@ -121,7 +121,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
  *  |A| <~~clk~~+
  *  |P| <--- TWL4030 <--------- Line In and MICs
  */
-static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
        SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
                           0, 0, omap3pandora_dac_event,
                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -130,22 +130,18 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_LINE("Line Out", NULL),
-};
 
-static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("Mic (internal)", NULL),
        SND_SOC_DAPM_MIC("Mic (external)", NULL),
        SND_SOC_DAPM_LINE("Line In", NULL),
 };
 
-static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
+static const struct snd_soc_dapm_route omap3pandora_map[] = {
        {"PCM DAC", NULL, "APLL Enable"},
        {"Headphone Amplifier", NULL, "PCM DAC"},
        {"Line Out", NULL, "PCM DAC"},
        {"Headphone Jack", NULL, "Headphone Amplifier"},
-};
 
-static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
        {"AUXL", NULL, "Line In"},
        {"AUXR", NULL, "Line In"},
 
@@ -160,7 +156,6 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
 
        /* All TWL4030 output pins are floating */
        snd_soc_dapm_nc_pin(dapm, "EARPIECE");
@@ -174,20 +169,13 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "HFR");
        snd_soc_dapm_nc_pin(dapm, "VIBRA");
 
-       ret = snd_soc_dapm_new_controls(dapm, omap3pandora_out_dapm_widgets,
-                               ARRAY_SIZE(omap3pandora_out_dapm_widgets));
-       if (ret < 0)
-               return ret;
-
-       return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
-               ARRAY_SIZE(omap3pandora_out_map));
+       return 0;
 }
 
 static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
 
        /* Not comnnected */
        snd_soc_dapm_nc_pin(dapm, "HSMIC");
@@ -195,13 +183,7 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
        snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
 
-       ret = snd_soc_dapm_new_controls(dapm, omap3pandora_in_dapm_widgets,
-                               ARRAY_SIZE(omap3pandora_in_dapm_widgets));
-       if (ret < 0)
-               return ret;
-
-       return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
-               ARRAY_SIZE(omap3pandora_in_map));
+       return 0;
 }
 
 static struct snd_soc_ops omap3pandora_ops = {
@@ -215,7 +197,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
                .stream_name = "HiFi Out",
                .cpu_dai_name = "omap-mcbsp.2",
                .codec_dai_name = "twl4030-hifi",
-               .platform_name = "omap-pcm-audio",
+               .platform_name = "omap-mcbsp.2",
                .codec_name = "twl4030-codec",
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                           SND_SOC_DAIFMT_CBS_CFS,
@@ -226,7 +208,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
                .stream_name = "Line/Mic In",
                .cpu_dai_name = "omap-mcbsp.4",
                .codec_dai_name = "twl4030-hifi",
-               .platform_name = "omap-pcm-audio",
+               .platform_name = "omap-mcbsp.4",
                .codec_name = "twl4030-codec",
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                           SND_SOC_DAIFMT_CBS_CFS,
@@ -241,6 +223,11 @@ static struct snd_soc_card snd_soc_card_omap3pandora = {
        .owner = THIS_MODULE,
        .dai_link = omap3pandora_dai,
        .num_links = ARRAY_SIZE(omap3pandora_dai),
+
+       .dapm_widgets = omap3pandora_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
+       .dapm_routes = omap3pandora_map,
+       .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
 };
 
 static struct platform_device *omap3pandora_snd_device;
index d03e57da7708f495282e5a801c1eccc9bdd864de..aa4053bf6710f88cd50d9d3225754152e7caa435 100644 (file)
@@ -96,7 +96,7 @@ static struct snd_soc_dai_link osk_dai = {
        .stream_name = "AIC23",
        .cpu_dai_name = "omap-mcbsp.1",
        .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name = "omap-pcm-audio",
+       .platform_name = "omap-mcbsp.1",
        .codec_name = "tlv320aic23-codec",
        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBM_CFM,
index 7fb3d4b103701c5a38a6bf25d4dc75b2fa32543c..866578bcda5580a42f02f764a568eb840fe6b3f0 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 
 #include "omap-mcbsp.h"
 
-#define RX51_TVOUT_SEL_GPIO            40
-#define RX51_JACK_DETECT_GPIO          177
-#define RX51_ECI_SW_GPIO               182
-/*
- * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
- * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
- */
-#define RX51_SPEAKER_AMP_TWL_GPIO      (192 + 7)
-
 enum {
        RX51_JACK_DISABLED,
        RX51_JACK_TVOUT,                /* tv-out with stereo output */
@@ -54,12 +46,21 @@ enum {
        RX51_JACK_HS,                   /* headset: stereo output with mic */
 };
 
+struct rx51_audio_pdata {
+       struct gpio_desc *tvout_selection_gpio;
+       struct gpio_desc *jack_detection_gpio;
+       struct gpio_desc *eci_sw_gpio;
+       struct gpio_desc *speaker_amp_gpio;
+};
+
 static int rx51_spk_func;
 static int rx51_dmic_func;
 static int rx51_jack_func;
 
 static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
 {
+       struct snd_soc_card *card = dapm->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
        int hp = 0, hs = 0, tvout = 0;
 
        switch (rx51_jack_func) {
@@ -93,7 +94,7 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
        else
                snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
 
-       gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
+       gpiod_set_value(pdata->tvout_selection_gpio, tvout);
 
        snd_soc_dapm_sync_unlocked(dapm);
 
@@ -154,10 +155,12 @@ static int rx51_set_spk(struct snd_kcontrol *kcontrol,
 static int rx51_spk_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *k, int event)
 {
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
-       else
-               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
+       gpiod_set_raw_value_cansleep(pdata->speaker_amp_gpio,
+                                    !!SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
 }
@@ -223,7 +226,6 @@ static struct snd_soc_jack rx51_av_jack;
 
 static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
        {
-               .gpio = RX51_JACK_DETECT_GPIO,
                .name = "avdet-gpio",
                .report = SND_JACK_HEADSET,
                .invert = 1,
@@ -237,9 +239,6 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
        SND_SOC_DAPM_MIC("HS Mic", NULL),
        SND_SOC_DAPM_LINE("FM Transmitter", NULL),
-};
-
-static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
        SND_SOC_DAPM_SPK("Earphone", NULL),
 };
 
@@ -253,9 +252,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
        {"DMic Rate 64", NULL, "Mic Bias"},
        {"Mic Bias", NULL, "DMic"},
-};
 
-static const struct snd_soc_dapm_route audio_mapb[] = {
        {"b LINE2R", NULL, "MONO_LOUT"},
        {"Earphone", NULL, "b HPLOUT"},
 
@@ -263,9 +260,11 @@ static const struct snd_soc_dapm_route audio_mapb[] = {
        {"b Mic Bias", NULL, "HS Mic"}
 };
 
-static const char *spk_function[] = {"Off", "On"};
-static const char *input_function[] = {"ADC", "Digital Mic"};
-static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"};
+static const char * const spk_function[] = {"Off", "On"};
+static const char * const input_function[] = {"ADC", "Digital Mic"};
+static const char * const jack_function[] = {
+       "Off", "TV-OUT", "Headphone", "Headset"
+};
 
 static const struct soc_enum rx51_enum[] = {
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
@@ -281,15 +280,15 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
        SOC_ENUM_EXT("Jack Function", rx51_enum[2],
                     rx51_get_jack, rx51_set_jack),
        SOC_DAPM_PIN_SWITCH("FM Transmitter"),
-};
-
-static const struct snd_kcontrol_new aic34_rx51_controlsb[] = {
        SOC_DAPM_PIN_SWITCH("Earphone"),
 };
 
 static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
@@ -298,57 +297,41 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "MIC3R");
        snd_soc_dapm_nc_pin(dapm, "LINE1R");
 
-       /* Add RX-51 specific controls */
-       err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls,
-                                  ARRAY_SIZE(aic34_rx51_controls));
-       if (err < 0)
-               return err;
-
-       /* Add RX-51 specific widgets */
-       snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
-                                 ARRAY_SIZE(aic34_dapm_widgets));
-
-       /* Set up RX-51 specific audio path audio_map */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        err = tpa6130a2_add_controls(codec);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
                return err;
+       }
        snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
 
-       err = omap_mcbsp_st_add_controls(rtd);
-       if (err < 0)
+       err = omap_mcbsp_st_add_controls(rtd, 2);
+       if (err < 0) {
+               dev_err(card->dev, "Failed to add MCBSP controls\n");
                return err;
+       }
 
        /* AV jack detection */
        err = snd_soc_jack_new(codec, "AV Jack",
                               SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
                               &rx51_av_jack);
-       if (err)
+       if (err) {
+               dev_err(card->dev, "Failed to add AV Jack\n");
                return err;
+       }
+
+       /* prepare gpio for snd_soc_jack_add_gpios */
+       rx51_av_jack_gpios[0].gpio = desc_to_gpio(pdata->jack_detection_gpio);
+       devm_gpiod_put(card->dev, pdata->jack_detection_gpio);
+
        err = snd_soc_jack_add_gpios(&rx51_av_jack,
                                     ARRAY_SIZE(rx51_av_jack_gpios),
                                     rx51_av_jack_gpios);
-
-       return err;
-}
-
-static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
-{
-       int err;
-
-       err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb,
-                                  ARRAY_SIZE(aic34_rx51_controlsb));
-       if (err < 0)
+       if (err) {
+               dev_err(card->dev, "Failed to add GPIOs\n");
                return err;
+       }
 
-       err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb,
-                                       ARRAY_SIZE(aic34_dapm_widgetsb));
-       if (err < 0)
-               return 0;
-
-       return snd_soc_dapm_add_routes(dapm, audio_mapb,
-                                      ARRAY_SIZE(audio_mapb));
+       return err;
 }
 
 /* Digital audio interface glue - connects codec <--> CPU */
@@ -358,7 +341,7 @@ static struct snd_soc_dai_link rx51_dai[] = {
                .stream_name = "AIC34",
                .cpu_dai_name = "omap-mcbsp.2",
                .codec_dai_name = "tlv320aic3x-hifi",
-               .platform_name = "omap-pcm-audio",
+               .platform_name = "omap-mcbsp.2",
                .codec_name = "tlv320aic3x-codec.2-0018",
                .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
                           SND_SOC_DAIFMT_CBM_CFM,
@@ -371,7 +354,6 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
        {
                .name = "TLV320AIC34b",
                .codec_name = "tlv320aic3x-codec.2-0019",
-               .init = rx51_aic34b_init,
        },
 };
 
@@ -392,63 +374,160 @@ static struct snd_soc_card rx51_sound_card = {
        .num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
        .codec_conf = rx51_codec_conf,
        .num_configs = ARRAY_SIZE(rx51_codec_conf),
-};
 
-static struct platform_device *rx51_snd_device;
+       .controls = aic34_rx51_controls,
+       .num_controls = ARRAY_SIZE(aic34_rx51_controls),
+       .dapm_widgets = aic34_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
 
-static int __init rx51_soc_init(void)
+static int rx51_soc_probe(struct platform_device *pdev)
 {
+       struct rx51_audio_pdata *pdata;
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &rx51_sound_card;
        int err;
 
        if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
                return -ENODEV;
 
-       err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
-                              GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel");
-       if (err)
-               goto err_gpio_tvout_sel;
-       err = gpio_request_one(RX51_ECI_SW_GPIO,
-                              GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw");
-       if (err)
-               goto err_gpio_eci_sw;
-
-       rx51_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!rx51_snd_device) {
-               err = -ENOMEM;
-               goto err1;
+       card->dev = &pdev->dev;
+
+       if (np) {
+               struct device_node *dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McBSP node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_dai[0].cpu_dai_name = NULL;
+               rx51_dai[0].platform_name = NULL;
+               rx51_dai[0].cpu_of_node = dai_node;
+               rx51_dai[0].platform_of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Codec node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_dai[0].codec_name = NULL;
+               rx51_dai[0].codec_of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_aux_dev[0].codec_name = NULL;
+               rx51_aux_dev[0].codec_of_node = dai_node;
+               rx51_codec_conf[0].dev_name = NULL;
+               rx51_codec_conf[0].of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
+                       return -EINVAL;
+               }
+
+               /* TODO: tpa6130a2a driver supports only a single instance, so
+                * this driver ignores the headphone-amplifier node for now.
+                * It's already mandatory in the DT binding to be future proof.
+                */
        }
 
-       platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (pdata == NULL) {
+               dev_err(card->dev, "failed to create private data\n");
+               return -ENOMEM;
+       }
+       snd_soc_card_set_drvdata(card, pdata);
 
-       err = platform_device_add(rx51_snd_device);
-       if (err)
-               goto err2;
+       pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
+                                                    "tvout-selection");
+       if (IS_ERR(pdata->tvout_selection_gpio)) {
+               dev_err(card->dev, "could not get tvout selection gpio\n");
+               return PTR_ERR(pdata->tvout_selection_gpio);
+       }
 
-       return 0;
-err2:
-       platform_device_put(rx51_snd_device);
-err1:
-       gpio_free(RX51_ECI_SW_GPIO);
-err_gpio_eci_sw:
-       gpio_free(RX51_TVOUT_SEL_GPIO);
-err_gpio_tvout_sel:
+       err = gpiod_direction_output(pdata->tvout_selection_gpio, 0);
+       if (err) {
+               dev_err(card->dev, "could not setup tvout selection gpio\n");
+               return err;
+       }
 
-       return err;
+       pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
+                                                   "jack-detection");
+       if (IS_ERR(pdata->jack_detection_gpio)) {
+               dev_err(card->dev, "could not get jack detection gpio\n");
+               return PTR_ERR(pdata->jack_detection_gpio);
+       }
+
+       pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch");
+       if (IS_ERR(pdata->eci_sw_gpio)) {
+               dev_err(card->dev, "could not get eci switch gpio\n");
+               return PTR_ERR(pdata->eci_sw_gpio);
+       }
+
+       err = gpiod_direction_output(pdata->eci_sw_gpio, 1);
+       if (err) {
+               dev_err(card->dev, "could not setup eci switch gpio\n");
+               return err;
+       }
+
+       pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
+                                                "speaker-amplifier");
+       if (IS_ERR(pdata->speaker_amp_gpio)) {
+               dev_err(card->dev, "could not get speaker enable gpio\n");
+               return PTR_ERR(pdata->speaker_amp_gpio);
+       }
+
+       err = gpiod_direction_output(pdata->speaker_amp_gpio, 0);
+       if (err) {
+               dev_err(card->dev, "could not setup speaker enable gpio\n");
+               return err;
+       }
+
+       err = devm_snd_soc_register_card(card->dev, card);
+       if (err) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
+               return err;
+       }
+
+       return 0;
 }
 
-static void __exit rx51_soc_exit(void)
+static int rx51_soc_remove(struct platform_device *pdev)
 {
        snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
                                rx51_av_jack_gpios);
 
-       platform_device_unregister(rx51_snd_device);
-       gpio_free(RX51_ECI_SW_GPIO);
-       gpio_free(RX51_TVOUT_SEL_GPIO);
+       return 0;
 }
 
-module_init(rx51_soc_init);
-module_exit(rx51_soc_exit);
+#if defined(CONFIG_OF)
+static const struct of_device_id rx51_audio_of_match[] = {
+       { .compatible = "nokia,n900-audio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rx51_audio_of_match);
+#endif
+
+static struct platform_driver rx51_soc_driver = {
+       .driver = {
+               .name = "rx51-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(rx51_audio_of_match),
+       },
+       .probe = rx51_soc_probe,
+       .remove = rx51_soc_remove,
+};
+
+module_platform_driver(rx51_soc_driver);
 
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rx51-audio");
index 6473052b689963996713e44e601181ec2e14b47e..6acb225ec6fdf40bec7a3738169c5d47947d979e 100644 (file)
@@ -140,7 +140,7 @@ config SND_PXA910_SOC
 
 config SND_SOC_TTC_DKB
        bool "SoC Audio support for TTC DKB"
-       depends on SND_PXA910_SOC && MACH_TTC_DKB
+       depends on SND_PXA910_SOC && MACH_TTC_DKB && I2C=y
        select PXA_SSP
        select SND_PXA_SOC_SSP
        select SND_MMP_SOC
index f2e289180e466ef0a9d673eea33f7ab0aaca1bd3..753b8c93ab51774847fd77f16de2d1c65103b6ac 100644 (file)
@@ -64,6 +64,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
 config SND_SOC_SAMSUNG_SMDK_WM8580
        tristate "SoC I2S Audio support for WM8580 on SMDK"
        depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+       depends on REGMAP_I2C
        select SND_SOC_WM8580
        select SND_SAMSUNG_I2S
        help
@@ -115,21 +116,21 @@ config SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
        tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
        select SND_S3C24XX_I2S
        select SND_SOC_TLV320AIC23_I2C
        select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
        tristate "SoC I2S Audio support for Simtec Hermes board"
-       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
        select SND_S3C24XX_I2S
        select SND_SOC_TLV320AIC3X
        select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_H1940_UDA1380
        tristate "Audio support for the HP iPAQ H1940"
-       depends on SND_SOC_SAMSUNG && ARCH_H1940
+       depends on SND_SOC_SAMSUNG && ARCH_H1940 && I2C
        select SND_S3C24XX_I2S
        select SND_SOC_UDA1380
        help
@@ -137,7 +138,7 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
 
 config SND_SOC_SAMSUNG_RX1950_UDA1380
        tristate "Audio support for the HP iPAQ RX1950"
-       depends on SND_SOC_SAMSUNG && MACH_RX1950
+       depends on SND_SOC_SAMSUNG && MACH_RX1950 && I2C
        select SND_S3C24XX_I2S
        select SND_SOC_UDA1380
        help
@@ -178,6 +179,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
 config SND_SOC_SMDK_WM8580_PCM
        tristate "SoC PCM Audio support for WM8580 on SMDK"
        depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+       depends on REGMAP_I2C
        select SND_SOC_WM8580
        select SND_SAMSUNG_PCM
        help
@@ -204,7 +206,7 @@ config SND_SOC_SPEYSIDE
 
 config SND_SOC_TOBERMORY
        tristate "Audio support for Wolfson Tobermory"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && INPUT
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8962
 
@@ -231,3 +233,13 @@ config SND_SOC_LITTLEMILL
        select SND_SAMSUNG_I2S
        select MFD_WM8994
        select SND_SOC_WM8994
+
+config SND_SOC_SNOW
+       tristate "Audio support for Google Snow boards"
+       depends on SND_SOC_SAMSUNG
+       select SND_SOC_MAX98090
+       select SND_SOC_MAX98095
+       select SND_SAMSUNG_I2S
+       help
+         Say Y if you want to add audio support for various Snow
+         boards based on Exynos5 series of SoCs.
index 86715d8efee66ca459adc99c2d68ca34907b1c45..6d0212ba571c5f66be711317b1d61b5e89e9e690 100644 (file)
@@ -34,6 +34,7 @@ snd-soc-h1940-uda1380-objs := h1940_uda1380.o
 snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
 snd-soc-smdk-wm8580-objs := smdk_wm8580.o
 snd-soc-smdk-wm8994-objs := smdk_wm8994.o
+snd-soc-snow-objs := snow.o
 snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-goni-wm8994-objs := goni_wm8994.o
@@ -58,6 +59,7 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_H1940_UDA1380) += snd-soc-h1940-uda1380.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
+obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
 obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
index 048ead96719984f85b2b1bc048e2c81b30cc9fb3..6e61db75ec4efde83aba521580a50b608f3dd503 100644 (file)
@@ -724,9 +724,6 @@ static int i2s_startup(struct snd_pcm_substream *substream,
        else
                i2s->mode |= DAI_MANAGER;
 
-       /* Enforce set_sysclk in Master mode */
-       i2s->rclk_srcrate = 0;
-
        if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR))
                writel(CON_RSTCLR, i2s->addr + I2SCON);
 
@@ -984,6 +981,7 @@ probe_exit:
        /* Reset any constraint on RFS and BFS */
        i2s->rfs = 0;
        i2s->bfs = 0;
+       i2s->rclk_srcrate = 0;
        i2s_txctrl(i2s, 0);
        i2s_rxctrl(i2s, 0);
        i2s_fifo(i2s, FIC_TXFLUSH);
index 3d5cf1530b6f754c4ff03c476777e2a61c3d45a1..e9891b44f0e2122514f076913bf35d82bfdb1ccb 100644 (file)
@@ -274,7 +274,7 @@ static irqreturn_t iis_irq(int irqno, void *dev_id)
 
                addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
                addr += prtd->periodsz;
-               addr %= (prtd->end - prtd->start);
+               addr %= (u32)(prtd->end - prtd->start);
                addr += idma.lp_tx_addr;
 
                writel(addr, idma.regs + I2SLVL0ADDR);
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
new file mode 100644 (file)
index 0000000..0fa89a4
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * ASoC machine driver for Snow boards
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <sound/soc.h>
+
+#include "i2s.h"
+
+#define FIN_PLL_RATE           24000000
+
+static struct snd_soc_dai_link snow_dai[] = {
+       {
+               .name = "Primary",
+               .stream_name = "Primary",
+               .codec_dai_name = "HiFi",
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                               SND_SOC_DAIFMT_NB_NF |
+                               SND_SOC_DAIFMT_CBS_CFS,
+       },
+};
+
+static int snow_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+       int ret;
+
+       /* Set the MCLK rate for the codec */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+                                       FIN_PLL_RATE, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* Select I2S Bus clock to set RCLK and BCLK */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+                                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_card snow_snd = {
+       .name = "Snow-I2S",
+       .dai_link = snow_dai,
+       .num_links = ARRAY_SIZE(snow_dai),
+
+       .late_probe = snow_late_probe,
+};
+
+static int snow_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snow_snd;
+       struct device_node *i2s_node, *codec_node;
+       int i, ret;
+
+       i2s_node = of_parse_phandle(pdev->dev.of_node,
+                                   "samsung,i2s-controller", 0);
+       if (!i2s_node) {
+               dev_err(&pdev->dev,
+                       "Property 'i2s-controller' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       codec_node = of_parse_phandle(pdev->dev.of_node,
+                                     "samsung,audio-codec", 0);
+       if (!codec_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(snow_dai); i++) {
+               snow_dai[i].codec_of_node = codec_node;
+               snow_dai[i].cpu_of_node = i2s_node;
+               snow_dai[i].platform_of_node = i2s_node;
+       }
+
+       card->dev = &pdev->dev;
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static const struct of_device_id snow_of_match[] = {
+       { .compatible = "google,snow-audio-max98090", },
+       { .compatible = "google,snow-audio-max98095", },
+       {},
+};
+
+static struct platform_driver snow_driver = {
+       .driver = {
+               .name = "snow-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = snow_of_match,
+       },
+       .probe = snow_probe,
+};
+
+module_platform_driver(snow_driver);
+
+MODULE_DESCRIPTION("ALSA SoC Audio machine driver for Snow");
+MODULE_LICENSE("GPL");
index ff60e11ecb564674bdffbe8814392fe1b2b01065..b43fdf0d08afe088740b604ebeaed624833782fd 100644 (file)
@@ -56,7 +56,7 @@ config SND_SH7760_AC97
 
 config SND_SIU_MIGOR
        tristate "SIU sound support on Migo-R"
-       depends on SH_MIGOR
+       depends on SH_MIGOR && I2C
        select SND_SOC_SH4_SIU
        select SND_SOC_WM8978
        help
index 215b668166be6c50d01963cac2ef62598cf6f7b2..89424470a1f3860eab989eabeab579184e070359 100644 (file)
@@ -197,13 +197,12 @@ static void rsnd_dma_complete(void *data)
         * rsnd_dai_pointer_update() will be called twice,
         * ant it will breaks io->byte_pos
         */
-
-       rsnd_dai_pointer_update(io, io->byte_per_period);
-
        if (dma->submit_loop)
                rsnd_dma_continue(dma);
 
        rsnd_unlock(priv, flags);
+
+       rsnd_dai_pointer_update(io, io->byte_per_period);
 }
 
 static void __rsnd_dma_start(struct rsnd_dma *dma)
index 6232b7d307aab2c553bad3c7b6a19f7f69ac997e..4d0720ed5a906d86315971a869028011c3c3a7af 100644 (file)
@@ -258,7 +258,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-       clk_enable(src->clk);
+       clk_prepare_enable(src->clk);
 
        return 0;
 }
@@ -269,7 +269,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-       clk_disable(src->clk);
+       clk_disable_unprepare(src->clk);
 
        return 0;
 }
index 4b7e20603dd7be8032198291ee08ed9b95de88dd..1d8387c25bd85f5b312db49e42109fdfd064815f 100644 (file)
@@ -171,7 +171,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
        u32 cr;
 
        if (0 == ssi->usrcnt) {
-               clk_enable(ssi->clk);
+               clk_prepare_enable(ssi->clk);
 
                if (rsnd_dai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
@@ -230,7 +230,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
                                rsnd_ssi_master_clk_stop(ssi);
                }
 
-               clk_disable(ssi->clk);
+               clk_disable_unprepare(ssi->clk);
        }
 
        dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
index b04a53f2b4f63e56b72ed395faf89cc823f832a2..b4afa31b2bc11ea00baf93c22a6cf244d47732e5 100644 (file)
@@ -6,60 +6,15 @@
  * Licensed under GPLv2 or later.
  */
 #include <linux/module.h>
-#include <linux/io.h>
-#include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
-#include "sirf-audio-port.h"
-
 struct sirf_audio_port {
        struct regmap *regmap;
        struct snd_dmaengine_dai_dma_data playback_dma_data;
        struct snd_dmaengine_dai_dma_data capture_dma_data;
 };
 
-static void sirf_audio_port_tx_enable(struct sirf_audio_port *port)
-{
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
-       regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
-       regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-               AUDIO_FIFO_START, AUDIO_FIFO_START);
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
-               IC_TX_ENABLE, IC_TX_ENABLE);
-}
-
-static void sirf_audio_port_tx_disable(struct sirf_audio_port *port)
-{
-       regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
-               IC_TX_ENABLE, ~IC_TX_ENABLE);
-}
-
-static void sirf_audio_port_rx_enable(struct sirf_audio_port *port,
-       int channels)
-{
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
-       regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
-       regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-               AUDIO_FIFO_START, AUDIO_FIFO_START);
-       if (channels == 1)
-               regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
-                       IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
-       else
-               regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
-                       IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
-}
-
-static void sirf_audio_port_rx_disable(struct sirf_audio_port *port)
-{
-       regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
-                       IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
-}
 
 static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
 {
@@ -69,41 +24,6 @@ static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
-static int sirf_audio_port_trigger(struct snd_pcm_substream *substream, int cmd,
-       struct snd_soc_dai *dai)
-{
-       struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
-       int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (playback)
-                       sirf_audio_port_tx_disable(port);
-               else
-                       sirf_audio_port_rx_disable(port);
-               break;
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (playback)
-                       sirf_audio_port_tx_enable(port);
-               else
-                       sirf_audio_port_rx_enable(port,
-                               substream->runtime->channels);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = {
-       .trigger = sirf_audio_port_trigger,
-};
-
 static struct snd_soc_dai_driver sirf_audio_port_dai = {
        .probe = sirf_audio_port_dai_probe,
        .name = "sirf-audio-port",
@@ -120,49 +40,22 @@ static struct snd_soc_dai_driver sirf_audio_port_dai = {
                .rates = SNDRV_PCM_RATE_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
-       .ops = &sirf_audio_port_dai_ops,
 };
 
 static const struct snd_soc_component_driver sirf_audio_port_component = {
        .name       = "sirf-audio-port",
 };
 
-static const struct regmap_config sirf_audio_port_regmap_config = {
-       .reg_bits = 32,
-       .reg_stride = 4,
-       .val_bits = 32,
-       .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
-       .cache_type = REGCACHE_NONE,
-};
-
 static int sirf_audio_port_probe(struct platform_device *pdev)
 {
        int ret;
        struct sirf_audio_port *port;
-       void __iomem *base;
-       struct resource *mem_res;
 
        port = devm_kzalloc(&pdev->dev,
                        sizeof(struct sirf_audio_port), GFP_KERNEL);
        if (!port)
                return -ENOMEM;
 
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem_res) {
-               dev_err(&pdev->dev, "no mem resource?\n");
-               return -ENODEV;
-       }
-
-       base = devm_ioremap(&pdev->dev, mem_res->start,
-                       resource_size(mem_res));
-       if (base == NULL)
-               return -ENOMEM;
-
-       port->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-                                           &sirf_audio_port_regmap_config);
-       if (IS_ERR(port->regmap))
-               return PTR_ERR(port->regmap);
-
        ret = devm_snd_soc_register_component(&pdev->dev,
                        &sirf_audio_port_component, &sirf_audio_port_dai, 1);
        if (ret)
diff --git a/sound/soc/sirf/sirf-audio-port.h b/sound/soc/sirf/sirf-audio-port.h
deleted file mode 100644 (file)
index f32dc54..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SiRF Audio port controllers define
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#ifndef _SIRF_AUDIO_PORT_H
-#define _SIRF_AUDIO_PORT_H
-
-#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK     0x3F
-#define AUDIO_PORT_TX_FIFO_SC_OFFSET    0
-#define AUDIO_PORT_TX_FIFO_LC_OFFSET    10
-#define AUDIO_PORT_TX_FIFO_HC_OFFSET    20
-
-#define TX_FIFO_SC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_TX_FIFO_SC_OFFSET)
-#define TX_FIFO_LC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_TX_FIFO_LC_OFFSET)
-#define TX_FIFO_HC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_TX_FIFO_HC_OFFSET)
-
-#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK     0x0F
-#define AUDIO_PORT_RX_FIFO_SC_OFFSET    0
-#define AUDIO_PORT_RX_FIFO_LC_OFFSET    10
-#define AUDIO_PORT_RX_FIFO_HC_OFFSET    20
-
-#define RX_FIFO_SC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_RX_FIFO_SC_OFFSET)
-#define RX_FIFO_LC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_RX_FIFO_LC_OFFSET)
-#define RX_FIFO_HC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_RX_FIFO_HC_OFFSET)
-#define AUDIO_PORT_IC_CODEC_TX_CTRL            (0x00F4)
-#define AUDIO_PORT_IC_CODEC_RX_CTRL            (0x00F8)
-
-#define AUDIO_PORT_IC_TXFIFO_OP                        (0x00FC)
-#define AUDIO_PORT_IC_TXFIFO_LEV_CHK           (0x0100)
-#define AUDIO_PORT_IC_TXFIFO_STS               (0x0104)
-#define AUDIO_PORT_IC_TXFIFO_INT               (0x0108)
-#define AUDIO_PORT_IC_TXFIFO_INT_MSK           (0x010C)
-
-#define AUDIO_PORT_IC_RXFIFO_OP                        (0x0110)
-#define AUDIO_PORT_IC_RXFIFO_LEV_CHK           (0x0114)
-#define AUDIO_PORT_IC_RXFIFO_STS               (0x0118)
-#define AUDIO_PORT_IC_RXFIFO_INT               (0x011C)
-#define AUDIO_PORT_IC_RXFIFO_INT_MSK           (0x0120)
-
-#define AUDIO_FIFO_START               (1 << 0)
-#define AUDIO_FIFO_RESET               (1 << 1)
-
-#define AUDIO_FIFO_FULL                        (1 << 0)
-#define AUDIO_FIFO_EMPTY               (1 << 1)
-#define AUDIO_FIFO_OFLOW               (1 << 2)
-#define AUDIO_FIFO_UFLOW               (1 << 3)
-
-#define IC_TX_ENABLE           (0x03)
-#define IC_RX_ENABLE_MONO      (0x01)
-#define IC_RX_ENABLE_STEREO    (0x03)
-
-#endif /*__SIRF_AUDIO_PORT_H*/
index bfed3e4c45ffa708910e580bf02359a7b6b3c509..3fa77d5f9b75c0b7f442669301f4bf667eab8f7c 100644 (file)
@@ -162,8 +162,6 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
                                                  i, codec_drv->reg_word_size) == val)
                                continue;
 
-               WARN_ON(!snd_soc_codec_writable_register(codec, i));
-
                ret = snd_soc_write(codec, i, val);
                if (ret)
                        return ret;
index 051c006281f5c2c003583f7104c9ec02dc886dfc..ff2b32fa43699cfcaaa91e5b687de8273edb11c0 100644 (file)
@@ -154,22 +154,15 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
                step = codec->driver->reg_cache_step;
 
        for (i = 0; i < codec->driver->reg_cache_size; i += step) {
-               if (!snd_soc_codec_readable_register(codec, i))
-                       continue;
-               if (codec->driver->display_register) {
-                       count += codec->driver->display_register(codec, buf + count,
-                                                        PAGE_SIZE - count, i);
-               } else {
-                       /* only support larger than PAGE_SIZE bytes debugfs
-                        * entries for the default case */
-                       if (p >= pos) {
-                               if (total + len >= count - 1)
-                                       break;
-                               format_register_str(codec, i, buf + total, len);
-                               total += len;
-                       }
-                       p += len;
+               /* only support larger than PAGE_SIZE bytes debugfs
+                * entries for the default case */
+               if (p >= pos) {
+                       if (total + len >= count - 1)
+                               break;
+                       format_register_str(codec, i, buf + total, len);
+                       total += len;
                }
+               p += len;
        }
 
        total = min(total, count - 1);
@@ -663,8 +656,8 @@ int snd_soc_suspend(struct device *dev)
                                codec->driver->suspend(codec);
                                codec->suspended = 1;
                                codec->cache_sync = 1;
-                               if (codec->using_regmap)
-                                       regcache_mark_dirty(codec->control_data);
+                               if (codec->component.regmap)
+                                       regcache_mark_dirty(codec->component.regmap);
                                /* deactivate pins to sleep state */
                                pinctrl_pm_select_sleep_state(codec->dev);
                                break;
@@ -854,14 +847,47 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
 static const struct snd_soc_dai_ops null_dai_ops = {
 };
 
+static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_node,
+                                           const char *codec_name)
+{
+       struct snd_soc_codec *codec;
+
+       list_for_each_entry(codec, &codec_list, list) {
+               if (codec_of_node) {
+                       if (codec->dev->of_node != codec_of_node)
+                               continue;
+               } else {
+                       if (strcmp(codec->name, codec_name))
+                               continue;
+               }
+
+               return codec;
+       }
+
+       return NULL;
+}
+
+static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec,
+                                             const char *codec_dai_name)
+{
+       struct snd_soc_dai *codec_dai;
+
+       list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
+               if (!strcmp(codec_dai->name, codec_dai_name)) {
+                       return codec_dai;
+               }
+       }
+
+       return NULL;
+}
+
 static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_component *component;
-       struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
-       struct snd_soc_dai *codec_dai, *cpu_dai;
+       struct snd_soc_dai *cpu_dai;
        const char *platform_name;
 
        dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
@@ -889,42 +915,24 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                return -EPROBE_DEFER;
        }
 
-       /* Find CODEC from registered CODECs */
-       list_for_each_entry(codec, &codec_list, list) {
-               if (dai_link->codec_of_node) {
-                       if (codec->dev->of_node != dai_link->codec_of_node)
-                               continue;
-               } else {
-                       if (strcmp(codec->name, dai_link->codec_name))
-                               continue;
-               }
-
-               rtd->codec = codec;
-
-               /*
-                * CODEC found, so find CODEC DAI from registered DAIs from
-                * this CODEC
-                */
-               list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
-                       if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
-                               rtd->codec_dai = codec_dai;
-                               break;
-                       }
-               }
-
-               if (!rtd->codec_dai) {
-                       dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
-                               dai_link->codec_dai_name);
-                       return -EPROBE_DEFER;
-               }
-       }
-
+       /* Find CODEC from registered list */
+       rtd->codec = soc_find_codec(dai_link->codec_of_node,
+                                   dai_link->codec_name);
        if (!rtd->codec) {
                dev_err(card->dev, "ASoC: CODEC %s not registered\n",
                        dai_link->codec_name);
                return -EPROBE_DEFER;
        }
 
+       /* Find CODEC DAI from registered list */
+       rtd->codec_dai = soc_find_codec_dai(rtd->codec,
+                                           dai_link->codec_dai_name);
+       if (!rtd->codec_dai) {
+               dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
+                       dai_link->codec_dai_name);
+               return -EPROBE_DEFER;
+       }
+
        /* if there's no platform we match on the empty platform */
        platform_name = dai_link->platform_name;
        if (!platform_name && !dai_link->platform_of_node)
@@ -995,21 +1003,10 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
        module_put(codec->dev->driver->owner);
 }
 
-static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
+static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order)
 {
-       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
        int err;
 
-       /* unregister the rtd device */
-       if (rtd->dev_registered) {
-               device_remove_file(rtd->dev, &dev_attr_pmdown_time);
-               device_remove_file(rtd->dev, &dev_attr_codec_reg);
-               device_unregister(rtd->dev);
-               rtd->dev_registered = 0;
-       }
-
-       /* remove the CODEC DAI */
        if (codec_dai && codec_dai->probed &&
                        codec_dai->driver->remove_order == order) {
                if (codec_dai->driver->remove) {
@@ -1022,6 +1019,24 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
                codec_dai->probed = 0;
                list_del(&codec_dai->card_list);
        }
+}
+
+static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
+{
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+       int err;
+
+       /* unregister the rtd device */
+       if (rtd->dev_registered) {
+               device_remove_file(rtd->dev, &dev_attr_pmdown_time);
+               device_remove_file(rtd->dev, &dev_attr_codec_reg);
+               device_unregister(rtd->dev);
+               rtd->dev_registered = 0;
+       }
+
+       /* remove the CODEC DAI */
+       soc_remove_codec_dai(codec_dai, order);
 
        /* remove the cpu_dai */
        if (cpu_dai && cpu_dai->probed &&
@@ -1104,10 +1119,12 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
 
        for (i = 0; i < card->num_configs; i++) {
                struct snd_soc_codec_conf *map = &card->codec_conf[i];
-               if (map->dev_name && !strcmp(codec->name, map->dev_name)) {
-                       codec->name_prefix = map->name_prefix;
-                       break;
-               }
+               if (map->of_node && codec->dev->of_node != map->of_node)
+                       continue;
+               if (map->dev_name && strcmp(codec->name, map->dev_name))
+                       continue;
+               codec->name_prefix = map->name_prefix;
+               break;
        }
 }
 
@@ -1127,26 +1144,31 @@ static int soc_probe_codec(struct snd_soc_card *card,
 
        soc_init_codec_debugfs(codec);
 
-       if (driver->dapm_widgets)
-               snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
-                                         driver->num_dapm_widgets);
+       if (driver->dapm_widgets) {
+               ret = snd_soc_dapm_new_controls(&codec->dapm,
+                                               driver->dapm_widgets,
+                                               driver->num_dapm_widgets);
 
-       /* Create DAPM widgets for each DAI stream */
-       list_for_each_entry(dai, &codec->component.dai_list, list)
-               snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to create new controls %d\n", ret);
+                       goto err_probe;
+               }
+       }
 
-       codec->dapm.idle_bias_off = driver->idle_bias_off;
+       /* Create DAPM widgets for each DAI stream */
+       list_for_each_entry(dai, &codec->component.dai_list, list) {
+               ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
 
-       if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
-               /* Set the default I/O up try regmap */
-               ret = snd_soc_codec_set_cache_io(codec, NULL);
-               if (ret < 0) {
+               if (ret != 0) {
                        dev_err(codec->dev,
-                               "Failed to set cache I/O: %d\n", ret);
+                               "Failed to create DAI widgets %d\n", ret);
                        goto err_probe;
                }
        }
 
+       codec->dapm.idle_bias_off = driver->idle_bias_off;
+
        if (driver->probe) {
                ret = driver->probe(codec);
                if (ret < 0) {
@@ -1246,6 +1268,50 @@ static void rtd_release(struct device *dev)
        kfree(dev);
 }
 
+static int soc_aux_dev_init(struct snd_soc_card *card,
+                           struct snd_soc_codec *codec,
+                           int num)
+{
+       struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+       struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
+       int ret;
+
+       rtd->card = card;
+
+       /* do machine specific initialization */
+       if (aux_dev->init) {
+               ret = aux_dev->init(&codec->dapm);
+               if (ret < 0)
+                       return ret;
+       }
+
+       rtd->codec = codec;
+
+       return 0;
+}
+
+static int soc_dai_link_init(struct snd_soc_card *card,
+                            struct snd_soc_codec *codec,
+                            int num)
+{
+       struct snd_soc_dai_link *dai_link =  &card->dai_link[num];
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       int ret;
+
+       rtd->card = card;
+
+       /* do machine specific initialization */
+       if (dai_link->init) {
+               ret = dai_link->init(rtd);
+               if (ret < 0)
+                       return ret;
+       }
+
+       rtd->codec = codec;
+
+       return 0;
+}
+
 static int soc_post_component_init(struct snd_soc_card *card,
                                   struct snd_soc_codec *codec,
                                   int num, int dailess)
@@ -1260,26 +1326,20 @@ static int soc_post_component_init(struct snd_soc_card *card,
                dai_link = &card->dai_link[num];
                rtd = &card->rtd[num];
                name = dai_link->name;
+               ret = soc_dai_link_init(card, codec, num);
        } else {
                aux_dev = &card->aux_dev[num];
                rtd = &card->rtd_aux[num];
                name = aux_dev->name;
+               ret = soc_aux_dev_init(card, codec, num);
        }
-       rtd->card = card;
 
-       /* do machine specific initialization */
-       if (!dailess && dai_link->init)
-               ret = dai_link->init(rtd);
-       else if (dailess && aux_dev->init)
-               ret = aux_dev->init(&codec->dapm);
        if (ret < 0) {
                dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);
                return ret;
        }
 
        /* register the rtd device */
-       rtd->codec = codec;
-
        rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
        if (!rtd->dev)
                return -ENOMEM;
@@ -1366,6 +1426,67 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
        return 0;
 }
 
+static int soc_probe_codec_dai(struct snd_soc_card *card,
+                              struct snd_soc_dai *codec_dai,
+                              int order)
+{
+       int ret;
+
+       if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
+               if (codec_dai->driver->probe) {
+                       ret = codec_dai->driver->probe(codec_dai);
+                       if (ret < 0) {
+                               dev_err(codec_dai->dev,
+                                       "ASoC: failed to probe CODEC DAI %s: %d\n",
+                                       codec_dai->name, ret);
+                               return ret;
+                       }
+               }
+
+               /* mark codec_dai as probed and add to card dai list */
+               codec_dai->probed = 1;
+               list_add(&codec_dai->card_list, &card->dai_dev_list);
+       }
+
+       return 0;
+}
+
+static int soc_link_dai_widgets(struct snd_soc_card *card,
+                               struct snd_soc_dai_link *dai_link,
+                               struct snd_soc_dai *cpu_dai,
+                               struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_dapm_widget *play_w, *capture_w;
+       int ret;
+
+       /* link the DAI widgets */
+       play_w = codec_dai->playback_widget;
+       capture_w = cpu_dai->capture_widget;
+       if (play_w && capture_w) {
+               ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+                                          capture_w, play_w);
+               if (ret != 0) {
+                       dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
+                               play_w->name, capture_w->name, ret);
+                       return ret;
+               }
+       }
+
+       play_w = cpu_dai->playback_widget;
+       capture_w = codec_dai->capture_widget;
+       if (play_w && capture_w) {
+               ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+                                          capture_w, play_w);
+               if (ret != 0) {
+                       dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
+                               play_w->name, capture_w->name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
@@ -1374,7 +1495,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dapm_widget *play_w, *capture_w;
        int ret;
 
        dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
@@ -1415,21 +1535,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
        }
 
        /* probe the CODEC DAI */
-       if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
-               if (codec_dai->driver->probe) {
-                       ret = codec_dai->driver->probe(codec_dai);
-                       if (ret < 0) {
-                               dev_err(codec_dai->dev,
-                                       "ASoC: failed to probe CODEC DAI %s: %d\n",
-                                       codec_dai->name, ret);
-                               return ret;
-                       }
-               }
-
-               /* mark codec_dai as probed and add to card dai list */
-               codec_dai->probed = 1;
-               list_add(&codec_dai->card_list, &card->dai_dev_list);
-       }
+       ret = soc_probe_codec_dai(card, codec_dai, order);
+       if (ret)
+               return ret;
 
        /* complete DAI probe during last probe */
        if (order != SND_SOC_COMP_ORDER_LAST)
@@ -1467,29 +1575,10 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                                                codec2codec_close_delayed_work);
 
                        /* link the DAI widgets */
-                       play_w = codec_dai->playback_widget;
-                       capture_w = cpu_dai->capture_widget;
-                       if (play_w && capture_w) {
-                               ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                                  capture_w, play_w);
-                               if (ret != 0) {
-                                       dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
-                                               play_w->name, capture_w->name, ret);
-                                       return ret;
-                               }
-                       }
-
-                       play_w = cpu_dai->playback_widget;
-                       capture_w = codec_dai->capture_widget;
-                       if (play_w && capture_w) {
-                               ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                                  capture_w, play_w);
-                               if (ret != 0) {
-                                       dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
-                                               play_w->name, capture_w->name, ret);
-                                       return ret;
-                               }
-                       }
+                       ret = soc_link_dai_widgets(card, dai_link,
+                                       cpu_dai, codec_dai);
+                       if (ret)
+                               return ret;
                }
        }
 
@@ -1501,14 +1590,15 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 }
 
 #ifdef CONFIG_SND_SOC_AC97_BUS
-static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+static int soc_register_ac97_codec(struct snd_soc_codec *codec,
+                                  struct snd_soc_dai *codec_dai)
 {
        int ret;
 
        /* Only instantiate AC97 if not already done by the adaptor
         * for the generic AC97 subsystem.
         */
-       if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
+       if (codec_dai->driver->ac97_control && !codec->ac97_registered) {
                /*
                 * It is possible that the AC97 device is already registered to
                 * the device subsystem. This happens when the device is created
@@ -1517,76 +1607,100 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
                 *
                 * In those cases we don't try to register the device again.
                 */
-               if (!rtd->codec->ac97_created)
+               if (!codec->ac97_created)
                        return 0;
 
-               ret = soc_ac97_dev_register(rtd->codec);
+               ret = soc_ac97_dev_register(codec);
                if (ret < 0) {
-                       dev_err(rtd->codec->dev,
+                       dev_err(codec->dev,
                                "ASoC: AC97 device register failed: %d\n", ret);
                        return ret;
                }
 
-               rtd->codec->ac97_registered = 1;
+               codec->ac97_registered = 1;
        }
        return 0;
 }
 
-static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+       return soc_register_ac97_codec(rtd->codec, rtd->codec_dai);
+}
+
+static void soc_unregister_ac97_codec(struct snd_soc_codec *codec)
 {
        if (codec->ac97_registered) {
                soc_ac97_dev_unregister(codec);
                codec->ac97_registered = 0;
        }
 }
+
+static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+       soc_unregister_ac97_codec(rtd->codec);
+}
 #endif
 
-static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+struct snd_soc_codec *soc_find_matching_codec(struct snd_soc_card *card, int num)
 {
        struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
        struct snd_soc_codec *codec;
 
-       /* find CODEC from registered CODECs*/
+       /* find CODEC from registered CODECs */
        list_for_each_entry(codec, &codec_list, list) {
-               if (!strcmp(codec->name, aux_dev->codec_name))
-                       return 0;
+               if (aux_dev->codec_of_node &&
+                  (codec->dev->of_node != aux_dev->codec_of_node))
+                       continue;
+               if (aux_dev->codec_name && strcmp(codec->name, aux_dev->codec_name))
+                       continue;
+               return codec;
        }
 
-       dev_err(card->dev, "ASoC: %s not registered\n", aux_dev->codec_name);
+       return NULL;
+}
 
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+       const char *codecname = aux_dev->codec_name;
+       struct snd_soc_codec *codec = soc_find_matching_codec(card, num);
+
+       if (codec)
+               return 0;
+       if (aux_dev->codec_of_node)
+               codecname = of_node_full_name(aux_dev->codec_of_node);
+
+       dev_err(card->dev, "ASoC: %s not registered\n", codecname);
        return -EPROBE_DEFER;
 }
 
 static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 {
        struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
-       struct snd_soc_codec *codec;
+       const char *codecname = aux_dev->codec_name;
        int ret = -ENODEV;
+       struct snd_soc_codec *codec = soc_find_matching_codec(card, num);
 
-       /* find CODEC from registered CODECs*/
-       list_for_each_entry(codec, &codec_list, list) {
-               if (!strcmp(codec->name, aux_dev->codec_name)) {
-                       if (codec->probed) {
-                               dev_err(codec->dev,
-                                       "ASoC: codec already probed");
-                               ret = -EBUSY;
-                               goto out;
-                       }
-                       goto found;
-               }
+       if (!codec) {
+               if (aux_dev->codec_of_node)
+                       codecname = of_node_full_name(aux_dev->codec_of_node);
+
+               /* codec not found */
+               dev_err(card->dev, "ASoC: codec %s not found", codecname);
+               return -EPROBE_DEFER;
+       }
+
+       if (codec->probed) {
+               dev_err(codec->dev, "ASoC: codec already probed");
+               return -EBUSY;
        }
-       /* codec not found */
-       dev_err(card->dev, "ASoC: codec %s not found", aux_dev->codec_name);
-       return -EPROBE_DEFER;
 
-found:
        ret = soc_probe_codec(card, codec);
        if (ret < 0)
                return ret;
 
        ret = soc_post_component_init(card, codec, num, 1);
 
-out:
        return ret;
 }
 
@@ -1837,7 +1951,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                        dev_err(card->dev,
                                "ASoC: failed to register AC97: %d\n", ret);
                        while (--i >= 0)
-                               soc_unregister_ac97_dai_link(card->rtd[i].codec);
+                               soc_unregister_ac97_dai_link(&card->rtd[i]);
                        goto probe_aux_dev_err;
                }
        }
@@ -1979,92 +2093,6 @@ static struct platform_driver soc_driver = {
        .remove         = soc_remove,
 };
 
-/**
- * snd_soc_codec_volatile_register: Report if a register is volatile.
- *
- * @codec: CODEC to query.
- * @reg: Register to query.
- *
- * Boolean function indiciating if a CODEC register is volatile.
- */
-int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       if (codec->volatile_register)
-               return codec->volatile_register(codec, reg);
-       else
-               return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
-
-/**
- * snd_soc_codec_readable_register: Report if a register is readable.
- *
- * @codec: CODEC to query.
- * @reg: Register to query.
- *
- * Boolean function indicating if a CODEC register is readable.
- */
-int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       if (codec->readable_register)
-               return codec->readable_register(codec, reg);
-       else
-               return 1;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
-
-/**
- * snd_soc_codec_writable_register: Report if a register is writable.
- *
- * @codec: CODEC to query.
- * @reg: Register to query.
- *
- * Boolean function indicating if a CODEC register is writable.
- */
-int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       if (codec->writable_register)
-               return codec->writable_register(codec, reg);
-       else
-               return 1;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
-
-int snd_soc_platform_read(struct snd_soc_platform *platform,
-                                       unsigned int reg)
-{
-       unsigned int ret;
-
-       if (!platform->driver->read) {
-               dev_err(platform->dev, "ASoC: platform has no read back\n");
-               return -1;
-       }
-
-       ret = platform->driver->read(platform, reg);
-       dev_dbg(platform->dev, "read %x => %x\n", reg, ret);
-       trace_snd_soc_preg_read(platform, reg, ret);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_platform_read);
-
-int snd_soc_platform_write(struct snd_soc_platform *platform,
-                                        unsigned int reg, unsigned int val)
-{
-       if (!platform->driver->write) {
-               dev_err(platform->dev, "ASoC: platform has no write back\n");
-               return -1;
-       }
-
-       dev_dbg(platform->dev, "write %x = %x\n", reg, val);
-       trace_snd_soc_preg_write(platform, reg, val);
-       return platform->driver->write(platform, reg, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_platform_write);
-
 /**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
@@ -2153,28 +2181,28 @@ static int snd_soc_ac97_parse_pinctl(struct device *dev,
        p = devm_pinctrl_get(dev);
        if (IS_ERR(p)) {
                dev_err(dev, "Failed to get pinctrl\n");
-               return PTR_RET(p);
+               return PTR_ERR(p);
        }
        cfg->pctl = p;
 
        state = pinctrl_lookup_state(p, "ac97-reset");
        if (IS_ERR(state)) {
                dev_err(dev, "Can't find pinctrl state ac97-reset\n");
-               return PTR_RET(state);
+               return PTR_ERR(state);
        }
        cfg->pstate_reset = state;
 
        state = pinctrl_lookup_state(p, "ac97-warm-reset");
        if (IS_ERR(state)) {
                dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
-               return PTR_RET(state);
+               return PTR_ERR(state);
        }
        cfg->pstate_warm_reset = state;
 
        state = pinctrl_lookup_state(p, "ac97-running");
        if (IS_ERR(state)) {
                dev_err(dev, "Can't find pinctrl state ac97-running\n");
-               return PTR_RET(state);
+               return PTR_ERR(state);
        }
        cfg->pstate_run = state;
 
@@ -2273,7 +2301,7 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 {
        mutex_lock(&codec->mutex);
 #ifdef CONFIG_SND_SOC_AC97_BUS
-       soc_unregister_ac97_dai_link(codec);
+       soc_unregister_ac97_codec(codec);
 #endif
        kfree(codec->ac97->bus);
        kfree(codec->ac97);
@@ -2283,118 +2311,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
 
-unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
-{
-       unsigned int ret;
-
-       ret = codec->read(codec, reg);
-       dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
-       trace_snd_soc_reg_read(codec, reg, ret);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_read);
-
-unsigned int snd_soc_write(struct snd_soc_codec *codec,
-                          unsigned int reg, unsigned int val)
-{
-       dev_dbg(codec->dev, "write %x = %x\n", reg, val);
-       trace_snd_soc_reg_write(codec, reg, val);
-       return codec->write(codec, reg, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_write);
-
-/**
- * snd_soc_update_bits - update codec register bits
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Writes new register value.
- *
- * Returns 1 for change, 0 for no change, or negative error code.
- */
-int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
-                               unsigned int mask, unsigned int value)
-{
-       bool change;
-       unsigned int old, new;
-       int ret;
-
-       if (codec->using_regmap) {
-               ret = regmap_update_bits_check(codec->control_data, reg,
-                                              mask, value, &change);
-       } else {
-               ret = snd_soc_read(codec, reg);
-               if (ret < 0)
-                       return ret;
-
-               old = ret;
-               new = (old & ~mask) | (value & mask);
-               change = old != new;
-               if (change)
-                       ret = snd_soc_write(codec, reg, new);
-       }
-
-       if (ret < 0)
-               return ret;
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_update_bits);
-
-/**
- * snd_soc_update_bits_locked - update codec register bits
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Writes new register value, and takes the codec mutex.
- *
- * Returns 1 for change else 0.
- */
-int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
-                              unsigned short reg, unsigned int mask,
-                              unsigned int value)
-{
-       int change;
-
-       mutex_lock(&codec->mutex);
-       change = snd_soc_update_bits(codec, reg, mask, value);
-       mutex_unlock(&codec->mutex);
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
-
-/**
- * snd_soc_test_bits - test register for change
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Tests a register with a new value and checks if the new value is
- * different from the old value.
- *
- * Returns 1 for change else 0.
- */
-int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
-                               unsigned int mask, unsigned int value)
-{
-       int change;
-       unsigned int old, new;
-
-       old = snd_soc_read(codec, reg);
-       new = (old & ~mask) | value;
-       change = old != new;
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_test_bits);
-
 /**
  * snd_soc_cnew - create new control
  * @_template: control template
@@ -2491,7 +2407,7 @@ int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
        struct snd_card *card = codec->card->snd_card;
 
        return snd_soc_add_controls(card, codec->dev, controls, num_controls,
-                       codec->name_prefix, codec);
+                       codec->name_prefix, &codec->component);
 }
 EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
 
@@ -2511,7 +2427,7 @@ int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
        struct snd_card *card = platform->card->snd_card;
 
        return snd_soc_add_controls(card, platform->dev, controls, num_controls,
-                       NULL, platform);
+                       NULL, &platform->component);
 }
 EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
 
@@ -2595,12 +2511,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
 int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, item;
        unsigned int reg_val;
+       int ret;
 
-       reg_val = snd_soc_read(codec, e->reg);
+       ret = snd_soc_component_read(component, e->reg, &reg_val);
+       if (ret)
+               return ret;
        val = (reg_val >> e->shift_l) & e->mask;
        item = snd_soc_enum_val_to_item(e, val);
        ucontrol->value.enumerated.item[0] = item;
@@ -2626,7 +2545,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
 int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int *item = ucontrol->value.enumerated.item;
        unsigned int val;
@@ -2643,38 +2562,48 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
                mask |= e->mask << e->shift_r;
        }
 
-       return snd_soc_update_bits_locked(codec, e->reg, mask, val);
+       return snd_soc_component_update_bits(component, e->reg, mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
 
 /**
  * snd_soc_read_signed - Read a codec register and interprete as signed value
- * @codec: codec
+ * @component: component
  * @reg: Register to read
  * @mask: Mask to use after shifting the register value
  * @shift: Right shift of register value
  * @sign_bit: Bit that describes if a number is negative or not.
+ * @signed_val: Pointer to where the read value should be stored
  *
  * This functions reads a codec register. The register value is shifted right
  * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
  * the given registervalue into a signed integer if sign_bit is non-zero.
  *
- * Returns the register value as signed int.
+ * Returns 0 on sucess, otherwise an error value
  */
-static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
-               unsigned int mask, unsigned int shift, unsigned int sign_bit)
+static int snd_soc_read_signed(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int shift,
+       unsigned int sign_bit, int *signed_val)
 {
        int ret;
        unsigned int val;
 
-       val = (snd_soc_read(codec, reg) >> shift) & mask;
+       ret = snd_soc_component_read(component, reg, &val);
+       if (ret < 0)
+               return ret;
 
-       if (!sign_bit)
-               return val;
+       val = (val >> shift) & mask;
+
+       if (!sign_bit) {
+               *signed_val = val;
+               return 0;
+       }
 
        /* non-negative number */
-       if (!(val & BIT(sign_bit)))
-               return val;
+       if (!(val & BIT(sign_bit))) {
+               *signed_val = val;
+               return 0;
+       }
 
        ret = val;
 
@@ -2686,7 +2615,9 @@ static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
         */
        ret |= ~((int)(BIT(sign_bit) - 1));
 
-       return ret;
+       *signed_val = ret;
+
+       return 0;
 }
 
 /**
@@ -2735,9 +2666,9 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -2747,25 +2678,32 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        int sign_bit = mc->sign_bit;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
+       int val;
+       int ret;
 
        if (sign_bit)
                mask = BIT(sign_bit + 1) - 1;
 
-       ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask,
-                       shift, sign_bit) - min;
+       ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val);
+       if (ret)
+               return ret;
+
+       ucontrol->value.integer.value[0] = val - min;
        if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
 
        if (snd_soc_volsw_is_stereo(mc)) {
                if (reg == reg2)
-                       ucontrol->value.integer.value[1] =
-                               snd_soc_read_signed(codec, reg, mask, rshift,
-                                               sign_bit) - min;
+                       ret = snd_soc_read_signed(component, reg, mask, rshift,
+                               sign_bit, &val);
                else
-                       ucontrol->value.integer.value[1] =
-                               snd_soc_read_signed(codec, reg2, mask, shift,
-                                               sign_bit) - min;
+                       ret = snd_soc_read_signed(component, reg2, mask, shift,
+                               sign_bit, &val);
+               if (ret)
+                       return ret;
+
+               ucontrol->value.integer.value[1] = val - min;
                if (invert)
                        ucontrol->value.integer.value[1] =
                                max - ucontrol->value.integer.value[1];
@@ -2788,9 +2726,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
 int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -2825,12 +2763,13 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
                        type_2r = true;
                }
        }
-       err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       err = snd_soc_component_update_bits(component, reg, val_mask, val);
        if (err < 0)
                return err;
 
        if (type_2r)
-               err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
+               err = snd_soc_component_update_bits(component, reg2, val_mask,
+                       val2);
 
        return err;
 }
@@ -2849,10 +2788,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
            (struct soc_mixer_control *)kcontrol->private_value;
-
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        unsigned int shift = mc->shift;
@@ -2860,13 +2798,23 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
        int max = mc->max;
        int min = mc->min;
        int mask = (1 << (fls(min + max) - 1)) - 1;
+       unsigned int val;
+       int ret;
 
-       ucontrol->value.integer.value[0] =
-           ((snd_soc_read(codec, reg) >> shift) - min) & mask;
+       ret = snd_soc_component_read(component, reg, &val);
+       if (ret < 0)
+               return ret;
 
-       if (snd_soc_volsw_is_stereo(mc))
-               ucontrol->value.integer.value[1] =
-                       ((snd_soc_read(codec, reg2) >> rshift) - min) & mask;
+       ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask;
+
+       if (snd_soc_volsw_is_stereo(mc)) {
+               ret = snd_soc_component_read(component, reg2, &val);
+               if (ret < 0)
+                       return ret;
+
+               val = ((val >> rshift) - min) & mask;
+               ucontrol->value.integer.value[1] = val;
+       }
 
        return 0;
 }
@@ -2884,7 +2832,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
 int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
            (struct soc_mixer_control *)kcontrol->private_value;
 
@@ -2896,13 +2844,13 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
        int min = mc->min;
        int mask = (1 << (fls(min + max) - 1)) - 1;
        int err = 0;
-       unsigned short val, val_mask, val2 = 0;
+       unsigned int val, val_mask, val2 = 0;
 
        val_mask = mask << shift;
        val = (ucontrol->value.integer.value[0] + min) & mask;
        val = val << shift;
 
-       err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       err = snd_soc_component_update_bits(component, reg, val_mask, val);
        if (err < 0)
                return err;
 
@@ -2911,10 +2859,10 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
                val2 = (ucontrol->value.integer.value[1] + min) & mask;
                val2 = val2 << rshift;
 
-               if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2))
-                       return err;
+               err = snd_soc_component_update_bits(component, reg2, val_mask,
+                       val2);
        }
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
 
@@ -2961,10 +2909,15 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
+       unsigned int val;
        int min = mc->min;
-       int val = snd_soc_read(codec, reg);
+       int ret;
+
+       ret = snd_soc_component_read(component, reg, &val);
+       if (ret)
+               return ret;
 
        ucontrol->value.integer.value[0] =
                ((signed char)(val & 0xff))-min;
@@ -2988,7 +2941,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        int min = mc->min;
        unsigned int val;
@@ -2996,7 +2949,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
        val = (ucontrol->value.integer.value[0]+min) & 0xff;
        val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
 
-       return snd_soc_update_bits_locked(codec, reg, 0xffff, val);
+       return snd_soc_component_update_bits(component, reg, 0xffff, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 
@@ -3045,7 +2998,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int rreg = mc->rreg;
        unsigned int shift = mc->shift;
@@ -3062,7 +3015,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        val_mask = mask << shift;
        val = val << shift;
 
-       ret = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       ret = snd_soc_component_update_bits(component, reg, val_mask, val);
        if (ret < 0)
                return ret;
 
@@ -3073,7 +3026,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                val_mask = mask << shift;
                val = val << shift;
 
-               ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val);
+               ret = snd_soc_component_update_bits(component, rreg, val_mask,
+                       val);
        }
 
        return ret;
@@ -3092,9 +3046,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
 int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int rreg = mc->rreg;
        unsigned int shift = mc->shift;
@@ -3102,9 +3056,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
+       unsigned int val;
+       int ret;
 
-       ucontrol->value.integer.value[0] =
-               (snd_soc_read(codec, reg) >> shift) & mask;
+       ret = snd_soc_component_read(component, reg, &val);
+       if (ret)
+               return ret;
+
+       ucontrol->value.integer.value[0] = (val >> shift) & mask;
        if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
@@ -3112,8 +3071,11 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
                ucontrol->value.integer.value[0] - min;
 
        if (snd_soc_volsw_is_stereo(mc)) {
-               ucontrol->value.integer.value[1] =
-                       (snd_soc_read(codec, rreg) >> shift) & mask;
+               ret = snd_soc_component_read(component, rreg, &val);
+               if (ret)
+                       return ret;
+
+               ucontrol->value.integer.value[1] = (val >> shift) & mask;
                if (invert)
                        ucontrol->value.integer.value[1] =
                                max - ucontrol->value.integer.value[1];
@@ -3167,11 +3129,11 @@ EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_info *uinfo)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_bytes *params = (void *)kcontrol->private_value;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-       uinfo->count = params->num_regs * codec->val_bytes;
+       uinfo->count = params->num_regs * component->val_bytes;
 
        return 0;
 }
@@ -3180,20 +3142,20 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_info);
 int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_bytes *params = (void *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        int ret;
 
-       if (codec->using_regmap)
-               ret = regmap_raw_read(codec->control_data, params->base,
+       if (component->regmap)
+               ret = regmap_raw_read(component->regmap, params->base,
                                      ucontrol->value.bytes.data,
-                                     params->num_regs * codec->val_bytes);
+                                     params->num_regs * component->val_bytes);
        else
                ret = -EINVAL;
 
        /* Hide any masked bytes to ensure consistent data reporting */
        if (ret == 0 && params->mask) {
-               switch (codec->val_bytes) {
+               switch (component->val_bytes) {
                case 1:
                        ucontrol->value.bytes.data[0] &= ~params->mask;
                        break;
@@ -3217,16 +3179,16 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
 int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_bytes *params = (void *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        int ret, len;
        unsigned int val, mask;
        void *data;
 
-       if (!codec->using_regmap)
+       if (!component->regmap)
                return -EINVAL;
 
-       len = params->num_regs * codec->val_bytes;
+       len = params->num_regs * component->val_bytes;
 
        data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
        if (!data)
@@ -3238,27 +3200,27 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
         * copy.
         */
        if (params->mask) {
-               ret = regmap_read(codec->control_data, params->base, &val);
+               ret = regmap_read(component->regmap, params->base, &val);
                if (ret != 0)
                        goto out;
 
                val &= params->mask;
 
-               switch (codec->val_bytes) {
+               switch (component->val_bytes) {
                case 1:
                        ((u8 *)data)[0] &= ~params->mask;
                        ((u8 *)data)[0] |= val;
                        break;
                case 2:
                        mask = ~params->mask;
-                       ret = regmap_parse_val(codec->control_data,
+                       ret = regmap_parse_val(component->regmap,
                                                        &mask, &mask);
                        if (ret != 0)
                                goto out;
 
                        ((u16 *)data)[0] &= mask;
 
-                       ret = regmap_parse_val(codec->control_data,
+                       ret = regmap_parse_val(component->regmap,
                                                        &val, &val);
                        if (ret != 0)
                                goto out;
@@ -3267,14 +3229,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                        break;
                case 4:
                        mask = ~params->mask;
-                       ret = regmap_parse_val(codec->control_data,
+                       ret = regmap_parse_val(component->regmap,
                                                        &mask, &mask);
                        if (ret != 0)
                                goto out;
 
                        ((u32 *)data)[0] &= mask;
 
-                       ret = regmap_parse_val(codec->control_data,
+                       ret = regmap_parse_val(component->regmap,
                                                        &val, &val);
                        if (ret != 0)
                                goto out;
@@ -3287,7 +3249,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                }
        }
 
-       ret = regmap_raw_write(codec->control_data, params->base,
+       ret = regmap_raw_write(component->regmap, params->base,
                               data, len);
 
 out:
@@ -3297,6 +3259,18 @@ out:
 }
 EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
 
+int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *ucontrol)
+{
+       struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+
+       ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       ucontrol->count = params->max;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext);
+
 /**
  * snd_soc_info_xr_sx - signed multi register info callback
  * @kcontrol: mreg control
@@ -3338,24 +3312,27 @@ EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
 int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mreg_control *mc =
                (struct soc_mreg_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int regbase = mc->regbase;
        unsigned int regcount = mc->regcount;
-       unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+       unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
        unsigned int regwmask = (1<<regwshift)-1;
        unsigned int invert = mc->invert;
        unsigned long mask = (1UL<<mc->nbits)-1;
        long min = mc->min;
        long max = mc->max;
        long val = 0;
-       unsigned long regval;
+       unsigned int regval;
        unsigned int i;
+       int ret;
 
        for (i = 0; i < regcount; i++) {
-               regval = snd_soc_read(codec, regbase+i) & regwmask;
-               val |= regval << (regwshift*(regcount-i-1));
+               ret = snd_soc_component_read(component, regbase+i, &regval);
+               if (ret)
+                       return ret;
+               val |= (regval & regwmask) << (regwshift*(regcount-i-1));
        }
        val &= mask;
        if (min < 0 && val > max)
@@ -3384,12 +3361,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
 int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mreg_control *mc =
                (struct soc_mreg_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int regbase = mc->regbase;
        unsigned int regcount = mc->regcount;
-       unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+       unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
        unsigned int regwmask = (1<<regwshift)-1;
        unsigned int invert = mc->invert;
        unsigned long mask = (1UL<<mc->nbits)-1;
@@ -3404,7 +3381,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        for (i = 0; i < regcount; i++) {
                regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
                regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
-               err = snd_soc_update_bits_locked(codec, regbase+i,
+               err = snd_soc_component_update_bits(component, regbase+i,
                                regmask, regval);
                if (err < 0)
                        return err;
@@ -3426,14 +3403,21 @@ EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
 int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int shift = mc->shift;
        unsigned int mask = 1 << shift;
        unsigned int invert = mc->invert != 0;
-       unsigned int val = snd_soc_read(codec, reg) & mask;
+       unsigned int val;
+       int ret;
+
+       ret = snd_soc_component_read(component, reg, &val);
+       if (ret)
+               return ret;
+
+       val &= mask;
 
        if (shift != 0 && val != 0)
                val = val >> shift;
@@ -3456,9 +3440,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
 int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
        unsigned int shift = mc->shift;
        unsigned int mask = 1 << shift;
@@ -3468,12 +3452,11 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
        unsigned int val2 = (strobe ^ invert) ? 0 : mask;
        int err;
 
-       err = snd_soc_update_bits_locked(codec, reg, mask, val1);
+       err = snd_soc_component_update_bits(component, reg, mask, val1);
        if (err < 0)
                return err;
 
-       err = snd_soc_update_bits_locked(codec, reg, mask, val2);
-       return err;
+       return snd_soc_component_update_bits(component, reg, mask, val2);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
 
@@ -4037,6 +4020,8 @@ __snd_soc_register_component(struct device *dev,
                return -ENOMEM;
        }
 
+       mutex_init(&cmpnt->io_mutex);
+
        cmpnt->name = fmt_single_name(dev, &cmpnt->id);
        if (!cmpnt->name) {
                dev_err(dev, "ASoC: Failed to simplifying name\n");
@@ -4084,12 +4069,25 @@ int snd_soc_register_component(struct device *dev,
        }
 
        cmpnt->ignore_pmdown_time = true;
+       cmpnt->registered_as_component = true;
 
        return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL,
                                            dai_drv, num_dai, true);
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_component);
 
+static void __snd_soc_unregister_component(struct snd_soc_component *cmpnt)
+{
+       snd_soc_unregister_dais(cmpnt);
+
+       mutex_lock(&client_mutex);
+       list_del(&cmpnt->list);
+       mutex_unlock(&client_mutex);
+
+       dev_dbg(cmpnt->dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
+       kfree(cmpnt->name);
+}
+
 /**
  * snd_soc_unregister_component - Unregister a component from the ASoC core
  *
@@ -4099,22 +4097,33 @@ void snd_soc_unregister_component(struct device *dev)
        struct snd_soc_component *cmpnt;
 
        list_for_each_entry(cmpnt, &component_list, list) {
-               if (dev == cmpnt->dev)
+               if (dev == cmpnt->dev && cmpnt->registered_as_component)
                        goto found;
        }
        return;
 
 found:
-       snd_soc_unregister_dais(cmpnt);
+       __snd_soc_unregister_component(cmpnt);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
 
-       mutex_lock(&client_mutex);
-       list_del(&cmpnt->list);
-       mutex_unlock(&client_mutex);
+static int snd_soc_platform_drv_write(struct snd_soc_component *component,
+       unsigned int reg, unsigned int val)
+{
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
 
-       dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
-       kfree(cmpnt->name);
+       return platform->driver->write(platform, reg, val);
+}
+
+static int snd_soc_platform_drv_read(struct snd_soc_component *component,
+       unsigned int reg, unsigned int *val)
+{
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
+
+       *val = platform->driver->read(platform, reg);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
 
 /**
  * snd_soc_add_platform - Add a platform to the ASoC core
@@ -4125,6 +4134,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
 int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
                const struct snd_soc_platform_driver *platform_drv)
 {
+       int ret;
+
        /* create platform component name */
        platform->name = fmt_single_name(dev, &platform->id);
        if (platform->name == NULL)
@@ -4134,8 +4145,22 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
        platform->driver = platform_drv;
        platform->dapm.dev = dev;
        platform->dapm.platform = platform;
+       platform->dapm.component = &platform->component;
        platform->dapm.stream_event = platform_drv->stream_event;
-       mutex_init(&platform->mutex);
+       if (platform_drv->write)
+               platform->component.write = snd_soc_platform_drv_write;
+       if (platform_drv->read)
+               platform->component.read = snd_soc_platform_drv_read;
+
+       /* register component */
+       ret = __snd_soc_register_component(dev, &platform->component,
+                                          &platform_drv->component_driver,
+                                          NULL, NULL, 0, false);
+       if (ret < 0) {
+               dev_err(platform->component.dev,
+                       "ASoC: Failed to register component: %d\n", ret);
+               return ret;
+       }
 
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
@@ -4178,6 +4203,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);
  */
 void snd_soc_remove_platform(struct snd_soc_platform *platform)
 {
+       __snd_soc_unregister_component(&platform->component);
+
        mutex_lock(&client_mutex);
        list_del(&platform->list);
        mutex_unlock(&client_mutex);
@@ -4252,6 +4279,24 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
                        stream->formats |= codec_format_map[i];
 }
 
+static int snd_soc_codec_drv_write(struct snd_soc_component *component,
+       unsigned int reg, unsigned int val)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+       return codec->driver->write(codec, reg, val);
+}
+
+static int snd_soc_codec_drv_read(struct snd_soc_component *component,
+       unsigned int reg, unsigned int *val)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+       *val = codec->driver->read(codec, reg);
+
+       return 0;
+}
+
 /**
  * snd_soc_register_codec - Register a codec with the ASoC core
  *
@@ -4263,6 +4308,7 @@ int snd_soc_register_codec(struct device *dev,
                           int num_dai)
 {
        struct snd_soc_codec *codec;
+       struct regmap *regmap;
        int ret, i;
 
        dev_dbg(dev, "codec register %s\n", dev_name(dev));
@@ -4278,22 +4324,41 @@ int snd_soc_register_codec(struct device *dev,
                goto fail_codec;
        }
 
-       codec->write = codec_drv->write;
-       codec->read = codec_drv->read;
-       codec->volatile_register = codec_drv->volatile_register;
-       codec->readable_register = codec_drv->readable_register;
-       codec->writable_register = codec_drv->writable_register;
+       if (codec_drv->write)
+               codec->component.write = snd_soc_codec_drv_write;
+       if (codec_drv->read)
+               codec->component.read = snd_soc_codec_drv_read;
        codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
+       codec->dapm.component = &codec->component;
        codec->dapm.seq_notifier = codec_drv->seq_notifier;
        codec->dapm.stream_event = codec_drv->stream_event;
        codec->dev = dev;
        codec->driver = codec_drv;
        codec->num_dai = num_dai;
+       codec->component.val_bytes = codec_drv->reg_word_size;
        mutex_init(&codec->mutex);
 
+       if (!codec->component.write) {
+               if (codec_drv->get_regmap)
+                       regmap = codec_drv->get_regmap(dev);
+               else
+                       regmap = dev_get_regmap(dev, NULL);
+
+               if (regmap) {
+                       ret = snd_soc_component_init_io(&codec->component,
+                               regmap);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                               "Failed to set cache I/O:%d\n",
+                                               ret);
+                               return ret;
+                       }
+               }
+       }
+
        for (i = 0; i < num_dai; i++) {
                fixup_codec_formats(&dai_drv[i].playback);
                fixup_codec_formats(&dai_drv[i].capture);
@@ -4343,7 +4408,7 @@ void snd_soc_unregister_codec(struct device *dev)
        return;
 
 found:
-       snd_soc_unregister_component(dev);
+       __snd_soc_unregister_component(&codec->component);
 
        mutex_lock(&client_mutex);
        list_del(&codec->list);
@@ -4554,7 +4619,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
 
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
-                                    const char *prefix)
+                                    const char *prefix,
+                                    struct device_node **bitclkmaster,
+                                    struct device_node **framemaster)
 {
        int ret, i;
        char prop[128];
@@ -4637,9 +4704,13 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
         */
        snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
        bit = !!of_get_property(np, prop, NULL);
+       if (bit && bitclkmaster)
+               *bitclkmaster = of_parse_phandle(np, prop, 0);
 
        snprintf(prop, sizeof(prop), "%sframe-master", prefix);
        frame = !!of_get_property(np, prop, NULL);
+       if (frame && framemaster)
+               *framemaster = of_parse_phandle(np, prop, 0);
 
        switch ((bit << 4) + frame) {
        case 0x11:
@@ -4698,7 +4769,7 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
 
                        if (id < 0 || id >= pos->num_dai) {
                                ret = -EINVAL;
-                               break;
+                               continue;
                        }
 
                        ret = 0;
index c8a780d0d057f43b08e74fc7c6d57f414e8aecde..1871dfcdbcb658f8ab145bda3656ba21dc4c8ea6 100644 (file)
@@ -254,7 +254,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
-       kfree(data->widget);
        kfree(data->wlist);
        kfree(data);
 }
@@ -379,86 +378,24 @@ static void dapm_reset(struct snd_soc_card *card)
 static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
        unsigned int *value)
 {
-       if (w->codec) {
-               *value = snd_soc_read(w->codec, reg);
-               return 0;
-       } else if (w->platform) {
-               *value = snd_soc_platform_read(w->platform, reg);
-               return 0;
-       }
-
-       dev_err(w->dapm->dev, "ASoC: no valid widget read method\n");
-       return -1;
-}
-
-static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
-       unsigned int val)
-{
-       if (w->codec)
-               return snd_soc_write(w->codec, reg, val);
-       else if (w->platform)
-               return snd_soc_platform_write(w->platform, reg, val);
-
-       dev_err(w->dapm->dev, "ASoC: no valid widget write method\n");
-       return -1;
-}
-
-static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
-{
-       if (w->codec && !w->codec->using_regmap)
-               mutex_lock(&w->codec->mutex);
-       else if (w->platform)
-               mutex_lock(&w->platform->mutex);
+       if (!w->dapm->component)
+               return -EIO;
+       return snd_soc_component_read(w->dapm->component, reg, value);
 }
 
-static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
+static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+       int reg, unsigned int mask, unsigned int value)
 {
-       if (w->codec && !w->codec->using_regmap)
-               mutex_unlock(&w->codec->mutex);
-       else if (w->platform)
-               mutex_unlock(&w->platform->mutex);
+       if (!w->dapm->component)
+               return -EIO;
+       return snd_soc_component_update_bits_async(w->dapm->component, reg,
+               mask, value);
 }
 
 static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
 {
-       if (dapm->codec && dapm->codec->using_regmap)
-               regmap_async_complete(dapm->codec->control_data);
-}
-
-static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
-       unsigned short reg, unsigned int mask, unsigned int value)
-{
-       bool change;
-       unsigned int old, new;
-       int ret;
-
-       if (w->codec && w->codec->using_regmap) {
-               ret = regmap_update_bits_check_async(w->codec->control_data,
-                                                    reg, mask, value,
-                                                    &change);
-               if (ret != 0)
-                       return ret;
-       } else {
-               soc_widget_lock(w);
-               ret = soc_widget_read(w, reg, &old);
-               if (ret < 0) {
-                       soc_widget_unlock(w);
-                       return ret;
-               }
-
-               new = (old & ~mask) | (value & mask);
-               change = old != new;
-               if (change) {
-                       ret = soc_widget_write(w, reg, new);
-                       if (ret < 0) {
-                               soc_widget_unlock(w);
-                               return ret;
-                       }
-               }
-               soc_widget_unlock(w);
-       }
-
-       return change;
+       if (dapm->component)
+               snd_soc_component_async_complete(dapm->component);
 }
 
 /**
@@ -1133,7 +1070,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
        else
                val = w->off_val;
 
-       soc_widget_update_bits_locked(w, -(w->reg + 1),
+       soc_widget_update_bits(w, -(w->reg + 1),
                            w->mask << w->shift, val << w->shift);
 
        return 0;
@@ -1429,7 +1366,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
                        "pop test : Applying 0x%x/0x%x to %x in %dms\n",
                        value, mask, reg, card->pop_time);
                pop_wait(card->pop_time);
-               soc_widget_update_bits_locked(w, reg, mask, value);
+               soc_widget_update_bits(w, reg, mask, value);
        }
 
        list_for_each_entry(w, pending, power_list) {
@@ -1575,8 +1512,7 @@ static void dapm_widget_update(struct snd_soc_card *card)
        if (!w)
                return;
 
-       ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
-                                 update->val);
+       ret = soc_widget_update_bits(w, update->reg, update->mask, update->val);
        if (ret < 0)
                dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
                        w->name, ret);
@@ -3510,32 +3446,25 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
        }
 }
 
-static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
        int event)
 {
+       struct snd_soc_dapm_widget *w;
 
-       struct snd_soc_dapm_widget *w_cpu, *w_codec;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               w_cpu = cpu_dai->playback_widget;
-               w_codec = codec_dai->playback_widget;
-       } else {
-               w_cpu = cpu_dai->capture_widget;
-               w_codec = codec_dai->capture_widget;
-       }
-
-       if (w_cpu) {
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               w = dai->playback_widget;
+       else
+               w = dai->capture_widget;
 
-               dapm_mark_dirty(w_cpu, "stream event");
+       if (w) {
+               dapm_mark_dirty(w, "stream event");
 
                switch (event) {
                case SND_SOC_DAPM_STREAM_START:
-                       w_cpu->active = 1;
+                       w->active = 1;
                        break;
                case SND_SOC_DAPM_STREAM_STOP:
-                       w_cpu->active = 0;
+                       w->active = 0;
                        break;
                case SND_SOC_DAPM_STREAM_SUSPEND:
                case SND_SOC_DAPM_STREAM_RESUME:
@@ -3544,25 +3473,13 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
                        break;
                }
        }
+}
 
-       if (w_codec) {
-
-               dapm_mark_dirty(w_codec, "stream event");
-
-               switch (event) {
-               case SND_SOC_DAPM_STREAM_START:
-                       w_codec->active = 1;
-                       break;
-               case SND_SOC_DAPM_STREAM_STOP:
-                       w_codec->active = 0;
-                       break;
-               case SND_SOC_DAPM_STREAM_SUSPEND:
-               case SND_SOC_DAPM_STREAM_RESUME:
-               case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
-               case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
-                       break;
-               }
-       }
+static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+       int event)
+{
+       soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
+       soc_dapm_dai_stream_event(rtd->codec_dai, stream, event);
 
        dapm_power_widgets(rtd->card, event);
 }
index 7ac745df1412689c6adf0bf246399870b79e44e7..057e5ef7dcce6730bdc99bc8e5719ebe458669d0 100644 (file)
@@ -52,6 +52,41 @@ int devm_snd_soc_register_component(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
 
+static void devm_platform_release(struct device *dev, void *res)
+{
+       snd_soc_unregister_platform(*(struct device **)res);
+}
+
+/**
+ * devm_snd_soc_register_platform - resource managed platform registration
+ * @dev: Device used to manage platform
+ * @platform: platform to register
+ *
+ * Register a platform driver with automatic unregistration when the device is
+ * unregistered.
+ */
+int devm_snd_soc_register_platform(struct device *dev,
+                       const struct snd_soc_platform_driver *platform_drv)
+{
+       struct device **ptr;
+       int ret;
+
+       ptr = devres_alloc(devm_platform_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       ret = snd_soc_register_platform(dev, platform_drv);
+       if (ret == 0) {
+               *ptr = dev;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_snd_soc_register_platform);
+
 static void devm_card_release(struct device *dev, void *res)
 {
        snd_soc_unregister_card(*(struct snd_soc_card **)res);
index 260efc8466fc352cf70d08663799c7fde0758a2e..7767fbd73eb7a464434c805a901fa94fe64a5e04 100644 (file)
 #include <linux/export.h>
 #include <sound/soc.h>
 
-#include <trace/events/asoc.h>
+/**
+ * snd_soc_component_read() - Read register value
+ * @component: Component to read from
+ * @reg: Register to read
+ * @val: Pointer to where the read value is stored
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int snd_soc_component_read(struct snd_soc_component *component,
+       unsigned int reg, unsigned int *val)
+{
+       int ret;
+
+       if (component->regmap)
+               ret = regmap_read(component->regmap, reg, val);
+       else if (component->read)
+               ret = component->read(component, reg, val);
+       else
+               ret = -EIO;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_read);
 
-#ifdef CONFIG_REGMAP
-static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
-                   unsigned int value)
+/**
+ * snd_soc_component_write() - Write register value
+ * @component: Component to write to
+ * @reg: Register to write
+ * @val: Value to write to the register
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int snd_soc_component_write(struct snd_soc_component *component,
+       unsigned int reg, unsigned int val)
 {
-       return regmap_write(codec->control_data, reg, value);
+       if (component->regmap)
+               return regmap_write(component->regmap, reg, val);
+       else if (component->write)
+               return component->write(component, reg, val);
+       else
+               return -EIO;
 }
+EXPORT_SYMBOL_GPL(snd_soc_component_write);
 
-static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
+static int snd_soc_component_update_bits_legacy(
+       struct snd_soc_component *component, unsigned int reg,
+       unsigned int mask, unsigned int val, bool *change)
 {
+       unsigned int old, new;
        int ret;
-       unsigned int val;
 
-       ret = regmap_read(codec->control_data, reg, &val);
-       if (ret == 0)
-               return val;
+       if (!component->read || !component->write)
+               return -EIO;
+
+       mutex_lock(&component->io_mutex);
+
+       ret = component->read(component, reg, &old);
+       if (ret < 0)
+               goto out_unlock;
+
+       new = (old & ~mask) | (val & mask);
+       *change = old != new;
+       if (*change)
+               ret = component->write(component, reg, new);
+out_unlock:
+       mutex_unlock(&component->io_mutex);
+
+       return ret;
+}
+
+/**
+ * snd_soc_component_update_bits() - Perform read/modify/write cycle
+ * @component: Component to update
+ * @reg: Register to update
+ * @mask: Mask that specifies which bits to update
+ * @val: New value for the bits specified by mask
+ *
+ * Return: 1 if the operation was successful and the value of the register
+ * changed, 0 if the operation was successful, but the value did not change.
+ * Returns a negative error code otherwise.
+ */
+int snd_soc_component_update_bits(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int val)
+{
+       bool change;
+       int ret;
+
+       if (component->regmap)
+               ret = regmap_update_bits_check(component->regmap, reg, mask,
+                       val, &change);
+       else
+               ret = snd_soc_component_update_bits_legacy(component, reg,
+                       mask, val, &change);
+
+       if (ret < 0)
+               return ret;
+       return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_update_bits);
+
+/**
+ * snd_soc_component_update_bits_async() - Perform asynchronous
+ *  read/modify/write cycle
+ * @component: Component to update
+ * @reg: Register to update
+ * @mask: Mask that specifies which bits to update
+ * @val: New value for the bits specified by mask
+ *
+ * This function is similar to snd_soc_component_update_bits(), but the update
+ * operation is scheduled asynchronously. This means it may not be completed
+ * when the function returns. To make sure that all scheduled updates have been
+ * completed snd_soc_component_async_complete() must be called.
+ *
+ * Return: 1 if the operation was successful and the value of the register
+ * changed, 0 if the operation was successful, but the value did not change.
+ * Returns a negative error code otherwise.
+ */
+int snd_soc_component_update_bits_async(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int val)
+{
+       bool change;
+       int ret;
+
+       if (component->regmap)
+               ret = regmap_update_bits_check_async(component->regmap, reg,
+                       mask, val, &change);
        else
+               ret = snd_soc_component_update_bits_legacy(component, reg,
+                       mask, val, &change);
+
+       if (ret < 0)
+               return ret;
+       return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
+
+/**
+ * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed
+ * @component: Component for which to wait
+ *
+ * This function blocks until all asynchronous I/O which has previously been
+ * scheduled using snd_soc_component_update_bits_async() has completed.
+ */
+void snd_soc_component_async_complete(struct snd_soc_component *component)
+{
+       if (component->regmap)
+               regmap_async_complete(component->regmap);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_async_complete);
+
+/**
+ * snd_soc_component_test_bits - Test register for change
+ * @component: component
+ * @reg: Register to test
+ * @mask: Mask that specifies which bits to test
+ * @value: Value to test against
+ *
+ * Tests a register with a new value and checks if the new value is
+ * different from the old value.
+ *
+ * Return: 1 for change, otherwise 0.
+ */
+int snd_soc_component_test_bits(struct snd_soc_component *component,
+       unsigned int reg, unsigned int mask, unsigned int value)
+{
+       unsigned int old, new;
+       int ret;
+
+       ret = snd_soc_component_read(component, reg, &old);
+       if (ret < 0)
+               return ret;
+       new = (old & ~mask) | value;
+       return old != new;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
+
+unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       unsigned int val;
+       int ret;
+
+       ret = snd_soc_component_read(&codec->component, reg, &val);
+       if (ret < 0)
                return -1;
+
+       return val;
 }
+EXPORT_SYMBOL_GPL(snd_soc_read);
+
+int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int val)
+{
+       return snd_soc_component_write(&codec->component, reg, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_write);
 
 /**
- * snd_soc_codec_set_cache_io: Set up standard I/O functions.
+ * snd_soc_update_bits - update codec register bits
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
  *
- * @codec: CODEC to configure.
- * @map: Register map to write to
+ * Writes new register value.
  *
- * Register formats are frequently shared between many I2C and SPI
- * devices.  In order to promote code reuse the ASoC core provides
- * some standard implementations of CODEC read and write operations
- * which can be set up using this function.
+ * Returns 1 for change, 0 for no change, or negative error code.
+ */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
+                               unsigned int mask, unsigned int value)
+{
+       return snd_soc_component_update_bits(&codec->component, reg, mask,
+               value);
+}
+EXPORT_SYMBOL_GPL(snd_soc_update_bits);
+
+/**
+ * snd_soc_test_bits - test register for change
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
  *
- * The caller is responsible for allocating and initialising the
- * actual cache.
+ * Tests a register with a new value and checks if the new value is
+ * different from the old value.
  *
- * Note that at present this code cannot be used by CODECs with
- * volatile registers.
+ * Returns 1 for change else 0.
  */
-int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              struct regmap *regmap)
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
+                               unsigned int mask, unsigned int value)
+{
+       return snd_soc_component_test_bits(&codec->component, reg, mask, value);
+}
+EXPORT_SYMBOL_GPL(snd_soc_test_bits);
+
+int snd_soc_platform_read(struct snd_soc_platform *platform,
+                                       unsigned int reg)
 {
+       unsigned int val;
        int ret;
 
-       /* Device has made its own regmap arrangements */
-       if (!regmap)
-               codec->control_data = dev_get_regmap(codec->dev, NULL);
-       else
-               codec->control_data = regmap;
+       ret = snd_soc_component_read(&platform->component, reg, &val);
+       if (ret < 0)
+               return -1;
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_read);
+
+int snd_soc_platform_write(struct snd_soc_platform *platform,
+                                        unsigned int reg, unsigned int val)
+{
+       return snd_soc_component_write(&platform->component, reg, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_write);
 
-       if (IS_ERR(codec->control_data))
-               return PTR_ERR(codec->control_data);
+/**
+ * snd_soc_component_init_io() - Initialize regmap IO
+ *
+ * @component: component to initialize
+ * @regmap: regmap instance to use for IO operations
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int snd_soc_component_init_io(struct snd_soc_component *component,
+       struct regmap *regmap)
+{
+       int ret;
 
-       codec->write = hw_write;
-       codec->read = hw_read;
+       if (!regmap)
+               return -EINVAL;
 
-       ret = regmap_get_val_bytes(codec->control_data);
+       ret = regmap_get_val_bytes(regmap);
        /* Errors are legitimate for non-integer byte
         * multiples */
        if (ret > 0)
-               codec->val_bytes = ret;
+               component->val_bytes = ret;
 
-       codec->using_regmap = true;
+       component->regmap = regmap;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
-#else
-int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              struct regmap *regmap)
-{
-       return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
-#endif
+EXPORT_SYMBOL_GPL(snd_soc_component_init_io);
index 2cedf09f6d9613c7b34bb22888806fde598052c6..88230ea330d8a4117b2bc9afe275972363711eb6 100644 (file)
@@ -1012,21 +1012,12 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
 }
 
 static inline struct snd_soc_dapm_widget *
-       rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+       dai_get_widget(struct snd_soc_dai *dai, int stream)
 {
        if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return rtd->cpu_dai->playback_widget;
+               return dai->playback_widget;
        else
-               return rtd->cpu_dai->capture_widget;
-}
-
-static inline struct snd_soc_dapm_widget *
-       rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
-{
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return rtd->codec_dai->playback_widget;
-       else
-               return rtd->codec_dai->capture_widget;
+               return dai->capture_widget;
 }
 
 static int widget_in_list(struct snd_soc_dapm_widget_list *list,
@@ -1076,14 +1067,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
        list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
 
                /* is there a valid CPU DAI widget for this BE */
-               widget = rtd_get_cpu_widget(dpcm->be, stream);
+               widget = dai_get_widget(dpcm->be->cpu_dai, stream);
 
                /* prune the BE if it's no longer in our active list */
                if (widget && widget_in_list(list, widget))
                        continue;
 
                /* is there a valid CODEC DAI widget for this BE */
-               widget = rtd_get_codec_widget(dpcm->be, stream);
+               widget = dai_get_widget(dpcm->be->codec_dai, stream);
 
                /* prune the BE if it's no longer in our active list */
                if (widget && widget_in_list(list, widget))
index e05a86b7c0da236e5efddc4c762aecca443283fd..d393153c474f2d763be5cdad6e39f4a1798d2463 100644 (file)
@@ -147,5 +147,18 @@ config SND_USB_HIFACE
          To compile this driver as a module, choose M here: the module
          will be called snd-usb-hiface.
 
+config SND_BCD2000
+       tristate "Behringer BCD2000 MIDI driver"
+       select SND_RAWMIDI
+       help
+         Say Y here to include MIDI support for the Behringer BCD2000 DJ
+         controller.
+
+         Audio support is still work-in-progress at
+         https://github.com/anyc/snd-usb-bcd2000
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-bcd2000.
+
 endif  # SND_USB
 
index abe668f660d16eb997950a692512f48638d152fb..2b92f0dcbc4cca532cc3b722a6ab77fbe155d23b 100644 (file)
@@ -23,4 +23,4 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
 
-obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/
+obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
diff --git a/sound/usb/bcd2000/Makefile b/sound/usb/bcd2000/Makefile
new file mode 100644 (file)
index 0000000..f09ccc0
--- /dev/null
@@ -0,0 +1,3 @@
+snd-bcd2000-y := bcd2000.o
+
+obj-$(CONFIG_SND_BCD2000) += snd-bcd2000.o
\ No newline at end of file
diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c
new file mode 100644 (file)
index 0000000..820d6ca
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Behringer BCD2000 driver
+ *
+ *   Copyright (C) 2014 Mario Kicherer (dev@kicherer.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/usb/audio.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+
+#define PREFIX "snd-bcd2000: "
+#define BUFSIZE 64
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x1397, 0x00bd) },
+       { },
+};
+
+static unsigned char device_cmd_prefix[] = {0x03, 0x00};
+
+static unsigned char bcd2000_init_sequence[] = {
+       0x07, 0x00, 0x00, 0x00, 0x78, 0x48, 0x1c, 0x81,
+       0xc4, 0x00, 0x00, 0x00, 0x5e, 0x53, 0x4a, 0xf7,
+       0x18, 0xfa, 0x11, 0xff, 0x6c, 0xf3, 0x90, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+       0x18, 0xfa, 0x11, 0xff, 0x14, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xf2, 0x34, 0x4a, 0xf7,
+       0x18, 0xfa, 0x11, 0xff
+};
+
+struct bcd2000 {
+       struct usb_device *dev;
+       struct snd_card *card;
+       struct usb_interface *intf;
+       int card_index;
+
+       int midi_out_active;
+       struct snd_rawmidi *rmidi;
+       struct snd_rawmidi_substream *midi_receive_substream;
+       struct snd_rawmidi_substream *midi_out_substream;
+
+       unsigned char midi_in_buf[BUFSIZE];
+       unsigned char midi_out_buf[BUFSIZE];
+
+       struct urb *midi_out_urb;
+       struct urb *midi_in_urb;
+
+       struct usb_anchor anchor;
+};
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+
+static DEFINE_MUTEX(devices_mutex);
+DECLARE_BITMAP(devices_used, SNDRV_CARDS);
+static struct usb_driver bcd2000_driver;
+
+#ifdef CONFIG_SND_DEBUG
+static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len)
+{
+       print_hex_dump(KERN_DEBUG, prefix,
+                       DUMP_PREFIX_NONE, 16, 1,
+                       buf, len, false);
+}
+#else
+static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len) {}
+#endif
+
+static int bcd2000_midi_input_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int bcd2000_midi_input_close(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+/* (de)register midi substream from client */
+static void bcd2000_midi_input_trigger(struct snd_rawmidi_substream *substream,
+                                               int up)
+{
+       struct bcd2000 *bcd2k = substream->rmidi->private_data;
+       bcd2k->midi_receive_substream = up ? substream : NULL;
+}
+
+static void bcd2000_midi_handle_input(struct bcd2000 *bcd2k,
+                               const unsigned char *buf, unsigned int buf_len)
+{
+       unsigned int payload_length, tocopy;
+       struct snd_rawmidi_substream *midi_receive_substream;
+
+       midi_receive_substream = ACCESS_ONCE(bcd2k->midi_receive_substream);
+       if (!midi_receive_substream)
+               return;
+
+       bcd2000_dump_buffer(PREFIX "received from device: ", buf, buf_len);
+
+       if (buf_len < 2)
+               return;
+
+       payload_length = buf[0];
+
+       /* ignore packets without payload */
+       if (payload_length == 0)
+               return;
+
+       tocopy = min(payload_length, buf_len-1);
+
+       bcd2000_dump_buffer(PREFIX "sending to userspace: ",
+                                       &buf[1], tocopy);
+
+       snd_rawmidi_receive(midi_receive_substream,
+                                       &buf[1], tocopy);
+}
+
+static void bcd2000_midi_send(struct bcd2000 *bcd2k)
+{
+       int len, ret;
+       struct snd_rawmidi_substream *midi_out_substream;
+
+       BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE);
+
+       midi_out_substream = ACCESS_ONCE(bcd2k->midi_out_substream);
+       if (!midi_out_substream)
+               return;
+
+       /* copy command prefix bytes */
+       memcpy(bcd2k->midi_out_buf, device_cmd_prefix,
+               sizeof(device_cmd_prefix));
+
+       /*
+        * get MIDI packet and leave space for command prefix
+        * and payload length
+        */
+       len = snd_rawmidi_transmit(midi_out_substream,
+                               bcd2k->midi_out_buf + 3, BUFSIZE - 3);
+
+       if (len < 0)
+               dev_err(&bcd2k->dev->dev, "%s: snd_rawmidi_transmit error %d\n",
+                               __func__, len);
+
+       if (len <= 0)
+               return;
+
+       /* set payload length */
+       bcd2k->midi_out_buf[2] = len;
+       bcd2k->midi_out_urb->transfer_buffer_length = BUFSIZE;
+
+       bcd2000_dump_buffer(PREFIX "sending to device: ",
+                       bcd2k->midi_out_buf, len+3);
+
+       /* send packet to the BCD2000 */
+       ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_ATOMIC);
+       if (ret < 0)
+               dev_err(&bcd2k->dev->dev, PREFIX
+                       "%s (%p): usb_submit_urb() failed, ret=%d, len=%d\n",
+                       __func__, midi_out_substream, ret, len);
+       else
+               bcd2k->midi_out_active = 1;
+}
+
+static int bcd2000_midi_output_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int bcd2000_midi_output_close(struct snd_rawmidi_substream *substream)
+{
+       struct bcd2000 *bcd2k = substream->rmidi->private_data;
+
+       if (bcd2k->midi_out_active) {
+               usb_kill_urb(bcd2k->midi_out_urb);
+               bcd2k->midi_out_active = 0;
+       }
+
+       return 0;
+}
+
+/* (de)register midi substream from client */
+static void bcd2000_midi_output_trigger(struct snd_rawmidi_substream *substream,
+                                               int up)
+{
+       struct bcd2000 *bcd2k = substream->rmidi->private_data;
+
+       if (up) {
+               bcd2k->midi_out_substream = substream;
+               /* check if there is data userspace wants to send */
+               if (!bcd2k->midi_out_active)
+                       bcd2000_midi_send(bcd2k);
+       } else {
+               bcd2k->midi_out_substream = NULL;
+       }
+}
+
+static void bcd2000_output_complete(struct urb *urb)
+{
+       struct bcd2000 *bcd2k = urb->context;
+
+       bcd2k->midi_out_active = 0;
+
+       if (urb->status)
+               dev_warn(&urb->dev->dev,
+                       PREFIX "output urb->status: %d\n", urb->status);
+
+       if (urb->status == -ESHUTDOWN)
+               return;
+
+       /* check if there is more data userspace wants to send */
+       bcd2000_midi_send(bcd2k);
+}
+
+static void bcd2000_input_complete(struct urb *urb)
+{
+       int ret;
+       struct bcd2000 *bcd2k = urb->context;
+
+       if (urb->status)
+               dev_warn(&urb->dev->dev,
+                       PREFIX "input urb->status: %i\n", urb->status);
+
+       if (!bcd2k || urb->status == -ESHUTDOWN)
+               return;
+
+       if (urb->actual_length > 0)
+               bcd2000_midi_handle_input(bcd2k, urb->transfer_buffer,
+                                       urb->actual_length);
+
+       /* return URB to device */
+       ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_ATOMIC);
+       if (ret < 0)
+               dev_err(&bcd2k->dev->dev, PREFIX
+                       "%s: usb_submit_urb() failed, ret=%d\n",
+                       __func__, ret);
+}
+
+static struct snd_rawmidi_ops bcd2000_midi_output = {
+       .open =    bcd2000_midi_output_open,
+       .close =   bcd2000_midi_output_close,
+       .trigger = bcd2000_midi_output_trigger,
+};
+
+static struct snd_rawmidi_ops bcd2000_midi_input = {
+       .open =    bcd2000_midi_input_open,
+       .close =   bcd2000_midi_input_close,
+       .trigger = bcd2000_midi_input_trigger,
+};
+
+static void bcd2000_init_device(struct bcd2000 *bcd2k)
+{
+       int ret;
+
+       init_usb_anchor(&bcd2k->anchor);
+       usb_anchor_urb(bcd2k->midi_out_urb, &bcd2k->anchor);
+       usb_anchor_urb(bcd2k->midi_in_urb, &bcd2k->anchor);
+
+       /* copy init sequence into buffer */
+       memcpy(bcd2k->midi_out_buf, bcd2000_init_sequence, 52);
+       bcd2k->midi_out_urb->transfer_buffer_length = 52;
+
+       /* submit sequence */
+       ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_KERNEL);
+       if (ret < 0)
+               dev_err(&bcd2k->dev->dev, PREFIX
+                       "%s: usb_submit_urb() out failed, ret=%d: ",
+                       __func__, ret);
+       else
+               bcd2k->midi_out_active = 1;
+
+       /* pass URB to device to enable button and controller events */
+       ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_KERNEL);
+       if (ret < 0)
+               dev_err(&bcd2k->dev->dev, PREFIX
+                       "%s: usb_submit_urb() in failed, ret=%d: ",
+                       __func__, ret);
+
+       /* ensure initialization is finished */
+       usb_wait_anchor_empty_timeout(&bcd2k->anchor, 1000);
+}
+
+static int bcd2000_init_midi(struct bcd2000 *bcd2k)
+{
+       int ret;
+       struct snd_rawmidi *rmidi;
+
+       ret = snd_rawmidi_new(bcd2k->card, bcd2k->card->shortname, 0,
+                                       1, /* output */
+                                       1, /* input */
+                                       &rmidi);
+
+       if (ret < 0)
+               return ret;
+
+       strlcpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
+
+       rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
+       rmidi->private_data = bcd2k;
+
+       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                                       &bcd2000_midi_output);
+
+       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                                       &bcd2000_midi_input);
+
+       bcd2k->rmidi = rmidi;
+
+       bcd2k->midi_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+       bcd2k->midi_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+       if (!bcd2k->midi_in_urb || !bcd2k->midi_out_urb) {
+               dev_err(&bcd2k->dev->dev, PREFIX "usb_alloc_urb failed\n");
+               return -ENOMEM;
+       }
+
+       usb_fill_int_urb(bcd2k->midi_in_urb, bcd2k->dev,
+                               usb_rcvintpipe(bcd2k->dev, 0x81),
+                               bcd2k->midi_in_buf, BUFSIZE,
+                               bcd2000_input_complete, bcd2k, 1);
+
+       usb_fill_int_urb(bcd2k->midi_out_urb, bcd2k->dev,
+                               usb_sndintpipe(bcd2k->dev, 0x1),
+                               bcd2k->midi_out_buf, BUFSIZE,
+                               bcd2000_output_complete, bcd2k, 1);
+
+       bcd2000_init_device(bcd2k);
+
+       return 0;
+}
+
+static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k,
+                                               struct usb_interface *interface)
+{
+       /* usb_kill_urb not necessary, urb is aborted automatically */
+
+       usb_free_urb(bcd2k->midi_out_urb);
+       usb_free_urb(bcd2k->midi_in_urb);
+
+       if (bcd2k->intf) {
+               usb_set_intfdata(bcd2k->intf, NULL);
+               bcd2k->intf = NULL;
+       }
+}
+
+static int bcd2000_probe(struct usb_interface *interface,
+                               const struct usb_device_id *usb_id)
+{
+       struct snd_card *card;
+       struct bcd2000 *bcd2k;
+       unsigned int card_index;
+       char usb_path[32];
+       int err;
+
+       mutex_lock(&devices_mutex);
+
+       for (card_index = 0; card_index < SNDRV_CARDS; ++card_index)
+               if (!test_bit(card_index, devices_used))
+                       break;
+
+       if (card_index >= SNDRV_CARDS) {
+               mutex_unlock(&devices_mutex);
+               return -ENOENT;
+       }
+
+       err = snd_card_new(&interface->dev, index[card_index], id[card_index],
+                       THIS_MODULE, sizeof(*bcd2k), &card);
+       if (err < 0) {
+               mutex_unlock(&devices_mutex);
+               return err;
+       }
+
+       bcd2k = card->private_data;
+       bcd2k->dev = interface_to_usbdev(interface);
+       bcd2k->card = card;
+       bcd2k->card_index = card_index;
+       bcd2k->intf = interface;
+
+       snd_card_set_dev(card, &interface->dev);
+
+       strncpy(card->driver, "snd-bcd2000", sizeof(card->driver));
+       strncpy(card->shortname, "BCD2000", sizeof(card->shortname));
+       usb_make_path(bcd2k->dev, usb_path, sizeof(usb_path));
+       snprintf(bcd2k->card->longname, sizeof(bcd2k->card->longname),
+                   "Behringer BCD2000 at %s",
+                       usb_path);
+
+       err = bcd2000_init_midi(bcd2k);
+       if (err < 0)
+               goto probe_error;
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto probe_error;
+
+       usb_set_intfdata(interface, bcd2k);
+       set_bit(card_index, devices_used);
+
+       mutex_unlock(&devices_mutex);
+       return 0;
+
+probe_error:
+       dev_info(&bcd2k->dev->dev, PREFIX "error during probing");
+       bcd2000_free_usb_related_resources(bcd2k, interface);
+       snd_card_free(card);
+       mutex_unlock(&devices_mutex);
+       return err;
+}
+
+static void bcd2000_disconnect(struct usb_interface *interface)
+{
+       struct bcd2000 *bcd2k = usb_get_intfdata(interface);
+
+       if (!bcd2k)
+               return;
+
+       mutex_lock(&devices_mutex);
+
+       /* make sure that userspace cannot create new requests */
+       snd_card_disconnect(bcd2k->card);
+
+       bcd2000_free_usb_related_resources(bcd2k, interface);
+
+       clear_bit(bcd2k->card_index, devices_used);
+
+       snd_card_free_when_closed(bcd2k->card);
+
+       mutex_unlock(&devices_mutex);
+}
+
+static struct usb_driver bcd2000_driver = {
+       .name =         "snd-bcd2000",
+       .probe =        bcd2000_probe,
+       .disconnect =   bcd2000_disconnect,
+       .id_table =     id_table,
+};
+
+module_usb_driver(bcd2000_driver);
+
+MODULE_DEVICE_TABLE(usb, id_table);
+MODULE_AUTHOR("Mario Kicherer, dev@kicherer.org");
+MODULE_DESCRIPTION("Behringer BCD2000 driver");
+MODULE_LICENSE("GPL");
index 893d5a1afc3ce6bf854a61ef0c3f4f54cc552d0d..c3b5b7dca1c3a8fd4b771512c841bb32e27b5554 100644 (file)
@@ -651,7 +651,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
        int err = -ENODEV;
 
        down_read(&chip->shutdown_rwsem);
-       if (chip->probing)
+       if (chip->probing && chip->in_pm)
                err = 0;
        else if (!chip->shutdown)
                err = usb_autopm_get_interface(chip->pm_intf);
@@ -663,7 +663,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
 void snd_usb_autosuspend(struct snd_usb_audio *chip)
 {
        down_read(&chip->shutdown_rwsem);
-       if (!chip->shutdown && !chip->probing)
+       if (!chip->shutdown && !chip->probing && !chip->in_pm)
                usb_autopm_put_interface(chip->pm_intf);
        up_read(&chip->shutdown_rwsem);
 }
@@ -695,8 +695,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
                        chip->autosuspended = 1;
        }
 
-       list_for_each_entry(mixer, &chip->mixer_list, list)
-               snd_usb_mixer_suspend(mixer);
+       if (chip->num_suspended_intf == 1)
+               list_for_each_entry(mixer, &chip->mixer_list, list)
+                       snd_usb_mixer_suspend(mixer);
 
        return 0;
 }
@@ -711,6 +712,8 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
                return 0;
        if (--chip->num_suspended_intf)
                return 0;
+
+       chip->in_pm = 1;
        /*
         * ALSA leaves material resumption to user space
         * we just notify and restart the mixers
@@ -726,6 +729,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
        chip->autosuspended = 0;
 
 err_out:
+       chip->in_pm = 0;
        return err;
 }
 
index 9867ab866857260df9432b4378d5ba87c1d90834..97acb906acc27041cebb340abaa9d69c36c34634 100644 (file)
@@ -92,6 +92,7 @@ struct snd_usb_endpoint {
        unsigned int curframesize;      /* current packet size in frames (for capture) */
        unsigned int syncmaxsize;       /* sync endpoint packet size */
        unsigned int fill_max:1;        /* fill max packet size always */
+       unsigned int udh01_fb_quirk:1;  /* corrupted feedback data */
        unsigned int datainterval;      /* log_2 of data packet interval */
        unsigned int syncinterval;      /* P for adaptive mode, 0 otherwise */
        unsigned char silence_value;
index e70a87e0d9fe6402765afa0741b9f974b1259bec..289f582c91303cd6bd26d194124b36702f8e4915 100644 (file)
@@ -471,6 +471,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
                        ep->syncinterval = 3;
 
                ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+
+               if (chip->usb_id == USB_ID(0x0644, 0x8038) /* TEAC UD-H01 */ &&
+                   ep->syncmaxsize == 4)
+                       ep->udh01_fb_quirk = 1;
        }
 
        list_add_tail(&ep->list, &chip->ep_list);
@@ -1105,7 +1109,16 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
        if (f == 0)
                return;
 
-       if (unlikely(ep->freqshift == INT_MIN)) {
+       if (unlikely(sender->udh01_fb_quirk)) {
+               /*
+                * The TEAC UD-H01 firmware sometimes changes the feedback value
+                * by +/- 0x1.0000.
+                */
+               if (f < ep->freqn - 0x8000)
+                       f += 0x10000;
+               else if (f > ep->freqn + 0x8000)
+                       f -= 0x10000;
+       } else if (unlikely(ep->freqshift == INT_MIN)) {
                /*
                 * The first time we see a feedback value, determine its format
                 * by shifting it left or right until it matches the nominal
index d40a2850e2709f3a60100f707eb650a398fb73f3..6fe83e4af8806cc7c94c00e3e9c9da4c88cd0387 100644 (file)
@@ -1986,7 +1986,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
                if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0)
                        len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);
                if (! len)
-                       sprintf(namelist[i], "Input %d", i);
+                       sprintf(namelist[i], "Input %u", i);
        }
 
        kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
index 131336d40492786b2283df01577a1957b0556a66..c62a1659106d2c3da63152d59e1302e2eee47d6d 100644 (file)
@@ -1501,9 +1501,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
         * The error should be lower than 2ms since the estimate relies
         * on two reads of a counter updated every ms.
         */
-       if (printk_ratelimit() &&
-           abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
-               dev_dbg(&subs->dev->dev,
+       if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
+               dev_dbg_ratelimited(&subs->dev->dev,
                        "delay: estimated %d, actual %d\n",
                        est_delay, subs->last_delay);
 
index 25c4c7e217de603c1f02c5c714833e6f29d92c3b..91d0380431b4f79f1e209cd973b7f44152caa494 100644 (file)
@@ -40,6 +40,7 @@ struct snd_usb_audio {
        struct rw_semaphore shutdown_rwsem;
        unsigned int shutdown:1;
        unsigned int probing:1;
+       unsigned int in_pm:1;
        unsigned int autosuspended:1;   
        unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
        
index 7c43479623537af4f0d4179f4cce195cbea3e9b1..a74fba6d774353d33fac7f04b71abdd241e0218e 100644 (file)
@@ -12,8 +12,8 @@
 char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
 
 static const char * const debugfs_known_mountpoints[] = {
-       "/sys/kernel/debug/",
-       "/debug/",
+       "/sys/kernel/debug",
+       "/debug",
        0,
 };
 
index baec7d887da4fafeeacbda82697ecff6200c95da..b83184f2d484f59f3a888648fd3f548c0dc37d12 100644 (file)
@@ -4344,6 +4344,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
                                              format, len_arg, arg);
                                trace_seq_terminate(&p);
                                trace_seq_puts(s, p.buffer);
+                               trace_seq_destroy(&p);
                                arg = arg->next;
                                break;
                        default:
index 791c539374c726b7e4d3ad8f6f75aad575692787..feab942816343aba5023d1b6ab588322e7d45506 100644 (file)
@@ -876,8 +876,8 @@ struct event_filter {
 struct event_filter *pevent_filter_alloc(struct pevent *pevent);
 
 /* for backward compatibility */
-#define FILTER_NONE            PEVENT_ERRNO__FILTER_NOT_FOUND
-#define FILTER_NOEXIST         PEVENT_ERRNO__NO_FILTER
+#define FILTER_NONE            PEVENT_ERRNO__NO_FILTER
+#define FILTER_NOEXIST         PEVENT_ERRNO__FILTER_NOT_FOUND
 #define FILTER_MISS            PEVENT_ERRNO__FILTER_MISS
 #define FILTER_MATCH           PEVENT_ERRNO__FILTER_MATCH
 
index bb31813e43ddca8bd2bad4544e593d8c6df418f2..9a287bec695a3630bc43f19e3376d8cff36d2856 100644 (file)
@@ -820,7 +820,7 @@ do_div:
                r->A &= r->X;
                break;
        case BPF_ALU_AND | BPF_K:
-               r->A &= r->X;
+               r->A &= K;
                break;
        case BPF_ALU_OR | BPF_X:
                r->A |= r->X;
index bf7be77ddd621238aa2a26ca2103b309bdcd089f..833a96611da6d042e089294990801817d0f1ade9 100644 (file)
@@ -92,6 +92,7 @@ extern void yyerror(const char *str);
 "#"?("cpu")    { return K_CPU; }
 "#"?("vlan_tci") { return K_VLANT; }
 "#"?("vlan_pr")        { return K_VLANP; }
+"#"?("rand")   { return K_RAND; }
 
 ":"            { return ':'; }
 ","            { return ','; }
index d15efc989ef500ac3f9998cf660d8e2bd22627e7..e6306c51c26f9e7cb53342ad088a9db1e4e32423 100644 (file)
@@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
 %token OP_LDXI
 
 %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
-%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF
+%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND
 
 %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
 
@@ -164,6 +164,9 @@ ldb
        | OP_LDB K_POFF {
                bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
                                   SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
+       | OP_LDB K_RAND {
+               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
+                                  SKF_AD_OFF + SKF_AD_RANDOM); }
        ;
 
 ldh
@@ -212,6 +215,9 @@ ldh
        | OP_LDH K_POFF {
                bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
                                   SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
+       | OP_LDH K_RAND {
+               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
+                                  SKF_AD_OFF + SKF_AD_RANDOM); }
        ;
 
 ldi
@@ -265,6 +271,9 @@ ld
        | OP_LD K_POFF {
                bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
                                   SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
+       | OP_LD K_RAND {
+               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
+                                  SKF_AD_OFF + SKF_AD_RANDOM); }
        | OP_LD 'M' '[' number ']' {
                bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
        | OP_LD '[' 'x' '+' number ']' {
index e96923310d5780e2fe62e45736b2511f43aa907d..895edd32930ce7283cbda2df8914ba44462fc7ef 100644 (file)
@@ -589,7 +589,7 @@ $(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H)
        $(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $<
 
 $(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS)
-       $(QUIET_LINK)$(CC) -o $@ -shared $(ALL_LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
+       $(QUIET_LINK)$(CC) -o $@ -shared $(LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
 
 $(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
index b602ad93ce630ae3f611ee74f0bb6277c367a09b..83bc2385e6d3c2820958b279f77c4d08342b1e06 100644 (file)
@@ -23,9 +23,10 @@ static int sample_ustack(struct perf_sample *sample,
 
        sp = (unsigned long) regs[PERF_REG_X86_SP];
 
-       map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
+       map = map_groups__find(&thread->mg, MAP__VARIABLE, (u64) sp);
        if (!map) {
                pr_debug("failed to get stack map\n");
+               free(buf);
                return -1;
        }
 
index 99167bf644eaa8b376060b6b6d42977e9cd09425..60875d5c556c217d3433487d65cf66382a78d25b 100644 (file)
@@ -1,4 +1,3 @@
-
 #include <linux/linkage.h>
 
 #define AX      0
@@ -90,3 +89,10 @@ ENTRY(perf_regs_load)
        ret
 ENDPROC(perf_regs_load)
 #endif
+
+/*
+ * We need to provide note.GNU-stack section, saying that we want
+ * NOT executable stack. Otherwise the final linking will assume that
+ * the ELF stack should not be restricted at all and set it RWX.
+ */
+.section .note.GNU-stack,"",@progbits
index ee21fa95ebcf60c2067b32f3e9b4575974f930ad..802cf544202b7b06720afc9abb1c9580cf362892 100644 (file)
@@ -34,6 +34,14 @@ ifeq ($(ARCH),arm)
   LIBUNWIND_LIBS = -lunwind -lunwind-arm
 endif
 
+# So far there's only x86 libdw unwind support merged in perf.
+# Disable it on all other architectures in case libdw unwind
+# support is detected in system. Add supported architectures
+# to the check.
+ifneq ($(ARCH),x86)
+  NO_LIBDW_DWARF_UNWIND := 1
+endif
+
 ifeq ($(LIBUNWIND_LIBS),)
   NO_LIBUNWIND := 1
 else
@@ -109,6 +117,10 @@ CFLAGS += -Wall
 CFLAGS += -Wextra
 CFLAGS += -std=gnu99
 
+# Enforce a non-executable stack, as we may regress (again) in the future by
+# adding assembler files missing the .GNU-stack linker note.
+LDFLAGS += -Wl,-z,noexecstack
+
 EXTLIBS = -lelf -lpthread -lrt -lm -ldl
 
 ifneq ($(OUTPUT),)
@@ -186,7 +198,10 @@ VF_FEATURE_TESTS =                 \
        stackprotector-all              \
        timerfd                         \
        libunwind-debug-frame           \
-       bionic
+       bionic                          \
+       liberty                         \
+       liberty-z                       \
+       cplus-demangle
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
@@ -504,7 +519,21 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd -lz -liberty
+  EXTLIBS += -lbfd
+
+  # call all detections now so we get correct
+  # status in VF output
+  $(call feature_check,liberty)
+  $(call feature_check,liberty-z)
+  $(call feature_check,cplus-demangle)
+
+  ifeq ($(feature-liberty), 1)
+    EXTLIBS += -liberty
+  else
+    ifeq ($(feature-liberty-z), 1)
+      EXTLIBS += -liberty -lz
+    endif
+  endif
 endif
 
 ifdef NO_DEMANGLE
@@ -515,15 +544,10 @@ else
     CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
   else
     ifneq ($(feature-libbfd), 1)
-      $(call feature_check,liberty)
-      ifeq ($(feature-liberty), 1)
-        EXTLIBS += -lbfd -liberty
-      else
-        $(call feature_check,liberty-z)
-        ifeq ($(feature-liberty-z), 1)
-          EXTLIBS += -lbfd -liberty -lz
-        else
-          $(call feature_check,cplus-demangle)
+      ifneq ($(feature-liberty), 1)
+        ifneq ($(feature-liberty-z), 1)
+          # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
+          # or any of 'bfd iberty z' trinity
           ifeq ($(feature-cplus-demangle), 1)
             EXTLIBS += -liberty
             CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
index 5daeae1cb4c01b3a87f4c54ee4018199c12aeeb6..2f92d6e7ee007bea58636fe8509757c4f626d77d 100644 (file)
@@ -46,6 +46,7 @@ make_install_man    := install-man
 make_install_html   := install-html
 make_install_info   := install-info
 make_install_pdf    := install-pdf
+make_static         := LDFLAGS=-static
 
 # all the NO_* variable combined
 make_minimal        := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
@@ -87,6 +88,7 @@ run += make_install_bin
 # run += make_install_info
 # run += make_install_pdf
 run += make_minimal
+run += make_static
 
 ifneq ($(call has,ctags),)
 run += make_tags
index a53cd0b8c151cdb898d3711c36e5081846813a15..27c2a5efe4504945bf9c8492b62b8256abc0be33 100644 (file)
@@ -717,7 +717,7 @@ static char *get_kernel_version(const char *root_dir)
 }
 
 static int map_groups__set_modules_path_dir(struct map_groups *mg,
-                               const char *dir_name)
+                               const char *dir_name, int depth)
 {
        struct dirent *dent;
        DIR *dir = opendir(dir_name);
@@ -742,7 +742,15 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
                            !strcmp(dent->d_name, ".."))
                                continue;
 
-                       ret = map_groups__set_modules_path_dir(mg, path);
+                       /* Do not follow top-level source and build symlinks */
+                       if (depth == 0) {
+                               if (!strcmp(dent->d_name, "source") ||
+                                   !strcmp(dent->d_name, "build"))
+                                       continue;
+                       }
+
+                       ret = map_groups__set_modules_path_dir(mg, path,
+                                                              depth + 1);
                        if (ret < 0)
                                goto out;
                } else {
@@ -786,11 +794,11 @@ static int machine__set_modules_path(struct machine *machine)
        if (!version)
                return -1;
 
-       snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
+       snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s",
                 machine->root_dir, version);
        free(version);
 
-       return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
+       return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
 }
 
 static int machine__create_module(void *arg, const char *name, u64 start)
index c2c0f20067a5028ebf304ca4758c830b80ffbe35..e5a3c4be2a10d696c31aebc733234964197affad 100644 (file)
@@ -19,6 +19,8 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
 $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
 endif
 
+SUBDIRS = tools/ec
+
 # --- CONFIGURATION BEGIN ---
 
 # Set the following to `true' to make a unstripped, unoptimized
@@ -68,7 +70,8 @@ WARNINGS += $(call cc-supports,-Wstrict-prototypes)
 WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
 
 KERNEL_INCLUDE := ../../../include
-CFLAGS += -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE)
+ACPICA_INCLUDE := ../../../drivers/acpi/acpica
+CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE)
 CFLAGS += $(WARNINGS)
 
 ifeq ($(strip $(V)),false)
@@ -92,10 +95,29 @@ endif
 # --- ACPIDUMP BEGIN ---
 
 vpath %.c \
-       tools/acpidump
+       ../../../drivers/acpi/acpica\
+       tools/acpidump\
+       common\
+       os_specific/service_layers
+
+CFLAGS += -DACPI_DUMP_APP -Itools/acpidump
 
 DUMP_OBJS = \
-       acpidump.o
+       apdump.o\
+       apfiles.o\
+       apmain.o\
+       osunixdir.o\
+       osunixmap.o\
+       tbprint.o\
+       tbxfroot.o\
+       utbuffer.o\
+       utexcep.o\
+       utmath.o\
+       utstring.o\
+       utxferror.o\
+       oslinuxtbl.o\
+       cmfsize.o\
+       getopt.o
 
 DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS))
 
diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c
new file mode 100644 (file)
index 0000000..5140e5e
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Module Name: cfsize - Common get file size function
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acapps.h"
+#include <stdio.h>
+
+#define _COMPONENT          ACPI_TOOLS
+ACPI_MODULE_NAME("cmfsize")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    cm_get_file_size
+ *
+ * PARAMETERS:  file                    - Open file descriptor
+ *
+ * RETURN:      File Size. On error, -1 (ACPI_UINT32_MAX)
+ *
+ * DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open.
+ *              Does not disturb the current file pointer. Uses perror for
+ *              error messages.
+ *
+ ******************************************************************************/
+u32 cm_get_file_size(FILE * file)
+{
+       long file_size;
+       long current_offset;
+
+       /* Save the current file pointer, seek to EOF to obtain file size */
+
+       current_offset = ftell(file);
+       if (current_offset < 0) {
+               goto offset_error;
+       }
+
+       if (fseek(file, 0, SEEK_END)) {
+               goto seek_error;
+       }
+
+       file_size = ftell(file);
+       if (file_size < 0) {
+               goto offset_error;
+       }
+
+       /* Restore original file pointer */
+
+       if (fseek(file, current_offset, SEEK_SET)) {
+               goto seek_error;
+       }
+
+       return ((u32)file_size);
+
+offset_error:
+       perror("Could not get file offset");
+       return (ACPI_UINT32_MAX);
+
+seek_error:
+       perror("Could not seek file");
+       return (ACPI_UINT32_MAX);
+}
diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c
new file mode 100644 (file)
index 0000000..a302f52
--- /dev/null
@@ -0,0 +1,239 @@
+/******************************************************************************
+ *
+ * Module Name: getopt
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+/*
+ * ACPICA getopt() implementation
+ *
+ * Option strings:
+ *    "f"       - Option has no arguments
+ *    "f:"      - Option requires an argument
+ *    "f^"      - Option has optional single-char sub-options
+ *    "f|"      - Option has required single-char sub-options
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acapps.h"
+
+#define ACPI_OPTION_ERROR(msg, badchar) \
+       if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);}
+
+int acpi_gbl_opterr = 1;
+int acpi_gbl_optind = 1;
+int acpi_gbl_sub_opt_char = 0;
+char *acpi_gbl_optarg;
+
+static int current_char_ptr = 1;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_getopt_argument
+ *
+ * PARAMETERS:  argc, argv          - from main
+ *
+ * RETURN:      0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg
+ *              to point to the next argument.
+ *
+ * DESCRIPTION: Get the next argument. Used to obtain arguments for the
+ *              two-character options after the original call to acpi_getopt.
+ *              Note: Either the argument starts at the next character after
+ *              the option, or it is pointed to by the next argv entry.
+ *              (After call to acpi_getopt, we need to backup to the previous
+ *              argv entry).
+ *
+ ******************************************************************************/
+
+int acpi_getopt_argument(int argc, char **argv)
+{
+       acpi_gbl_optind--;
+       current_char_ptr++;
+
+       if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
+               acpi_gbl_optarg =
+                   &argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)];
+       } else if (++acpi_gbl_optind >= argc) {
+               ACPI_OPTION_ERROR("Option requires an argument: -", 'v');
+
+               current_char_ptr = 1;
+               return (-1);
+       } else {
+               acpi_gbl_optarg = argv[acpi_gbl_optind++];
+       }
+
+       current_char_ptr = 1;
+       return (0);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_getopt
+ *
+ * PARAMETERS:  argc, argv          - from main
+ *              opts                - options info list
+ *
+ * RETURN:      Option character or EOF
+ *
+ * DESCRIPTION: Get the next option
+ *
+ ******************************************************************************/
+
+int acpi_getopt(int argc, char **argv, char *opts)
+{
+       int current_char;
+       char *opts_ptr;
+
+       if (current_char_ptr == 1) {
+               if (acpi_gbl_optind >= argc ||
+                   argv[acpi_gbl_optind][0] != '-' ||
+                   argv[acpi_gbl_optind][1] == '\0') {
+                       return (EOF);
+               } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) {
+                       acpi_gbl_optind++;
+                       return (EOF);
+               }
+       }
+
+       /* Get the option */
+
+       current_char = argv[acpi_gbl_optind][current_char_ptr];
+
+       /* Make sure that the option is legal */
+
+       if (current_char == ':' ||
+           (opts_ptr = strchr(opts, current_char)) == NULL) {
+               ACPI_OPTION_ERROR("Illegal option: -", current_char);
+
+               if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
+                       acpi_gbl_optind++;
+                       current_char_ptr = 1;
+               }
+
+               return ('?');
+       }
+
+       /* Option requires an argument? */
+
+       if (*++opts_ptr == ':') {
+               if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
+                       acpi_gbl_optarg =
+                           &argv[acpi_gbl_optind++][(int)
+                                                    (current_char_ptr + 1)];
+               } else if (++acpi_gbl_optind >= argc) {
+                       ACPI_OPTION_ERROR("Option requires an argument: -",
+                                         current_char);
+
+                       current_char_ptr = 1;
+                       return ('?');
+               } else {
+                       acpi_gbl_optarg = argv[acpi_gbl_optind++];
+               }
+
+               current_char_ptr = 1;
+       }
+
+       /* Option has an optional argument? */
+
+       else if (*opts_ptr == '+') {
+               if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
+                       acpi_gbl_optarg =
+                           &argv[acpi_gbl_optind++][(int)
+                                                    (current_char_ptr + 1)];
+               } else if (++acpi_gbl_optind >= argc) {
+                       acpi_gbl_optarg = NULL;
+               } else {
+                       acpi_gbl_optarg = argv[acpi_gbl_optind++];
+               }
+
+               current_char_ptr = 1;
+       }
+
+       /* Option has optional single-char arguments? */
+
+       else if (*opts_ptr == '^') {
+               if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
+                       acpi_gbl_optarg =
+                           &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
+               } else {
+                       acpi_gbl_optarg = "^";
+               }
+
+               acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
+               acpi_gbl_optind++;
+               current_char_ptr = 1;
+       }
+
+       /* Option has a required single-char argument? */
+
+       else if (*opts_ptr == '|') {
+               if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
+                       acpi_gbl_optarg =
+                           &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
+               } else {
+                       ACPI_OPTION_ERROR
+                           ("Option requires a single-character suboption: -",
+                            current_char);
+
+                       current_char_ptr = 1;
+                       return ('?');
+               }
+
+               acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
+               acpi_gbl_optind++;
+               current_char_ptr = 1;
+       }
+
+       /* Option with no arguments */
+
+       else {
+               if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
+                       current_char_ptr = 1;
+                       acpi_gbl_optind++;
+               }
+
+               acpi_gbl_optarg = NULL;
+       }
+
+       return (current_char);
+}
index adfa99166e5eabeb5d85ad066345871d67f2adb9..38f095d86b5260d54a30f8dfde8da33de91d1995 100644 (file)
@@ -1,18 +1,64 @@
 .TH ACPIDUMP 8
 .SH NAME
-acpidump \- Dump system's ACPI tables to an ASCII file.
+acpidump \- dump a system's ACPI tables to an ASCII file
+
 .SH SYNOPSIS
-.ft B
-.B acpidump > acpidump.out
+.B acpidump
+.RI [ options ]
+.br
+
 .SH DESCRIPTION
-\fBacpidump \fP dumps the systems ACPI tables to an ASCII file
-appropriate for attaching to a bug report.
+.B acpidump
+dumps the systems ACPI tables to an ASCII file appropriate for
+attaching to a bug report.
 
 Subsequently, they can be processed by utilities in the ACPICA package.
-.SS Options
-no options worth worrying about.
-.PP
-.SH EXAMPLE
+
+.SH OPTIONS
+acpidump options are as follow:
+.TP
+.B Options
+.TP
+.B \-b
+Dump tables to binary files
+.TP
+.B \-c
+Dump customized tables
+.TP
+.B \-h \-?
+This help message
+.TP
+.B \-o <File>
+Redirect output to file
+.TP
+.B \-r <Address>
+Dump tables from specified RSDP
+.TP
+.B \-s
+Print table summaries only
+.TP
+.B \-v
+Display version information
+.TP
+.B \-z
+Verbose mode
+.TP
+.B Table Options
+.TP
+.B \-a <Address>
+Get table via a physical address
+.TP
+.B \-f <BinaryFile>
+Get table via a binary file
+.TP
+.B \-n <Signature>
+Get table via a name/signature
+.TP
+Invocation without parameters dumps all available tables
+.TP
+Multiple mixed instances of -a, -f, and -n are supported
+
+.SH EXAMPLES
 
 .nf
 # acpidump > acpidump.out
@@ -50,10 +96,25 @@ ACPICA: https://acpica.org/
 .ta
 .nf
 /dev/mem
+/sys/firmware/acpi/tables/*
 /sys/firmware/acpi/tables/dynamic/*
+/sys/firmware/efi/systab
 .fi
 
-.PP
 .SH AUTHOR
-.nf
-Written by Len Brown <len.brown@intel.com>
+.TP
+Original by:
+ Len Brown <len.brown@intel.com>
+.TP
+Written by:
+ Chao Guan <chao.guan@intel.com>
+.TP
+Updated by:
+ Bob Moore <robert.moore@intel.com>
+ Lv Zheng <lv.zheng@intel.com>
+
+.SH SEE ALSO
+\&\fIacpixtract\fR\|(8), \fIiasl\fR\|(8).
+
+.SH COPYRIGHT
+COPYRIGHT (c) 2013, Intel Corporation.
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
new file mode 100644 (file)
index 0000000..e975aa9
--- /dev/null
@@ -0,0 +1,1275 @@
+/******************************************************************************
+ *
+ * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include "acpidump.h"
+
+#define _COMPONENT          ACPI_OS_SERVICES
+ACPI_MODULE_NAME("oslinuxtbl")
+
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif
+/* List of information about obtained ACPI tables */
+typedef struct osl_table_info {
+       struct osl_table_info *next;
+       u32 instance;
+       char signature[ACPI_NAME_SIZE];
+
+} osl_table_info;
+
+/* Local prototypes */
+
+static acpi_status osl_table_initialize(void);
+
+static acpi_status
+osl_table_name_from_file(char *filename, char *signature, u32 *instance);
+
+static acpi_status osl_add_table_to_list(char *signature, u32 instance);
+
+static acpi_status
+osl_read_table_from_file(char *filename,
+                        acpi_size file_offset,
+                        char *signature, struct acpi_table_header **table);
+
+static acpi_status
+osl_map_table(acpi_size address,
+             char *signature, struct acpi_table_header **table);
+
+static void osl_unmap_table(struct acpi_table_header *table);
+
+static acpi_physical_address osl_find_rsdp_via_efi(void);
+
+static acpi_status osl_load_rsdp(void);
+
+static acpi_status osl_list_customized_tables(char *directory);
+
+static acpi_status
+osl_get_customized_table(char *pathname,
+                        char *signature,
+                        u32 instance,
+                        struct acpi_table_header **table,
+                        acpi_physical_address * address);
+
+static acpi_status osl_list_bios_tables(void);
+
+static acpi_status
+osl_get_bios_table(char *signature,
+                  u32 instance,
+                  struct acpi_table_header **table,
+                  acpi_physical_address * address);
+
+static acpi_status osl_get_last_status(acpi_status default_status);
+
+/* File locations */
+
+#define DYNAMIC_TABLE_DIR   "/sys/firmware/acpi/tables/dynamic"
+#define STATIC_TABLE_DIR    "/sys/firmware/acpi/tables"
+#define EFI_SYSTAB          "/sys/firmware/efi/systab"
+
+/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
+
+u8 gbl_dump_dynamic_tables = TRUE;
+
+/* Initialization flags */
+
+u8 gbl_table_list_initialized = FALSE;
+
+/* Local copies of main ACPI tables */
+
+struct acpi_table_rsdp gbl_rsdp;
+struct acpi_table_fadt *gbl_fadt = NULL;
+struct acpi_table_rsdt *gbl_rsdt = NULL;
+struct acpi_table_xsdt *gbl_xsdt = NULL;
+
+/* Table addresses */
+
+acpi_physical_address gbl_fadt_address = 0;
+acpi_physical_address gbl_rsdp_address = 0;
+
+/* Revision of RSD PTR */
+
+u8 gbl_revision = 0;
+
+struct osl_table_info *gbl_table_list_head = NULL;
+u32 gbl_table_count = 0;
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_get_last_status
+ *
+ * PARAMETERS:  default_status  - Default error status to return
+ *
+ * RETURN:      Status; Converted from errno.
+ *
+ * DESCRIPTION: Get last errno and conver it to acpi_status.
+ *
+ *****************************************************************************/
+
+static acpi_status osl_get_last_status(acpi_status default_status)
+{
+
+       switch (errno) {
+       case EACCES:
+       case EPERM:
+
+               return (AE_ACCESS);
+
+       case ENOENT:
+
+               return (AE_NOT_FOUND);
+
+       case ENOMEM:
+
+               return (AE_NO_MEMORY);
+
+       default:
+
+               return (default_status);
+       }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os_get_table_by_address
+ *
+ * PARAMETERS:  address         - Physical address of the ACPI table
+ *              table           - Where a pointer to the table is returned
+ *
+ * RETURN:      Status; Table buffer is returned if AE_OK.
+ *              AE_NOT_FOUND: A valid table was not found at the address
+ *
+ * DESCRIPTION: Get an ACPI table via a physical memory address.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_get_table_by_address(acpi_physical_address address,
+                            struct acpi_table_header ** table)
+{
+       u32 table_length;
+       struct acpi_table_header *mapped_table;
+       struct acpi_table_header *local_table = NULL;
+       acpi_status status = AE_OK;
+
+       /* Get main ACPI tables from memory on first invocation of this function */
+
+       status = osl_table_initialize();
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Map the table and validate it */
+
+       status = osl_map_table(address, NULL, &mapped_table);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Copy table to local buffer and return it */
+
+       table_length = ap_get_table_length(mapped_table);
+       if (table_length == 0) {
+               status = AE_BAD_HEADER;
+               goto exit;
+       }
+
+       local_table = calloc(1, table_length);
+       if (!local_table) {
+               status = AE_NO_MEMORY;
+               goto exit;
+       }
+
+       ACPI_MEMCPY(local_table, mapped_table, table_length);
+
+exit:
+       osl_unmap_table(mapped_table);
+       *table = local_table;
+       return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os_get_table_by_name
+ *
+ * PARAMETERS:  signature       - ACPI Signature for desired table. Must be
+ *                                a null terminated 4-character string.
+ *              instance        - Multiple table support for SSDT/UEFI (0...n)
+ *                                Must be 0 for other tables.
+ *              table           - Where a pointer to the table is returned
+ *              address         - Where the table physical address is returned
+ *
+ * RETURN:      Status; Table buffer and physical address returned if AE_OK.
+ *              AE_LIMIT: Instance is beyond valid limit
+ *              AE_NOT_FOUND: A table with the signature was not found
+ *
+ * NOTE:        Assumes the input signature is uppercase.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_get_table_by_name(char *signature,
+                         u32 instance,
+                         struct acpi_table_header ** table,
+                         acpi_physical_address * address)
+{
+       acpi_status status;
+
+       /* Get main ACPI tables from memory on first invocation of this function */
+
+       status = osl_table_initialize();
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
+
+       if (!gbl_dump_customized_tables) {
+
+               /* Attempt to get the table from the memory */
+
+               status =
+                   osl_get_bios_table(signature, instance, table, address);
+       } else {
+               /* Attempt to get the table from the static directory */
+
+               status = osl_get_customized_table(STATIC_TABLE_DIR, signature,
+                                                 instance, table, address);
+       }
+
+       if (ACPI_FAILURE(status) && status == AE_LIMIT) {
+               if (gbl_dump_dynamic_tables) {
+
+                       /* Attempt to get a dynamic table */
+
+                       status =
+                           osl_get_customized_table(DYNAMIC_TABLE_DIR,
+                                                    signature, instance, table,
+                                                    address);
+               }
+       }
+
+       return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_add_table_to_list
+ *
+ * PARAMETERS:  signature       - Table signature
+ *              instance        - Table instance
+ *
+ * RETURN:      Status; Successfully added if AE_OK.
+ *              AE_NO_MEMORY: Memory allocation error
+ *
+ * DESCRIPTION: Insert a table structure into OSL table list.
+ *
+ *****************************************************************************/
+
+static acpi_status osl_add_table_to_list(char *signature, u32 instance)
+{
+       struct osl_table_info *new_info;
+       struct osl_table_info *next;
+       u32 next_instance = 0;
+       u8 found = FALSE;
+
+       new_info = calloc(1, sizeof(struct osl_table_info));
+       if (!new_info) {
+               return (AE_NO_MEMORY);
+       }
+
+       ACPI_MOVE_NAME(new_info->signature, signature);
+
+       if (!gbl_table_list_head) {
+               gbl_table_list_head = new_info;
+       } else {
+               next = gbl_table_list_head;
+               while (1) {
+                       if (ACPI_COMPARE_NAME(next->signature, signature)) {
+                               if (next->instance == instance) {
+                                       found = TRUE;
+                               }
+                               if (next->instance >= next_instance) {
+                                       next_instance = next->instance + 1;
+                               }
+                       }
+
+                       if (!next->next) {
+                               break;
+                       }
+                       next = next->next;
+               }
+               next->next = new_info;
+       }
+
+       if (found) {
+               if (instance) {
+                       fprintf(stderr,
+                               "%4.4s: Warning unmatched table instance %d, expected %d\n",
+                               signature, instance, next_instance);
+               }
+               instance = next_instance;
+       }
+
+       new_info->instance = instance;
+       gbl_table_count++;
+
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os_get_table_by_index
+ *
+ * PARAMETERS:  index           - Which table to get
+ *              table           - Where a pointer to the table is returned
+ *              instance        - Where a pointer to the table instance no. is
+ *                                returned
+ *              address         - Where the table physical address is returned
+ *
+ * RETURN:      Status; Table buffer and physical address returned if AE_OK.
+ *              AE_LIMIT: Index is beyond valid limit
+ *
+ * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
+ *              AE_LIMIT when an invalid index is reached. Index is not
+ *              necessarily an index into the RSDT/XSDT.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_get_table_by_index(u32 index,
+                          struct acpi_table_header ** table,
+                          u32 *instance, acpi_physical_address * address)
+{
+       struct osl_table_info *info;
+       acpi_status status;
+       u32 i;
+
+       /* Get main ACPI tables from memory on first invocation of this function */
+
+       status = osl_table_initialize();
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Validate Index */
+
+       if (index >= gbl_table_count) {
+               return (AE_LIMIT);
+       }
+
+       /* Point to the table list entry specified by the Index argument */
+
+       info = gbl_table_list_head;
+       for (i = 0; i < index; i++) {
+               info = info->next;
+       }
+
+       /* Now we can just get the table via the signature */
+
+       status = acpi_os_get_table_by_name(info->signature, info->instance,
+                                          table, address);
+
+       if (ACPI_SUCCESS(status)) {
+               *instance = info->instance;
+       }
+       return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_find_rsdp_via_efi
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      RSDP address if found
+ *
+ * DESCRIPTION: Find RSDP address via EFI.
+ *
+ *****************************************************************************/
+
+static acpi_physical_address osl_find_rsdp_via_efi(void)
+{
+       FILE *file;
+       char buffer[80];
+       unsigned long address = 0;
+
+       file = fopen(EFI_SYSTAB, "r");
+       if (file) {
+               while (fgets(buffer, 80, file)) {
+                       if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) {
+                               break;
+                       }
+               }
+               fclose(file);
+       }
+
+       return ((acpi_physical_address) (address));
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_load_rsdp
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Scan and load RSDP.
+ *
+ *****************************************************************************/
+
+static acpi_status osl_load_rsdp(void)
+{
+       struct acpi_table_header *mapped_table;
+       u8 *rsdp_address;
+       acpi_physical_address rsdp_base;
+       acpi_size rsdp_size;
+
+       /* Get RSDP from memory */
+
+       rsdp_size = sizeof(struct acpi_table_rsdp);
+       if (gbl_rsdp_base) {
+               rsdp_base = gbl_rsdp_base;
+       } else {
+               rsdp_base = osl_find_rsdp_via_efi();
+       }
+
+       if (!rsdp_base) {
+               rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
+               rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
+       }
+
+       rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
+       if (!rsdp_address) {
+               return (osl_get_last_status(AE_BAD_ADDRESS));
+       }
+
+       /* Search low memory for the RSDP */
+
+       mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
+                                    acpi_tb_scan_memory_for_rsdp(rsdp_address,
+                                                                 rsdp_size));
+       if (!mapped_table) {
+               acpi_os_unmap_memory(rsdp_address, rsdp_size);
+               return (AE_NOT_FOUND);
+       }
+
+       gbl_rsdp_address =
+           rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
+
+       ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
+       acpi_os_unmap_memory(rsdp_address, rsdp_size);
+
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_table_initialize
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
+ *              local variables. Main ACPI tables include RSDT, FADT, RSDT,
+ *              and/or XSDT.
+ *
+ *****************************************************************************/
+
+static acpi_status osl_table_initialize(void)
+{
+       acpi_status status;
+       acpi_physical_address address;
+
+       if (gbl_table_list_initialized) {
+               return (AE_OK);
+       }
+
+       /* Get RSDP from memory */
+
+       status = osl_load_rsdp();
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Get XSDT from memory */
+
+       if (gbl_rsdp.revision) {
+               if (gbl_xsdt) {
+                       free(gbl_xsdt);
+                       gbl_xsdt = NULL;
+               }
+
+               gbl_revision = 2;
+               status = osl_get_bios_table(ACPI_SIG_XSDT, 0,
+                                           ACPI_CAST_PTR(struct
+                                                         acpi_table_header *,
+                                                         &gbl_xsdt), &address);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       }
+
+       /* Get RSDT from memory */
+
+       if (gbl_rsdp.rsdt_physical_address) {
+               if (gbl_rsdt) {
+                       free(gbl_rsdt);
+                       gbl_rsdt = NULL;
+               }
+
+               status = osl_get_bios_table(ACPI_SIG_RSDT, 0,
+                                           ACPI_CAST_PTR(struct
+                                                         acpi_table_header *,
+                                                         &gbl_rsdt), &address);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       }
+
+       /* Get FADT from memory */
+
+       if (gbl_fadt) {
+               free(gbl_fadt);
+               gbl_fadt = NULL;
+       }
+
+       status = osl_get_bios_table(ACPI_SIG_FADT, 0,
+                                   ACPI_CAST_PTR(struct acpi_table_header *,
+                                                 &gbl_fadt),
+                                   &gbl_fadt_address);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       if (!gbl_dump_customized_tables) {
+
+               /* Add mandatory tables to global table list first */
+
+               status = osl_add_table_to_list(ACPI_RSDP_NAME, 0);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               status = osl_add_table_to_list(ACPI_SIG_RSDT, 0);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               if (gbl_revision == 2) {
+                       status = osl_add_table_to_list(ACPI_SIG_XSDT, 0);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+               }
+
+               status = osl_add_table_to_list(ACPI_SIG_DSDT, 0);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               status = osl_add_table_to_list(ACPI_SIG_FACS, 0);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               /* Add all tables found in the memory */
+
+               status = osl_list_bios_tables();
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       } else {
+               /* Add all tables found in the static directory */
+
+               status = osl_list_customized_tables(STATIC_TABLE_DIR);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       }
+
+       if (gbl_dump_dynamic_tables) {
+
+               /* Add all dynamically loaded tables in the dynamic directory */
+
+               status = osl_list_customized_tables(DYNAMIC_TABLE_DIR);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       }
+
+       gbl_table_list_initialized = TRUE;
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_list_bios_tables
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status; Table list is initialized if AE_OK.
+ *
+ * DESCRIPTION: Add ACPI tables to the table list from memory.
+ *
+ * NOTE:        This works on Linux as table customization does not modify the
+ *              addresses stored in RSDP/RSDT/XSDT/FADT.
+ *
+ *****************************************************************************/
+
+static acpi_status osl_list_bios_tables(void)
+{
+       struct acpi_table_header *mapped_table = NULL;
+       u8 *table_data;
+       u8 number_of_tables;
+       u8 item_size;
+       acpi_physical_address table_address = 0;
+       acpi_status status = AE_OK;
+       u32 i;
+
+       if (gbl_revision) {
+               item_size = sizeof(u64);
+               table_data =
+                   ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
+               number_of_tables =
+                   (u8)((gbl_xsdt->header.length -
+                         sizeof(struct acpi_table_header))
+                        / item_size);
+       } else {                /* Use RSDT if XSDT is not available */
+
+               item_size = sizeof(u32);
+               table_data =
+                   ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
+               number_of_tables =
+                   (u8)((gbl_rsdt->header.length -
+                         sizeof(struct acpi_table_header))
+                        / item_size);
+       }
+
+       /* Search RSDT/XSDT for the requested table */
+
+       for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
+               if (gbl_revision) {
+                       table_address =
+                           (acpi_physical_address) (*ACPI_CAST64(table_data));
+               } else {
+                       table_address =
+                           (acpi_physical_address) (*ACPI_CAST32(table_data));
+               }
+
+               status = osl_map_table(table_address, NULL, &mapped_table);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               osl_add_table_to_list(mapped_table->signature, 0);
+               osl_unmap_table(mapped_table);
+       }
+
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_get_bios_table
+ *
+ * PARAMETERS:  signature       - ACPI Signature for common table. Must be
+ *                                a null terminated 4-character string.
+ *              instance        - Multiple table support for SSDT/UEFI (0...n)
+ *                                Must be 0 for other tables.
+ *              table           - Where a pointer to the table is returned
+ *              address         - Where the table physical address is returned
+ *
+ * RETURN:      Status; Table buffer and physical address returned if AE_OK.
+ *              AE_LIMIT: Instance is beyond valid limit
+ *              AE_NOT_FOUND: A table with the signature was not found
+ *
+ * DESCRIPTION: Get a BIOS provided ACPI table
+ *
+ * NOTE:        Assumes the input signature is uppercase.
+ *
+ *****************************************************************************/
+
+static acpi_status
+osl_get_bios_table(char *signature,
+                  u32 instance,
+                  struct acpi_table_header **table,
+                  acpi_physical_address * address)
+{
+       struct acpi_table_header *local_table = NULL;
+       struct acpi_table_header *mapped_table = NULL;
+       u8 *table_data;
+       u8 number_of_tables;
+       u8 item_size;
+       u32 current_instance = 0;
+       acpi_physical_address table_address = 0;
+       u32 table_length = 0;
+       acpi_status status = AE_OK;
+       u32 i;
+
+       /* Handle special tables whose addresses are not in RSDT/XSDT */
+
+       if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) ||
+           ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) ||
+           ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) ||
+           ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) ||
+           ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
+               /*
+                * Get the appropriate address, either 32-bit or 64-bit. Be very
+                * careful about the FADT length and validate table addresses.
+                * Note: The 64-bit addresses have priority.
+                */
+               if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) {
+                       if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) &&
+                           gbl_fadt->Xdsdt) {
+                               table_address =
+                                   (acpi_physical_address) gbl_fadt->Xdsdt;
+                       } else
+                           if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT)
+                               && gbl_fadt->dsdt) {
+                               table_address =
+                                   (acpi_physical_address) gbl_fadt->dsdt;
+                       }
+               } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
+                       if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) &&
+                           gbl_fadt->Xfacs) {
+                               table_address =
+                                   (acpi_physical_address) gbl_fadt->Xfacs;
+                       } else
+                           if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS)
+                               && gbl_fadt->facs) {
+                               table_address =
+                                   (acpi_physical_address) gbl_fadt->facs;
+                       }
+               } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
+                       if (!gbl_revision) {
+                               return (AE_BAD_SIGNATURE);
+                       }
+                       table_address =
+                           (acpi_physical_address) gbl_rsdp.
+                           xsdt_physical_address;
+               } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
+                       table_address =
+                           (acpi_physical_address) gbl_rsdp.
+                           rsdt_physical_address;
+               } else {
+                       table_address =
+                           (acpi_physical_address) gbl_rsdp_address;
+                       signature = ACPI_SIG_RSDP;
+               }
+
+               /* Now we can get the requested special table */
+
+               status = osl_map_table(table_address, signature, &mapped_table);
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+
+               table_length = ap_get_table_length(mapped_table);
+       } else {                /* Case for a normal ACPI table */
+
+               if (gbl_revision) {
+                       item_size = sizeof(u64);
+                       table_data =
+                           ACPI_CAST8(gbl_xsdt) +
+                           sizeof(struct acpi_table_header);
+                       number_of_tables =
+                           (u8)((gbl_xsdt->header.length -
+                                 sizeof(struct acpi_table_header))
+                                / item_size);
+               } else {        /* Use RSDT if XSDT is not available */
+
+                       item_size = sizeof(u32);
+                       table_data =
+                           ACPI_CAST8(gbl_rsdt) +
+                           sizeof(struct acpi_table_header);
+                       number_of_tables =
+                           (u8)((gbl_rsdt->header.length -
+                                 sizeof(struct acpi_table_header))
+                                / item_size);
+               }
+
+               /* Search RSDT/XSDT for the requested table */
+
+               for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
+                       if (gbl_revision) {
+                               table_address =
+                                   (acpi_physical_address) (*ACPI_CAST64
+                                                            (table_data));
+                       } else {
+                               table_address =
+                                   (acpi_physical_address) (*ACPI_CAST32
+                                                            (table_data));
+                       }
+
+                       status =
+                           osl_map_table(table_address, NULL, &mapped_table);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+                       table_length = mapped_table->length;
+
+                       /* Does this table match the requested signature? */
+
+                       if (!ACPI_COMPARE_NAME
+                           (mapped_table->signature, signature)) {
+                               osl_unmap_table(mapped_table);
+                               mapped_table = NULL;
+                               continue;
+                       }
+
+                       /* Match table instance (for SSDT/UEFI tables) */
+
+                       if (current_instance != instance) {
+                               osl_unmap_table(mapped_table);
+                               mapped_table = NULL;
+                               current_instance++;
+                               continue;
+                       }
+
+                       break;
+               }
+       }
+
+       if (!mapped_table) {
+               return (AE_LIMIT);
+       }
+
+       if (table_length == 0) {
+               status = AE_BAD_HEADER;
+               goto exit;
+       }
+
+       /* Copy table to local buffer and return it */
+
+       local_table = calloc(1, table_length);
+       if (!local_table) {
+               status = AE_NO_MEMORY;
+               goto exit;
+       }
+
+       ACPI_MEMCPY(local_table, mapped_table, table_length);
+       *address = table_address;
+       *table = local_table;
+
+exit:
+       osl_unmap_table(mapped_table);
+       return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_list_customized_tables
+ *
+ * PARAMETERS:  directory           - Directory that contains the tables
+ *
+ * RETURN:      Status; Table list is initialized if AE_OK.
+ *
+ * DESCRIPTION: Add ACPI tables to the table list from a directory.
+ *
+ *****************************************************************************/
+
+static acpi_status osl_list_customized_tables(char *directory)
+{
+       void *table_dir;
+       u32 instance;
+       char temp_name[ACPI_NAME_SIZE];
+       char *filename;
+       acpi_status status = AE_OK;
+
+       /* Open the requested directory */
+
+       table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);
+       if (!table_dir) {
+               return (osl_get_last_status(AE_NOT_FOUND));
+       }
+
+       /* Examine all entries in this directory */
+
+       while ((filename = acpi_os_get_next_filename(table_dir))) {
+
+               /* Extract table name and instance number */
+
+               status =
+                   osl_table_name_from_file(filename, temp_name, &instance);
+
+               /* Ignore meaningless files */
+
+               if (ACPI_FAILURE(status)) {
+                       continue;
+               }
+
+               /* Add new info node to global table list */
+
+               status = osl_add_table_to_list(temp_name, instance);
+               if (ACPI_FAILURE(status)) {
+                       break;
+               }
+       }
+
+       acpi_os_close_directory(table_dir);
+       return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_map_table
+ *
+ * PARAMETERS:  address             - Address of the table in memory
+ *              signature           - Optional ACPI Signature for desired table.
+ *                                    Null terminated 4-character string.
+ *              table               - Where a pointer to the mapped table is
+ *                                    returned
+ *
+ * RETURN:      Status; Mapped table is returned if AE_OK.
+ *              AE_NOT_FOUND: A valid table was not found at the address
+ *
+ * DESCRIPTION: Map entire ACPI table into caller's address space.
+ *
+ *****************************************************************************/
+
+static acpi_status
+osl_map_table(acpi_size address,
+             char *signature, struct acpi_table_header **table)
+{
+       struct acpi_table_header *mapped_table;
+       u32 length;
+
+       if (!address) {
+               return (AE_BAD_ADDRESS);
+       }
+
+       /*
+        * Map the header so we can get the table length.
+        * Use sizeof (struct acpi_table_header) as:
+        * 1. it is bigger than 24 to include RSDP->Length
+        * 2. it is smaller than sizeof (struct acpi_table_rsdp)
+        */
+       mapped_table =
+           acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+       if (!mapped_table) {
+               fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
+                       ACPI_FORMAT_UINT64(address));
+               return (osl_get_last_status(AE_BAD_ADDRESS));
+       }
+
+       /* If specified, signature must match */
+
+       if (signature && !ACPI_COMPARE_NAME(signature, mapped_table->signature)) {
+               acpi_os_unmap_memory(mapped_table,
+                                    sizeof(struct acpi_table_header));
+               return (AE_BAD_SIGNATURE);
+       }
+
+       /* Map the entire table */
+
+       length = ap_get_table_length(mapped_table);
+       acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
+       if (length == 0) {
+               return (AE_BAD_HEADER);
+       }
+
+       mapped_table = acpi_os_map_memory(address, length);
+       if (!mapped_table) {
+               fprintf(stderr,
+                       "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
+                       ACPI_FORMAT_UINT64(address), length);
+               return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
+       }
+
+       (void)ap_is_valid_checksum(mapped_table);
+
+       *table = mapped_table;
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_unmap_table
+ *
+ * PARAMETERS:  table               - A pointer to the mapped table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Unmap entire ACPI table.
+ *
+ *****************************************************************************/
+
+static void osl_unmap_table(struct acpi_table_header *table)
+{
+       if (table) {
+               acpi_os_unmap_memory(table, ap_get_table_length(table));
+       }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_table_name_from_file
+ *
+ * PARAMETERS:  filename            - File that contains the desired table
+ *              signature           - Pointer to 4-character buffer to store
+ *                                    extracted table signature.
+ *              instance            - Pointer to integer to store extracted
+ *                                    table instance number.
+ *
+ * RETURN:      Status; Table name is extracted if AE_OK.
+ *
+ * DESCRIPTION: Extract table signature and instance number from a table file
+ *              name.
+ *
+ *****************************************************************************/
+
+static acpi_status
+osl_table_name_from_file(char *filename, char *signature, u32 *instance)
+{
+
+       /* Ignore meaningless files */
+
+       if (strlen(filename) < ACPI_NAME_SIZE) {
+               return (AE_BAD_SIGNATURE);
+       }
+
+       /* Extract instance number */
+
+       if (isdigit((int)filename[ACPI_NAME_SIZE])) {
+               sscanf(&filename[ACPI_NAME_SIZE], "%d", instance);
+       } else if (strlen(filename) != ACPI_NAME_SIZE) {
+               return (AE_BAD_SIGNATURE);
+       } else {
+               *instance = 0;
+       }
+
+       /* Extract signature */
+
+       ACPI_MOVE_NAME(signature, filename);
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_read_table_from_file
+ *
+ * PARAMETERS:  filename            - File that contains the desired table
+ *              file_offset         - Offset of the table in file
+ *              signature           - Optional ACPI Signature for desired table.
+ *                                    A null terminated 4-character string.
+ *              table               - Where a pointer to the table is returned
+ *
+ * RETURN:      Status; Table buffer is returned if AE_OK.
+ *
+ * DESCRIPTION: Read a ACPI table from a file.
+ *
+ *****************************************************************************/
+
+static acpi_status
+osl_read_table_from_file(char *filename,
+                        acpi_size file_offset,
+                        char *signature, struct acpi_table_header **table)
+{
+       FILE *table_file;
+       struct acpi_table_header header;
+       struct acpi_table_header *local_table = NULL;
+       u32 table_length;
+       s32 count;
+       u32 total = 0;
+       acpi_status status = AE_OK;
+
+       /* Open the file */
+
+       table_file = fopen(filename, "rb");
+       if (table_file == NULL) {
+               fprintf(stderr, "Could not open table file: %s\n", filename);
+               return (osl_get_last_status(AE_NOT_FOUND));
+       }
+
+       fseek(table_file, file_offset, SEEK_SET);
+
+       /* Read the Table header to get the table length */
+
+       count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
+       if (count != sizeof(struct acpi_table_header)) {
+               fprintf(stderr, "Could not read table header: %s\n", filename);
+               status = AE_BAD_HEADER;
+               goto exit;
+       }
+
+       /* If signature is specified, it must match the table */
+
+       if (signature && !ACPI_COMPARE_NAME(signature, header.signature)) {
+               fprintf(stderr,
+                       "Incorrect signature: Expecting %4.4s, found %4.4s\n",
+                       signature, header.signature);
+               status = AE_BAD_SIGNATURE;
+               goto exit;
+       }
+
+       table_length = ap_get_table_length(&header);
+       if (table_length == 0) {
+               status = AE_BAD_HEADER;
+               goto exit;
+       }
+
+       /* Read the entire table into a local buffer */
+
+       local_table = calloc(1, table_length);
+       if (!local_table) {
+               fprintf(stderr,
+                       "%4.4s: Could not allocate buffer for table of length %X\n",
+                       header.signature, table_length);
+               status = AE_NO_MEMORY;
+               goto exit;
+       }
+
+       fseek(table_file, file_offset, SEEK_SET);
+
+       while (!feof(table_file) && total < table_length) {
+               count = fread(local_table + total, 1, table_length - total, table_file);
+               if (count < 0) {
+                       fprintf(stderr, "%4.4s: Could not read table content\n",
+                               header.signature);
+                       status = AE_INVALID_TABLE_LENGTH;
+                       goto exit;
+               }
+
+               total += count;
+       }
+
+       /* Validate checksum */
+
+       (void)ap_is_valid_checksum(local_table);
+
+exit:
+       fclose(table_file);
+       *table = local_table;
+       return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    osl_get_customized_table
+ *
+ * PARAMETERS:  pathname        - Directory to find Linux customized table
+ *              signature       - ACPI Signature for desired table. Must be
+ *                                a null terminated 4-character string.
+ *              instance        - Multiple table support for SSDT/UEFI (0...n)
+ *                                Must be 0 for other tables.
+ *              table           - Where a pointer to the table is returned
+ *              address         - Where the table physical address is returned
+ *
+ * RETURN:      Status; Table buffer is returned if AE_OK.
+ *              AE_LIMIT: Instance is beyond valid limit
+ *              AE_NOT_FOUND: A table with the signature was not found
+ *
+ * DESCRIPTION: Get an OS customized table.
+ *
+ *****************************************************************************/
+
+static acpi_status
+osl_get_customized_table(char *pathname,
+                        char *signature,
+                        u32 instance,
+                        struct acpi_table_header **table,
+                        acpi_physical_address * address)
+{
+       void *table_dir;
+       u32 current_instance = 0;
+       char temp_name[ACPI_NAME_SIZE];
+       char table_filename[PATH_MAX];
+       char *filename;
+       acpi_status status;
+
+       /* Open the directory for customized tables */
+
+       table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
+       if (!table_dir) {
+               return (osl_get_last_status(AE_NOT_FOUND));
+       }
+
+       /* Attempt to find the table in the directory */
+
+       while ((filename = acpi_os_get_next_filename(table_dir))) {
+
+               /* Ignore meaningless files */
+
+               if (!ACPI_COMPARE_NAME(filename, signature)) {
+                       continue;
+               }
+
+               /* Extract table name and instance number */
+
+               status =
+                   osl_table_name_from_file(filename, temp_name,
+                                            &current_instance);
+
+               /* Ignore meaningless files */
+
+               if (ACPI_FAILURE(status) || current_instance != instance) {
+                       continue;
+               }
+
+               /* Create the table pathname */
+
+               if (instance != 0) {
+                       sprintf(table_filename, "%s/%4.4s%d", pathname,
+                               temp_name, instance);
+               } else {
+                       sprintf(table_filename, "%s/%4.4s", pathname,
+                               temp_name);
+               }
+               break;
+       }
+
+       acpi_os_close_directory(table_dir);
+
+       if (!filename) {
+               return (AE_LIMIT);
+       }
+
+       /* There is no physical address saved for customized tables, use zero */
+
+       *address = 0;
+       status = osl_read_table_from_file(table_filename, 0, NULL, table);
+
+       return (status);
+}
diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c
new file mode 100644 (file)
index 0000000..733f9e4
--- /dev/null
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * Module Name: osunixdir - Unix directory access interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+/*
+ * Allocated structure returned from os_open_directory
+ */
+typedef struct external_find_info {
+       char *dir_pathname;
+       DIR *dir_ptr;
+       char temp_buffer[256];
+       char *wildcard_spec;
+       char requested_file_type;
+
+} external_find_info;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_os_open_directory
+ *
+ * PARAMETERS:  dir_pathname        - Full pathname to the directory
+ *              wildcard_spec       - string of the form "*.c", etc.
+ *
+ * RETURN:      A directory "handle" to be used in subsequent search operations.
+ *              NULL returned on failure.
+ *
+ * DESCRIPTION: Open a directory in preparation for a wildcard search
+ *
+ ******************************************************************************/
+
+void *acpi_os_open_directory(char *dir_pathname,
+                            char *wildcard_spec, char requested_file_type)
+{
+       struct external_find_info *external_info;
+       DIR *dir;
+
+       /* Allocate the info struct that will be returned to the caller */
+
+       external_info = calloc(1, sizeof(struct external_find_info));
+       if (!external_info) {
+               return (NULL);
+       }
+
+       /* Get the directory stream */
+
+       dir = opendir(dir_pathname);
+       if (!dir) {
+               fprintf(stderr, "Cannot open directory - %s\n", dir_pathname);
+               free(external_info);
+               return (NULL);
+       }
+
+       /* Save the info in the return structure */
+
+       external_info->wildcard_spec = wildcard_spec;
+       external_info->requested_file_type = requested_file_type;
+       external_info->dir_pathname = dir_pathname;
+       external_info->dir_ptr = dir;
+       return (external_info);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_os_get_next_filename
+ *
+ * PARAMETERS:  dir_handle          - Created via acpi_os_open_directory
+ *
+ * RETURN:      Next filename matched. NULL if no more matches.
+ *
+ * DESCRIPTION: Get the next file in the directory that matches the wildcard
+ *              specification.
+ *
+ ******************************************************************************/
+
+char *acpi_os_get_next_filename(void *dir_handle)
+{
+       struct external_find_info *external_info = dir_handle;
+       struct dirent *dir_entry;
+       char *temp_str;
+       int str_len;
+       struct stat temp_stat;
+       int err;
+
+       while ((dir_entry = readdir(external_info->dir_ptr))) {
+               if (!fnmatch
+                   (external_info->wildcard_spec, dir_entry->d_name, 0)) {
+                       if (dir_entry->d_name[0] == '.') {
+                               continue;
+                       }
+
+                       str_len = strlen(dir_entry->d_name) +
+                           strlen(external_info->dir_pathname) + 2;
+
+                       temp_str = calloc(str_len, 1);
+                       if (!temp_str) {
+                               fprintf(stderr,
+                                       "Could not allocate buffer for temporary string\n");
+                               return (NULL);
+                       }
+
+                       strcpy(temp_str, external_info->dir_pathname);
+                       strcat(temp_str, "/");
+                       strcat(temp_str, dir_entry->d_name);
+
+                       err = stat(temp_str, &temp_stat);
+                       if (err == -1) {
+                               fprintf(stderr,
+                                       "Cannot stat file (should not happen) - %s\n",
+                                       temp_str);
+                               free(temp_str);
+                               return (NULL);
+                       }
+
+                       free(temp_str);
+
+                       if ((S_ISDIR(temp_stat.st_mode)
+                            && (external_info->requested_file_type ==
+                                REQUEST_DIR_ONLY))
+                           || ((!S_ISDIR(temp_stat.st_mode)
+                                && external_info->requested_file_type ==
+                                REQUEST_FILE_ONLY))) {
+
+                               /* copy to a temp buffer because dir_entry struct is on the stack */
+
+                               strcpy(external_info->temp_buffer,
+                                      dir_entry->d_name);
+                               return (external_info->temp_buffer);
+                       }
+               }
+       }
+
+       return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_os_close_directory
+ *
+ * PARAMETERS:  dir_handle          - Created via acpi_os_open_directory
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Close the open directory and cleanup.
+ *
+ ******************************************************************************/
+
+void acpi_os_close_directory(void *dir_handle)
+{
+       struct external_find_info *external_info = dir_handle;
+
+       /* Close the directory and free allocations */
+
+       closedir(external_info->dir_ptr);
+       free(dir_handle);
+}
diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c
new file mode 100644 (file)
index 0000000..99b47b6
--- /dev/null
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ * Module Name: osunixmap - Unix OSL for file mappings
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include "acpidump.h"
+#include <unistd.h>
+#include <sys/mman.h>
+#ifdef _free_BSD
+#include <sys/param.h>
+#endif
+
+#define _COMPONENT          ACPI_OS_SERVICES
+ACPI_MODULE_NAME("osunixmap")
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+#ifdef _free_BSD
+#define MMAP_FLAGS          MAP_SHARED
+#else
+#define MMAP_FLAGS          MAP_PRIVATE
+#endif
+#define SYSTEM_MEMORY       "/dev/mem"
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_os_get_page_size
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Page size of the platform.
+ *
+ * DESCRIPTION: Obtain page size of the platform.
+ *
+ ******************************************************************************/
+static acpi_size acpi_os_get_page_size(void)
+{
+
+#ifdef PAGE_SIZE
+       return PAGE_SIZE;
+#else
+       return sysconf(_SC_PAGESIZE);
+#endif
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os_map_memory
+ *
+ * PARAMETERS:  where               - Physical address of memory to be mapped
+ *              length              - How much memory to map
+ *
+ * RETURN:      Pointer to mapped memory. Null on error.
+ *
+ * DESCRIPTION: Map physical memory into local address space.
+ *
+ *****************************************************************************/
+
+void *acpi_os_map_memory(acpi_physical_address where, acpi_size length)
+{
+       u8 *mapped_memory;
+       acpi_physical_address offset;
+       acpi_size page_size;
+       int fd;
+
+       fd = open(SYSTEM_MEMORY, O_RDONLY | O_BINARY);
+       if (fd < 0) {
+               fprintf(stderr, "Cannot open %s\n", SYSTEM_MEMORY);
+               return (NULL);
+       }
+
+       /* Align the offset to use mmap */
+
+       page_size = acpi_os_get_page_size();
+       offset = where % page_size;
+
+       /* Map the table header to get the length of the full table */
+
+       mapped_memory = mmap(NULL, (length + offset), PROT_READ, MMAP_FLAGS,
+                            fd, (where - offset));
+       if (mapped_memory == MAP_FAILED) {
+               fprintf(stderr, "Cannot map %s\n", SYSTEM_MEMORY);
+               close(fd);
+               return (NULL);
+       }
+
+       close(fd);
+       return (ACPI_CAST8(mapped_memory + offset));
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os_unmap_memory
+ *
+ * PARAMETERS:  where               - Logical address of memory to be unmapped
+ *              length              - How much memory to unmap
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Delete a previously created mapping. Where and Length must
+ *              correspond to a previous mapping exactly.
+ *
+ *****************************************************************************/
+
+void acpi_os_unmap_memory(void *where, acpi_size length)
+{
+       acpi_physical_address offset;
+       acpi_size page_size;
+
+       page_size = acpi_os_get_page_size();
+       offset = (acpi_physical_address) where % page_size;
+       munmap((u8 *)where - offset, (length + offset));
+}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.c b/tools/power/acpi/tools/acpidump/acpidump.c
deleted file mode 100644 (file)
index a84553a..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * (c) Alexey Starikovskiy, Intel, 2005-2006.
- * All rights reserved.
- *
- * 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,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#ifdef DEFINE_ALTERNATE_TYPES
-/* hack to enable building old application with new headers -lenb */
-#define acpi_fadt_descriptor acpi_table_fadt
-#define acpi_rsdp_descriptor acpi_table_rsdp
-#define DSDT_SIG ACPI_SIG_DSDT
-#define FACS_SIG ACPI_SIG_FACS
-#define FADT_SIG ACPI_SIG_FADT
-#define xfirmware_ctrl Xfacs
-#define firmware_ctrl facs
-
-typedef int                            s32;
-typedef unsigned char                  u8;
-typedef unsigned short                 u16;
-typedef unsigned int                   u32;
-typedef unsigned long long             u64;
-typedef long long                      s64;
-#endif
-
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-
-#include <dirent.h>
-
-#include <acpi/acconfig.h>
-#include <acpi/platform/acenv.h>
-#include <acpi/actypes.h>
-#include <acpi/actbl.h>
-
-static inline u8 checksum(u8 * buffer, u32 length)
-{
-       u8 sum = 0, *i = buffer;
-       buffer += length;
-       for (; i < buffer; sum += *(i++));
-       return sum;
-}
-
-static unsigned long psz, addr, length;
-static int print, connect, skip;
-static u8 select_sig[4];
-
-static unsigned long read_efi_systab( void )
-{
-       char buffer[80];
-       unsigned long addr;
-       FILE *f = fopen("/sys/firmware/efi/systab", "r");
-       if (f) {
-               while (fgets(buffer, 80, f)) {
-                       if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1)
-                               return addr;
-               }
-               fclose(f);
-       }
-       return 0;
-}
-
-static u8 *acpi_map_memory(unsigned long where, unsigned length)
-{
-       unsigned long offset;
-       u8 *there;
-       int fd = open("/dev/mem", O_RDONLY);
-       if (fd < 0) {
-               fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n");
-               exit(1);
-       }
-       offset = where % psz;
-       there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE,
-                        fd, where - offset);
-       close(fd);
-       if (there == MAP_FAILED) return 0;
-       return (there + offset);
-}
-
-static void acpi_unmap_memory(u8 * there, unsigned length)
-{
-       unsigned long offset = (unsigned long)there % psz;
-       munmap(there - offset, length + offset);
-}
-
-static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
-{
-       unsigned size;
-       struct acpi_table_header *tbl = (struct acpi_table_header *)
-           acpi_map_memory(where, sizeof(struct acpi_table_header));
-       if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
-       size = tbl->length;
-       acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
-       return (struct acpi_table_header *)acpi_map_memory(where, size);
-}
-
-static void acpi_unmap_table(struct acpi_table_header *tbl)
-{
-       acpi_unmap_memory((u8 *)tbl, tbl->length);
-}
-
-static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length)
-{
-       struct acpi_rsdp_descriptor *rsdp;
-       u8 *i, *end = begin + length;
-       /* Search from given start address for the requested length */
-       for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) {
-               /* The signature and checksum must both be correct */
-               if (memcmp((char *)i, "RSD PTR ", 8)) continue;
-               rsdp = (struct acpi_rsdp_descriptor *)i;
-               /* Signature matches, check the appropriate checksum */
-               if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ?
-                             ACPI_RSDP_CHECKSUM_LENGTH :
-                             ACPI_RSDP_XCHECKSUM_LENGTH))
-                       /* Checksum valid, we have found a valid RSDP */
-                       return rsdp;
-       }
-       /* Searched entire block, no RSDP was found */
-       return 0;
-}
-
-/*
- * Output data
- */
-static void acpi_show_data(int fd, u8 * data, int size)
-{
-       char buffer[256];
-       int len;
-       int i, remain = size;
-       while (remain > 0) {
-               len = snprintf(buffer, 256, "  %04x:", size - remain);
-               for (i = 0; i < 16 && i < remain; i++) {
-                       len +=
-                           snprintf(&buffer[len], 256 - len, " %02x", data[i]);
-               }
-               for (; i < 16; i++) {
-                       len += snprintf(&buffer[len], 256 - len, "   ");
-               }
-               len += snprintf(&buffer[len], 256 - len, "  ");
-               for (i = 0; i < 16 && i < remain; i++) {
-                       buffer[len++] = (isprint(data[i])) ? data[i] : '.';
-               }
-               buffer[len++] = '\n';
-               write(fd, buffer, len);
-               data += 16;
-               remain -= 16;
-       }
-}
-
-/*
- * Output ACPI table
- */
-static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr)
-{
-       char buff[80];
-       int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr);
-       write(fd, buff, len);
-       acpi_show_data(fd, (u8 *) table, table->length);
-       buff[0] = '\n';
-       write(fd, buff, 1);
-}
-
-static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr)
-{
-       static int select_done = 0;
-       if (!select_sig[0]) {
-               if (print) {
-                       acpi_show_table(fd, tbl, addr);
-               } else {
-                       write(fd, tbl, tbl->length);
-               }
-       } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) {
-               if (skip > 0) {
-                       --skip;
-                       return;
-               }
-               if (print) {
-                       acpi_show_table(fd, tbl, addr);
-               } else {
-                       write(fd, tbl, tbl->length);
-               }
-               select_done = 1;
-       }
-}
-
-static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) {
-       struct acpi_fadt_descriptor x;
-       unsigned long addr;
-       size_t len = sizeof(struct acpi_fadt_descriptor);
-       if (len > tbl->length) len = tbl->length;
-       memcpy(&x, tbl, len);
-       x.header.length = len;
-       if (checksum((u8 *)tbl, len)) {
-               fprintf(stderr, "Wrong checksum for FADT!\n");
-       }
-       if (x.header.length >= 148 && x.Xdsdt) {
-               addr = (unsigned long)x.Xdsdt;
-               if (connect) {
-                       x.Xdsdt = lseek(fd, 0, SEEK_CUR);
-               }
-       } else if (x.header.length >= 44 && x.dsdt) {
-               addr = (unsigned long)x.dsdt;
-               if (connect) {
-                       x.dsdt = lseek(fd, 0, SEEK_CUR);
-               }
-       } else {
-               fprintf(stderr, "No DSDT in FADT!\n");
-               goto no_dsdt;
-       }
-       tbl = acpi_map_table(addr, DSDT_SIG);
-       if (!tbl) goto no_dsdt;
-       if (checksum((u8 *)tbl, tbl->length))
-               fprintf(stderr, "Wrong checksum for DSDT!\n");
-       write_table(fd, tbl, addr);
-       acpi_unmap_table(tbl);
-no_dsdt:
-       if (x.header.length >= 140 && x.xfirmware_ctrl) {
-               addr = (unsigned long)x.xfirmware_ctrl;
-               if (connect) {
-                       x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR);
-               }
-       } else if (x.header.length >= 40 && x.firmware_ctrl) {
-               addr = (unsigned long)x.firmware_ctrl;
-               if (connect) {
-                       x.firmware_ctrl = lseek(fd, 0, SEEK_CUR);
-               }
-       } else {
-               fprintf(stderr, "No FACS in FADT!\n");
-               goto no_facs;
-       }
-       tbl = acpi_map_table(addr, FACS_SIG);
-       if (!tbl) goto no_facs;
-       /* do not checksum FACS */
-       write_table(fd, tbl, addr);
-       acpi_unmap_table(tbl);
-no_facs:
-       write_table(fd, (struct acpi_table_header *)&x, xaddr);
-}
-
-static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp)
-{
-       struct acpi_table_header *sdt, *tbl = 0;
-       int xsdt = 1, i, num;
-       char *offset;
-       unsigned long addr;
-       if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
-               tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT");
-       }
-       if (!tbl && rsdp->rsdt_physical_address) {
-               xsdt = 0;
-               tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT");
-       }
-       if (!tbl) return 0;
-       sdt = malloc(tbl->length);
-       memcpy(sdt, tbl, tbl->length);
-       acpi_unmap_table(tbl);
-       if (checksum((u8 *)sdt, sdt->length))
-               fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT");
-       num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32));
-       offset = (char *)sdt + sizeof(struct acpi_table_header);
-       for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) {
-               addr = (xsdt) ? (unsigned long)(*(u64 *)offset):
-                               (unsigned long)(*(u32 *)offset);
-               if (!addr) continue;
-               tbl = acpi_map_table(addr, 0);
-               if (!tbl) continue;
-               if (!memcmp(tbl->signature, FADT_SIG, 4)) {
-                       acpi_dump_FADT(fd, tbl, addr);
-               } else {
-                       if (checksum((u8 *)tbl, tbl->length))
-                               fprintf(stderr, "Wrong checksum for generic table!\n");
-                       write_table(fd, tbl, addr);
-               }
-               acpi_unmap_table(tbl);
-               if (connect) {
-                       if (xsdt)
-                               (*(u64*)offset) = lseek(fd, 0, SEEK_CUR);
-                       else
-                               (*(u32*)offset) = lseek(fd, 0, SEEK_CUR);
-               }
-       }
-       if (xsdt) {
-               addr = (unsigned long)rsdp->xsdt_physical_address;
-               if (connect) {
-                       rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR);
-               }
-       } else {
-               addr = (unsigned long)rsdp->rsdt_physical_address;
-               if (connect) {
-                       rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR);
-               }
-       }
-       write_table(fd, sdt, addr);
-       free (sdt);
-       return 1;
-}
-
-#define DYNAMIC_SSDT   "/sys/firmware/acpi/tables/dynamic"
-
-static void acpi_dump_dynamic_SSDT(int fd)
-{
-       struct stat file_stat;
-       char filename[256], *ptr;
-       DIR *tabledir;
-       struct dirent *entry;
-       FILE *fp;
-       int count, readcount, length;
-       struct acpi_table_header table_header, *ptable;
-
-       if (stat(DYNAMIC_SSDT, &file_stat) == -1) {
-               /* The directory doesn't exist */
-               return;
-       }
-       tabledir = opendir(DYNAMIC_SSDT);
-       if(!tabledir){
-               /*can't open the directory */
-               return;
-         }
-
-       while ((entry = readdir(tabledir)) != 0){
-               /* skip the file of . /.. */
-               if (entry->d_name[0] == '.')
-                       continue;
-
-               sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name);
-               fp = fopen(filename, "r");
-               if (fp == NULL) {
-                       fprintf(stderr, "Can't open the file of %s\n",
-                                               filename);
-                       continue;
-               }
-               /* Read the Table header to parse the table length */
-               count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp);
-               if (count < sizeof(table_header)) {
-                       /* the length is lessn than ACPI table header. skip it */
-                       fclose(fp);
-                       continue;
-               }
-               length = table_header.length;
-               ptr = malloc(table_header.length);
-               fseek(fp, 0, SEEK_SET);
-               readcount = 0;
-               while(!feof(fp) && readcount < length) {
-                       count = fread(ptr + readcount, 1, 256, fp);
-                       readcount += count;
-               }
-               fclose(fp);
-               ptable = (struct acpi_table_header *) ptr;
-               if (checksum((u8 *) ptable, ptable->length))
-                       fprintf(stderr, "Wrong checksum "
-                                       "for dynamic SSDT table!\n");
-               write_table(fd, ptable, 0);
-               free(ptr);
-       }
-       closedir(tabledir);
-       return;
-}
-
-static void usage(const char *progname)
-{
-       puts("Usage:");
-       printf("%s [--addr 0x1234][--table DSDT][--output filename]"
-               "[--binary][--length 0x456][--help]\n", progname);
-       puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
-       puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
-       puts("\t--output filename or -o filename -- redirect output from stdin to filename");
-       puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
-       puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
-               "\n\t\tregion without trying to understand it's contents");
-       puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one");
-       puts("\t--help or -h -- this help message");
-       exit(0);
-}
-
-static struct option long_options[] = {
-       {"addr", 1, 0, 0},
-       {"table", 1, 0, 0},
-       {"output", 1, 0, 0},
-       {"binary", 0, 0, 0},
-       {"length", 1, 0, 0},
-       {"skip", 1, 0, 0},
-       {"help", 0, 0, 0},
-       {0, 0, 0, 0}
-};
-int main(int argc, char **argv)
-{
-       int option_index, c, fd;
-       u8 *raw;
-       struct acpi_rsdp_descriptor rsdpx, *x = 0;
-       char *filename = 0;
-       char buff[80];
-       memset(select_sig, 0, 4);
-       print = 1;
-       connect = 0;
-       addr = length = 0;
-       skip = 0;
-       while (1) {
-               option_index = 0;
-               c = getopt_long(argc, argv, "a:t:o:bl:s:h",
-                                   long_options, &option_index);
-               if (c == -1)
-                       break;
-
-               switch (c) {
-               case 0:
-                       switch (option_index) {
-                       case 0:
-                               addr = strtoul(optarg, (char **)NULL, 16);
-                               break;
-                       case 1:
-                               memcpy(select_sig, optarg, 4);
-                               break;
-                       case 2:
-                               filename = optarg;
-                               break;
-                       case 3:
-                               print = 0;
-                               break;
-                       case 4:
-                               length = strtoul(optarg, (char **)NULL, 16);
-                               break;
-                       case 5:
-                               skip = strtoul(optarg, (char **)NULL, 10);
-                               break;
-                       case 6:
-                               usage(argv[0]);
-                               exit(0);
-                       }
-                       break;
-               case 'a':
-                       addr = strtoul(optarg, (char **)NULL, 16);
-                       break;
-               case 't':
-                       memcpy(select_sig, optarg, 4);
-                       break;
-               case 'o':
-                       filename = optarg;
-                       break;
-               case 'b':
-                       print = 0;
-                       break;
-               case 'l':
-                       length = strtoul(optarg, (char **)NULL, 16);
-                       break;
-               case 's':
-                       skip = strtoul(optarg, (char **)NULL, 10);
-                       break;
-               case 'h':
-                       usage(argv[0]);
-                       exit(0);
-               default:
-                       printf("Unknown option!\n");
-                       usage(argv[0]);
-                       exit(0);
-               }
-       }
-
-       fd = STDOUT_FILENO;
-       if (filename) {
-               fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-               if (fd < 0)
-                       return fd;
-       }
-
-       if (!select_sig[0] && !print) {
-               connect = 1;
-       }
-
-       psz = sysconf(_SC_PAGESIZE);
-       if (length && addr) {
-               /* We know length and address, it means we just want a memory dump */
-               if (!(raw = acpi_map_memory(addr, length)))
-                       goto not_found;
-               write(fd, raw, length);
-               acpi_unmap_memory(raw, length);
-               close(fd);
-               return 0;
-       }
-
-       length = sizeof(struct acpi_rsdp_descriptor);
-       if (!addr) {
-               addr = read_efi_systab();
-               if (!addr) {
-                       addr = ACPI_HI_RSDP_WINDOW_BASE;
-                       length = ACPI_HI_RSDP_WINDOW_SIZE;
-               }
-       }
-
-       if (!(raw = acpi_map_memory(addr, length)) ||
-           !(x = acpi_scan_for_rsdp(raw, length)))
-               goto not_found;
-
-       /* Find RSDP and print all found tables */
-       memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
-       acpi_unmap_memory(raw, length);
-       if (connect) {
-               lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
-       }
-       if (!acpi_dump_SDT(fd, &rsdpx))
-               goto not_found;
-       if (connect) {
-               lseek(fd, 0, SEEK_SET);
-               write(fd, x, (rsdpx.revision < 2) ?
-                       ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
-       } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
-               addr += (long)x - (long)raw;
-               length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
-               write(fd, buff, length);
-               acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
-                               ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
-               buff[0] = '\n';
-               write(fd, buff, 1);
-       }
-       acpi_dump_dynamic_SSDT(fd);
-       close(fd);
-       return 0;
-not_found:
-       close(fd);
-       fprintf(stderr, "ACPI tables were not found. If you know location "
-               "of RSD PTR table (from dmesg, etc), "
-               "supply it with either --addr or -a option\n");
-       return 1;
-}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h
new file mode 100644 (file)
index 0000000..3361b9e
--- /dev/null
@@ -0,0 +1,131 @@
+/******************************************************************************
+ *
+ * Module Name: acpidump.h - Include file for acpi_dump utility
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "actables.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+/*
+ * Global variables. Defined in main.c only, externed in all other files
+ */
+#ifdef _DECLARE_GLOBALS
+#define EXTERN
+#define INIT_GLOBAL(a,b)        a=b
+#else
+#define EXTERN                  extern
+#define INIT_GLOBAL(a,b)        a
+#endif
+
+/* Globals */
+
+EXTERN u8 INIT_GLOBAL(gbl_summary_mode, FALSE);
+EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE);
+EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE);
+EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE);
+EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL);
+EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL);
+EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0);
+
+/* Globals required for use with ACPICA modules */
+
+#ifdef _DECLARE_GLOBALS
+u8 acpi_gbl_enable_interpreter_slack = FALSE;
+u8 acpi_gbl_integer_byte_width = 8;
+u32 acpi_dbg_level = 0;
+u32 acpi_dbg_layer = 0;
+#endif
+
+/* Action table used to defer requested options */
+
+struct ap_dump_action {
+       char *argument;
+       u32 to_be_done;
+};
+
+#define AP_MAX_ACTIONS              32
+
+#define AP_DUMP_ALL_TABLES          0
+#define AP_DUMP_TABLE_BY_ADDRESS    1
+#define AP_DUMP_TABLE_BY_NAME       2
+#define AP_DUMP_TABLE_BY_FILE       3
+
+#define AP_MAX_ACPI_FILES           256        /* Prevent infinite loops */
+
+/* Minimum FADT sizes for various table addresses */
+
+#define MIN_FADT_FOR_DSDT           (ACPI_FADT_OFFSET (dsdt) + sizeof (u32))
+#define MIN_FADT_FOR_FACS           (ACPI_FADT_OFFSET (facs) + sizeof (u32))
+#define MIN_FADT_FOR_XDSDT          (ACPI_FADT_OFFSET (Xdsdt) + sizeof (u64))
+#define MIN_FADT_FOR_XFACS          (ACPI_FADT_OFFSET (Xfacs) + sizeof (u64))
+
+/*
+ * apdump - Table get/dump routines
+ */
+int ap_dump_table_from_file(char *pathname);
+
+int ap_dump_table_by_name(char *signature);
+
+int ap_dump_table_by_address(char *ascii_address);
+
+int ap_dump_all_tables(void);
+
+u8 ap_is_valid_header(struct acpi_table_header *table);
+
+u8 ap_is_valid_checksum(struct acpi_table_header *table);
+
+u32 ap_get_table_length(struct acpi_table_header *table);
+
+/*
+ * apfiles - File I/O utilities
+ */
+int ap_open_output_file(char *pathname);
+
+int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance);
+
+struct acpi_table_header *ap_get_table_from_file(char *pathname,
+                                                u32 *file_size);
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c
new file mode 100644 (file)
index 0000000..3cac123
--- /dev/null
@@ -0,0 +1,451 @@
+/******************************************************************************
+ *
+ * Module Name: apdump - Dump routines for ACPI tables (acpidump)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include "acpidump.h"
+
+/* Local prototypes */
+
+static int
+ap_dump_table_buffer(struct acpi_table_header *table,
+                    u32 instance, acpi_physical_address address);
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_is_valid_header
+ *
+ * PARAMETERS:  table               - Pointer to table to be validated
+ *
+ * RETURN:      TRUE if the header appears to be valid. FALSE otherwise
+ *
+ * DESCRIPTION: Check for a valid ACPI table header
+ *
+ ******************************************************************************/
+
+u8 ap_is_valid_header(struct acpi_table_header *table)
+{
+
+       if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) {
+
+               /* Make sure signature is all ASCII and a valid ACPI name */
+
+               if (!acpi_ut_valid_acpi_name(table->signature)) {
+                       fprintf(stderr,
+                               "Table signature (0x%8.8X) is invalid\n",
+                               *(u32 *)table->signature);
+                       return (FALSE);
+               }
+
+               /* Check for minimum table length */
+
+               if (table->length < sizeof(struct acpi_table_header)) {
+                       fprintf(stderr, "Table length (0x%8.8X) is invalid\n",
+                               table->length);
+                       return (FALSE);
+               }
+       }
+
+       return (TRUE);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_is_valid_checksum
+ *
+ * PARAMETERS:  table               - Pointer to table to be validated
+ *
+ * RETURN:      TRUE if the checksum appears to be valid. FALSE otherwise.
+ *
+ * DESCRIPTION: Check for a valid ACPI table checksum.
+ *
+ ******************************************************************************/
+
+u8 ap_is_valid_checksum(struct acpi_table_header *table)
+{
+       acpi_status status;
+       struct acpi_table_rsdp *rsdp;
+
+       if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
+               /*
+                * Checksum for RSDP.
+                * Note: Other checksums are computed during the table dump.
+                */
+               rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
+               status = acpi_tb_validate_rsdp(rsdp);
+       } else {
+               status = acpi_tb_verify_checksum(table, table->length);
+       }
+
+       if (ACPI_FAILURE(status)) {
+               fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n",
+                       table->signature);
+       }
+
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_get_table_length
+ *
+ * PARAMETERS:  table               - Pointer to the table
+ *
+ * RETURN:      Table length
+ *
+ * DESCRIPTION: Obtain table length according to table signature.
+ *
+ ******************************************************************************/
+
+u32 ap_get_table_length(struct acpi_table_header *table)
+{
+       struct acpi_table_rsdp *rsdp;
+
+       /* Check if table is valid */
+
+       if (!ap_is_valid_header(table)) {
+               return (0);
+       }
+
+       if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
+               rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
+               return (rsdp->length);
+       }
+
+       /* Normal ACPI table */
+
+       return (table->length);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_dump_table_buffer
+ *
+ * PARAMETERS:  table               - ACPI table to be dumped
+ *              instance            - ACPI table instance no. to be dumped
+ *              address             - Physical address of the table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a
+ *              header that is compatible with the acpi_xtract utility.
+ *
+ ******************************************************************************/
+
+static int
+ap_dump_table_buffer(struct acpi_table_header *table,
+                    u32 instance, acpi_physical_address address)
+{
+       u32 table_length;
+
+       table_length = ap_get_table_length(table);
+
+       /* Print only the header if requested */
+
+       if (gbl_summary_mode) {
+               acpi_tb_print_table_header(address, table);
+               return (0);
+       }
+
+       /* Dump to binary file if requested */
+
+       if (gbl_binary_mode) {
+               return (ap_write_to_binary_file(table, instance));
+       }
+
+       /*
+        * Dump the table with header for use with acpixtract utility.
+        * Note: simplest to just always emit a 64-bit address. acpi_xtract
+        * utility can handle this.
+        */
+       printf("%4.4s @ 0x%8.8X%8.8X\n", table->signature,
+              ACPI_FORMAT_UINT64(address));
+
+       acpi_ut_dump_buffer(ACPI_CAST_PTR(u8, table), table_length,
+                           DB_BYTE_DISPLAY, 0);
+       printf("\n");
+       return (0);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_dump_all_tables
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the
+ *              tables that we can possibly get).
+ *
+ ******************************************************************************/
+
+int ap_dump_all_tables(void)
+{
+       struct acpi_table_header *table;
+       u32 instance = 0;
+       acpi_physical_address address;
+       acpi_status status;
+       int table_status;
+       u32 i;
+
+       /* Get and dump all available ACPI tables */
+
+       for (i = 0; i < AP_MAX_ACPI_FILES; i++) {
+               status =
+                   acpi_os_get_table_by_index(i, &table, &instance, &address);
+               if (ACPI_FAILURE(status)) {
+
+                       /* AE_LIMIT means that no more tables are available */
+
+                       if (status == AE_LIMIT) {
+                               return (0);
+                       } else if (i == 0) {
+                               fprintf(stderr,
+                                       "Could not get ACPI tables, %s\n",
+                                       acpi_format_exception(status));
+                               return (-1);
+                       } else {
+                               fprintf(stderr,
+                                       "Could not get ACPI table at index %u, %s\n",
+                                       i, acpi_format_exception(status));
+                               continue;
+                       }
+               }
+
+               table_status = ap_dump_table_buffer(table, instance, address);
+               free(table);
+
+               if (table_status) {
+                       break;
+               }
+       }
+
+       /* Something seriously bad happened if the loop terminates here */
+
+       return (-1);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_dump_table_by_address
+ *
+ * PARAMETERS:  ascii_address       - Address for requested ACPI table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get an ACPI table via a physical address and dump it.
+ *
+ ******************************************************************************/
+
+int ap_dump_table_by_address(char *ascii_address)
+{
+       acpi_physical_address address;
+       struct acpi_table_header *table;
+       acpi_status status;
+       int table_status;
+       u64 long_address;
+
+       /* Convert argument to an integer physical address */
+
+       status = acpi_ut_strtoul64(ascii_address, 0, &long_address);
+       if (ACPI_FAILURE(status)) {
+               fprintf(stderr, "%s: Could not convert to a physical address\n",
+                       ascii_address);
+               return (-1);
+       }
+
+       address = (acpi_physical_address) long_address;
+       status = acpi_os_get_table_by_address(address, &table);
+       if (ACPI_FAILURE(status)) {
+               fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
+                       ACPI_FORMAT_UINT64(address),
+                       acpi_format_exception(status));
+               return (-1);
+       }
+
+       table_status = ap_dump_table_buffer(table, 0, address);
+       free(table);
+       return (table_status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_dump_table_by_name
+ *
+ * PARAMETERS:  signature           - Requested ACPI table signature
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles
+ *              multiple tables with the same signature (SSDTs).
+ *
+ ******************************************************************************/
+
+int ap_dump_table_by_name(char *signature)
+{
+       char local_signature[ACPI_NAME_SIZE + 1];
+       u32 instance;
+       struct acpi_table_header *table;
+       acpi_physical_address address;
+       acpi_status status;
+       int table_status;
+
+       if (strlen(signature) != ACPI_NAME_SIZE) {
+               fprintf(stderr,
+                       "Invalid table signature [%s]: must be exactly 4 characters\n",
+                       signature);
+               return (-1);
+       }
+
+       /* Table signatures are expected to be uppercase */
+
+       strcpy(local_signature, signature);
+       acpi_ut_strupr(local_signature);
+
+       /* To be friendly, handle tables whose signatures do not match the name */
+
+       if (ACPI_COMPARE_NAME(local_signature, "FADT")) {
+               strcpy(local_signature, ACPI_SIG_FADT);
+       } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) {
+               strcpy(local_signature, ACPI_SIG_MADT);
+       }
+
+       /* Dump all instances of this signature (to handle multiple SSDTs) */
+
+       for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) {
+               status = acpi_os_get_table_by_name(local_signature, instance,
+                                                  &table, &address);
+               if (ACPI_FAILURE(status)) {
+
+                       /* AE_LIMIT means that no more tables are available */
+
+                       if (status == AE_LIMIT) {
+                               return (0);
+                       }
+
+                       fprintf(stderr,
+                               "Could not get ACPI table with signature [%s], %s\n",
+                               local_signature, acpi_format_exception(status));
+                       return (-1);
+               }
+
+               table_status = ap_dump_table_buffer(table, instance, address);
+               free(table);
+
+               if (table_status) {
+                       break;
+               }
+       }
+
+       /* Something seriously bad happened if the loop terminates here */
+
+       return (-1);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_dump_table_from_file
+ *
+ * PARAMETERS:  pathname            - File containing the binary ACPI table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Dump an ACPI table from a binary file
+ *
+ ******************************************************************************/
+
+int ap_dump_table_from_file(char *pathname)
+{
+       struct acpi_table_header *table;
+       u32 file_size = 0;
+       int table_status = -1;
+
+       /* Get the entire ACPI table from the file */
+
+       table = ap_get_table_from_file(pathname, &file_size);
+       if (!table) {
+               return (-1);
+       }
+
+       /* File must be at least as long as the table length */
+
+       if (table->length > file_size) {
+               fprintf(stderr,
+                       "Table length (0x%X) is too large for input file (0x%X) %s\n",
+                       table->length, file_size, pathname);
+               goto exit;
+       }
+
+       if (gbl_verbose_mode) {
+               fprintf(stderr,
+                       "Input file:  %s contains table [%4.4s], 0x%X (%u) bytes\n",
+                       pathname, table->signature, file_size, file_size);
+       }
+
+       table_status = ap_dump_table_buffer(table, 0, 0);
+
+exit:
+       free(table);
+       return (table_status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os* print functions
+ *
+ * DESCRIPTION: Used for linkage with ACPICA modules
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vfprintf(stdout, fmt, args);
+       va_end(args);
+}
+
+void acpi_os_vprintf(const char *fmt, va_list args)
+{
+       vfprintf(stdout, fmt, args);
+}
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
new file mode 100644 (file)
index 0000000..4488acc
--- /dev/null
@@ -0,0 +1,228 @@
+/******************************************************************************
+ *
+ * Module Name: apfiles - File-related functions for acpidump utility
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include "acpidump.h"
+#include "acapps.h"
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_open_output_file
+ *
+ * PARAMETERS:  pathname            - Output filename
+ *
+ * RETURN:      Open file handle
+ *
+ * DESCRIPTION: Open a text output file for acpidump. Checks if file already
+ *              exists.
+ *
+ ******************************************************************************/
+
+int ap_open_output_file(char *pathname)
+{
+       struct stat stat_info;
+       FILE *file;
+
+       /* If file exists, prompt for overwrite */
+
+       if (!stat(pathname, &stat_info)) {
+               fprintf(stderr,
+                       "Target path already exists, overwrite? [y|n] ");
+
+               if (getchar() != 'y') {
+                       return (-1);
+               }
+       }
+
+       /* Point stdout to the file */
+
+       file = freopen(pathname, "w", stdout);
+       if (!file) {
+               perror("Could not open output file");
+               return (-1);
+       }
+
+       /* Save the file and path */
+
+       gbl_output_file = file;
+       gbl_output_filename = pathname;
+       return (0);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_write_to_binary_file
+ *
+ * PARAMETERS:  table               - ACPI table to be written
+ *              instance            - ACPI table instance no. to be written
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Write an ACPI table to a binary file. Builds the output
+ *              filename from the table signature.
+ *
+ ******************************************************************************/
+
+int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
+{
+       char filename[ACPI_NAME_SIZE + 16];
+       char instance_str[16];
+       FILE *file;
+       size_t actual;
+       u32 table_length;
+
+       /* Obtain table length */
+
+       table_length = ap_get_table_length(table);
+
+       /* Construct lower-case filename from the table local signature */
+
+       if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
+               ACPI_MOVE_NAME(filename, ACPI_RSDP_NAME);
+       } else {
+               ACPI_MOVE_NAME(filename, table->signature);
+       }
+       filename[0] = (char)ACPI_TOLOWER(filename[0]);
+       filename[1] = (char)ACPI_TOLOWER(filename[1]);
+       filename[2] = (char)ACPI_TOLOWER(filename[2]);
+       filename[3] = (char)ACPI_TOLOWER(filename[3]);
+       filename[ACPI_NAME_SIZE] = 0;
+
+       /* Handle multiple SSDts - create different filenames for each */
+
+       if (instance > 0) {
+               sprintf(instance_str, "%u", instance);
+               strcat(filename, instance_str);
+       }
+
+       strcat(filename, ACPI_TABLE_FILE_SUFFIX);
+
+       if (gbl_verbose_mode) {
+               fprintf(stderr,
+                       "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
+                       table->signature, filename, table->length,
+                       table->length);
+       }
+
+       /* Open the file and dump the entire table in binary mode */
+
+       file = fopen(filename, "wb");
+       if (!file) {
+               perror("Could not open output file");
+               return (-1);
+       }
+
+       actual = fwrite(table, 1, table_length, file);
+       if (actual != table_length) {
+               perror("Error writing binary output file");
+               fclose(file);
+               return (-1);
+       }
+
+       fclose(file);
+       return (0);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_get_table_from_file
+ *
+ * PARAMETERS:  pathname            - File containing the binary ACPI table
+ *              out_file_size       - Where the file size is returned
+ *
+ * RETURN:      Buffer containing the ACPI table. NULL on error.
+ *
+ * DESCRIPTION: Open a file and read it entirely into a new buffer
+ *
+ ******************************************************************************/
+
+struct acpi_table_header *ap_get_table_from_file(char *pathname,
+                                                u32 *out_file_size)
+{
+       struct acpi_table_header *buffer = NULL;
+       FILE *file;
+       u32 file_size;
+       size_t actual;
+
+       /* Must use binary mode */
+
+       file = fopen(pathname, "rb");
+       if (!file) {
+               perror("Could not open input file");
+               return (NULL);
+       }
+
+       /* Need file size to allocate a buffer */
+
+       file_size = cm_get_file_size(file);
+       if (file_size == ACPI_UINT32_MAX) {
+               fprintf(stderr,
+                       "Could not get input file size: %s\n", pathname);
+               goto cleanup;
+       }
+
+       /* Allocate a buffer for the entire file */
+
+       buffer = calloc(1, file_size);
+       if (!buffer) {
+               fprintf(stderr,
+                       "Could not allocate file buffer of size: %u\n",
+                       file_size);
+               goto cleanup;
+       }
+
+       /* Read the entire file */
+
+       actual = fread(buffer, 1, file_size, file);
+       if (actual != file_size) {
+               fprintf(stderr, "Could not read input file: %s\n", pathname);
+               free(buffer);
+               buffer = NULL;
+               goto cleanup;
+       }
+
+       *out_file_size = file_size;
+
+cleanup:
+       fclose(file);
+       return (buffer);
+}
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c
new file mode 100644 (file)
index 0000000..70d71ec
--- /dev/null
@@ -0,0 +1,340 @@
+/******************************************************************************
+ *
+ * Module Name: apmain - Main module for the acpidump utility
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#define _DECLARE_GLOBALS
+#include "acpidump.h"
+#include "acapps.h"
+
+/*
+ * acpidump - A portable utility for obtaining system ACPI tables and dumping
+ * them in an ASCII hex format suitable for binary extraction via acpixtract.
+ *
+ * Obtaining the system ACPI tables is an OS-specific operation.
+ *
+ * This utility can be ported to any host operating system by providing a
+ * module containing system-specific versions of these interfaces:
+ *
+ *      acpi_os_get_table_by_address
+ *      acpi_os_get_table_by_index
+ *      acpi_os_get_table_by_name
+ *
+ * See the ACPICA Reference Guide for the exact definitions of these
+ * interfaces. Also, see these ACPICA source code modules for example
+ * implementations:
+ *
+ *      source/os_specific/service_layers/oswintbl.c
+ *      source/os_specific/service_layers/oslinuxtbl.c
+ */
+
+/* Local prototypes */
+
+static void ap_display_usage(void);
+
+static int ap_do_options(int argc, char **argv);
+
+static void ap_insert_action(char *argument, u32 to_be_done);
+
+/* Table for deferred actions from command line options */
+
+struct ap_dump_action action_table[AP_MAX_ACTIONS];
+u32 current_action = 0;
+
+#define AP_UTILITY_NAME             "ACPI Binary Table Dump Utility"
+#define AP_SUPPORTED_OPTIONS        "?a:bcf:hn:o:r:svz"
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_display_usage
+ *
+ * DESCRIPTION: Usage message for the acpi_dump utility
+ *
+ ******************************************************************************/
+
+static void ap_display_usage(void)
+{
+
+       ACPI_USAGE_HEADER("acpidump [options]");
+
+       ACPI_OPTION("-b", "Dump tables to binary files");
+       ACPI_OPTION("-c", "Dump customized tables");
+       ACPI_OPTION("-h -?", "This help message");
+       ACPI_OPTION("-o <File>", "Redirect output to file");
+       ACPI_OPTION("-r <Address>", "Dump tables from specified RSDP");
+       ACPI_OPTION("-s", "Print table summaries only");
+       ACPI_OPTION("-v", "Display version information");
+       ACPI_OPTION("-z", "Verbose mode");
+
+       printf("\nTable Options:\n");
+
+       ACPI_OPTION("-a <Address>", "Get table via a physical address");
+       ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file");
+       ACPI_OPTION("-n <Signature>", "Get table via a name/signature");
+
+       printf("\n"
+              "Invocation without parameters dumps all available tables\n"
+              "Multiple mixed instances of -a, -f, and -n are supported\n\n");
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_insert_action
+ *
+ * PARAMETERS:  argument            - Pointer to the argument for this action
+ *              to_be_done          - What to do to process this action
+ *
+ * RETURN:      None. Exits program if action table becomes full.
+ *
+ * DESCRIPTION: Add an action item to the action table
+ *
+ ******************************************************************************/
+
+static void ap_insert_action(char *argument, u32 to_be_done)
+{
+
+       /* Insert action and check for table overflow */
+
+       action_table[current_action].argument = argument;
+       action_table[current_action].to_be_done = to_be_done;
+
+       current_action++;
+       if (current_action > AP_MAX_ACTIONS) {
+               fprintf(stderr, "Too many table options (max %u)\n",
+                       AP_MAX_ACTIONS);
+               exit(-1);
+       }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_do_options
+ *
+ * PARAMETERS:  argc/argv           - Standard argc/argv
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Command line option processing. The main actions for getting
+ *              and dumping tables are deferred via the action table.
+ *
+ *****************************************************************************/
+
+static int ap_do_options(int argc, char **argv)
+{
+       int j;
+       acpi_status status;
+
+       /* Command line options */
+
+       while ((j = acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != EOF)
+               switch (j) {
+                       /*
+                        * Global options
+                        */
+               case 'b':       /* Dump all input tables to binary files */
+
+                       gbl_binary_mode = TRUE;
+                       continue;
+
+               case 'c':       /* Dump customized tables */
+
+                       gbl_dump_customized_tables = TRUE;
+                       continue;
+
+               case 'h':
+               case '?':
+
+                       ap_display_usage();
+                       exit(0);
+
+               case 'o':       /* Redirect output to a single file */
+
+                       if (ap_open_output_file(acpi_gbl_optarg)) {
+                               exit(-1);
+                       }
+                       continue;
+
+               case 'r':       /* Dump tables from specified RSDP */
+
+                       status =
+                           acpi_ut_strtoul64(acpi_gbl_optarg, 0,
+                                             &gbl_rsdp_base);
+                       if (ACPI_FAILURE(status)) {
+                               fprintf(stderr,
+                                       "%s: Could not convert to a physical address\n",
+                                       acpi_gbl_optarg);
+                               exit(-1);
+                       }
+                       continue;
+
+               case 's':       /* Print table summaries only */
+
+                       gbl_summary_mode = TRUE;
+                       continue;
+
+               case 'v':       /* Revision/version */
+
+                       printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
+                       exit(0);
+
+               case 'z':       /* Verbose mode */
+
+                       gbl_verbose_mode = TRUE;
+                       fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
+                       continue;
+
+                       /*
+                        * Table options
+                        */
+               case 'a':       /* Get table by physical address */
+
+                       ap_insert_action(acpi_gbl_optarg,
+                                        AP_DUMP_TABLE_BY_ADDRESS);
+                       break;
+
+               case 'f':       /* Get table from a file */
+
+                       ap_insert_action(acpi_gbl_optarg,
+                                        AP_DUMP_TABLE_BY_FILE);
+                       break;
+
+               case 'n':       /* Get table by input name (signature) */
+
+                       ap_insert_action(acpi_gbl_optarg,
+                                        AP_DUMP_TABLE_BY_NAME);
+                       break;
+
+               default:
+
+                       ap_display_usage();
+                       exit(-1);
+               }
+
+       /* If there are no actions, this means "get/dump all tables" */
+
+       if (current_action == 0) {
+               ap_insert_action(NULL, AP_DUMP_ALL_TABLES);
+       }
+
+       return (0);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    main
+ *
+ * PARAMETERS:  argc/argv           - Standard argc/argv
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: C main function for acpidump utility
+ *
+ ******************************************************************************/
+
+int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
+{
+       int status = 0;
+       struct ap_dump_action *action;
+       u32 file_size;
+       u32 i;
+
+       ACPI_DEBUG_INITIALIZE();        /* For debug version only */
+
+       /* Process command line options */
+
+       if (ap_do_options(argc, argv)) {
+               return (-1);
+       }
+
+       /* Get/dump ACPI table(s) as requested */
+
+       for (i = 0; i < current_action; i++) {
+               action = &action_table[i];
+               switch (action->to_be_done) {
+               case AP_DUMP_ALL_TABLES:
+
+                       status = ap_dump_all_tables();
+                       break;
+
+               case AP_DUMP_TABLE_BY_ADDRESS:
+
+                       status = ap_dump_table_by_address(action->argument);
+                       break;
+
+               case AP_DUMP_TABLE_BY_NAME:
+
+                       status = ap_dump_table_by_name(action->argument);
+                       break;
+
+               case AP_DUMP_TABLE_BY_FILE:
+
+                       status = ap_dump_table_from_file(action->argument);
+                       break;
+
+               default:
+
+                       fprintf(stderr,
+                               "Internal error, invalid action: 0x%X\n",
+                               action->to_be_done);
+                       return (-1);
+               }
+
+               if (status) {
+                       return (status);
+               }
+       }
+
+       if (gbl_output_file) {
+               if (gbl_verbose_mode) {
+
+                       /* Summary for the output file */
+
+                       file_size = cm_get_file_size(gbl_output_file);
+                       fprintf(stderr,
+                               "Output file %s contains 0x%X (%u) bytes\n\n",
+                               gbl_output_filename, file_size, file_size);
+               }
+
+               fclose(gbl_output_file);
+       }
+
+       return (status);
+}
diff --git a/tools/power/acpi/tools/ec/Makefile b/tools/power/acpi/tools/ec/Makefile
new file mode 100644 (file)
index 0000000..b7b0b92
--- /dev/null
@@ -0,0 +1,22 @@
+ec_access: ec_access.o
+       $(ECHO) "  LD      " $@
+       $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $< -o $@
+       $(QUIET) $(STRIPCMD) $@
+
+%.o: %.c
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) -c $(CFLAGS) -o $@ $<
+
+all: ec_access
+
+install:
+       $(INSTALL) -d $(DESTDIR)${sbindir}
+       $(INSTALL_PROGRAM) ec_access $(DESTDIR)${sbindir}
+
+uninstall:
+       - rm -f $(DESTDIR)${sbindir}/ec_access
+
+clean:
+       -rm -f $(OUTPUT)ec_access
+
+.PHONY: all install uninstall
diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c
new file mode 100644 (file)
index 0000000..6b8aaed
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * ec_access.c
+ *
+ * Copyright (C) 2010 SUSE Linux Products GmbH
+ * Author:
+ *      Thomas Renninger <trenn@suse.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#include <fcntl.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#define EC_SPACE_SIZE 256
+#define SYSFS_PATH "/sys/kernel/debug/ec/ec0/io"
+
+/* TBD/Enhancements:
+   - Provide param for accessing different ECs (not supported by kernel yet)
+*/
+
+static int read_mode = -1;
+static int sleep_time;
+static int write_byte_offset = -1;
+static int read_byte_offset = -1;
+static uint8_t write_value = -1;
+
+void usage(char progname[], int exit_status)
+{
+       printf("Usage:\n");
+       printf("1) %s -r [-s sleep]\n", basename(progname));
+       printf("2) %s -b byte_offset\n", basename(progname));
+       printf("3) %s -w byte_offset -v value\n\n", basename(progname));
+
+       puts("\t-r [-s sleep]      : Dump EC registers");
+       puts("\t                     If sleep is given, sleep x seconds,");
+       puts("\t                     re-read EC registers and show changes");
+       puts("\t-b offset          : Read value at byte_offset (in hex)");
+       puts("\t-w offset -v value : Write value at byte_offset");
+       puts("\t-h                 : Print this help\n\n");
+       puts("Offsets and values are in hexadecimal number sytem.");
+       puts("The offset and value must be between 0 and 0xff.");
+       exit(exit_status);
+}
+
+void parse_opts(int argc, char *argv[])
+{
+       int c;
+
+       while ((c = getopt(argc, argv, "rs:b:w:v:h")) != -1) {
+
+               switch (c) {
+               case 'r':
+                       if (read_mode != -1)
+                               usage(argv[0], EXIT_FAILURE);
+                       read_mode = 1;
+                       break;
+               case 's':
+                       if (read_mode != -1 && read_mode != 1)
+                               usage(argv[0], EXIT_FAILURE);
+
+                       sleep_time = atoi(optarg);
+                       if (sleep_time <= 0) {
+                               sleep_time = 0;
+                               usage(argv[0], EXIT_FAILURE);
+                               printf("Bad sleep time: %s\n", optarg);
+                       }
+                       break;
+               case 'b':
+                       if (read_mode != -1)
+                               usage(argv[0], EXIT_FAILURE);
+                       read_mode = 1;
+                       read_byte_offset = strtoul(optarg, NULL, 16);
+                       break;
+               case 'w':
+                       if (read_mode != -1)
+                               usage(argv[0], EXIT_FAILURE);
+                       read_mode = 0;
+                       write_byte_offset = strtoul(optarg, NULL, 16);
+                       break;
+               case 'v':
+                       write_value = strtoul(optarg, NULL, 16);
+                       break;
+               case 'h':
+                       usage(argv[0], EXIT_SUCCESS);
+               default:
+                       fprintf(stderr, "Unknown option!\n");
+                       usage(argv[0], EXIT_FAILURE);
+               }
+       }
+       if (read_mode == 0) {
+               if (write_byte_offset < 0 ||
+                   write_byte_offset >= EC_SPACE_SIZE) {
+                       fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
+                               "[0-0x%.2x]\n",
+                               write_byte_offset, EC_SPACE_SIZE - 1);
+                       usage(argv[0], EXIT_FAILURE);
+               }
+               if (write_value < 0 ||
+                   write_value >= 255) {
+                       fprintf(stderr, "Wrong byte offset 0x%.2x, valid:"
+                               "[0-0xff]\n", write_byte_offset);
+                       usage(argv[0], EXIT_FAILURE);
+               }
+       }
+       if (read_mode == 1 && read_byte_offset != -1) {
+               if (read_byte_offset < -1 ||
+                   read_byte_offset >= EC_SPACE_SIZE) {
+                       fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
+                               "[0-0x%.2x]\n",
+                               read_byte_offset, EC_SPACE_SIZE - 1);
+                       usage(argv[0], EXIT_FAILURE);
+               }
+       }
+       /* Add additional parameter checks here */
+}
+
+void dump_ec(int fd)
+{
+       char buf[EC_SPACE_SIZE];
+       char buf2[EC_SPACE_SIZE];
+       int byte_off, bytes_read;
+
+       bytes_read = read(fd, buf, EC_SPACE_SIZE);
+
+       if (bytes_read == -1)
+               err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
+
+       if (bytes_read != EC_SPACE_SIZE)
+               fprintf(stderr, "Could only read %d bytes\n", bytes_read);
+
+       printf("     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F");
+       for (byte_off = 0; byte_off < bytes_read; byte_off++) {
+               if ((byte_off % 16) == 0)
+                       printf("\n%.2X: ", byte_off);
+               printf(" %.2x ", (uint8_t)buf[byte_off]);
+       }
+       printf("\n");
+
+       if (!sleep_time)
+               return;
+
+       printf("\n");
+       lseek(fd, 0, SEEK_SET);
+       sleep(sleep_time);
+
+       bytes_read = read(fd, buf2, EC_SPACE_SIZE);
+
+       if (bytes_read == -1)
+               err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
+
+       if (bytes_read != EC_SPACE_SIZE)
+               fprintf(stderr, "Could only read %d bytes\n", bytes_read);
+
+       printf("     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F");
+       for (byte_off = 0; byte_off < bytes_read; byte_off++) {
+               if ((byte_off % 16) == 0)
+                       printf("\n%.2X: ", byte_off);
+
+               if (buf[byte_off] == buf2[byte_off])
+                       printf(" %.2x ", (uint8_t)buf2[byte_off]);
+               else
+                       printf("*%.2x ", (uint8_t)buf2[byte_off]);
+       }
+       printf("\n");
+}
+
+void read_ec_val(int fd, int byte_offset)
+{
+       uint8_t buf;
+       int error;
+
+       error = lseek(fd, byte_offset, SEEK_SET);
+       if (error != byte_offset)
+               err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
+
+       error = read(fd, &buf, 1);
+       if (error != 1)
+               err(EXIT_FAILURE, "Could not read byte 0x%.2x from %s\n",
+                   byte_offset, SYSFS_PATH);
+       printf("0x%.2x\n", buf);
+       return;
+}
+
+void write_ec_val(int fd, int byte_offset, uint8_t value)
+{
+       int error;
+
+       error = lseek(fd, byte_offset, SEEK_SET);
+       if (error != byte_offset)
+               err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
+
+       error = write(fd, &value, 1);
+       if (error != 1)
+               err(EXIT_FAILURE, "Cannot write value 0x%.2x to offset 0x%.2x",
+                   value, byte_offset);
+}
+
+int main(int argc, char *argv[])
+{
+       int file_mode = O_RDONLY;
+       int fd;
+
+       parse_opts(argc, argv);
+
+       if (read_mode == 0)
+               file_mode = O_WRONLY;
+       else if (read_mode == 1)
+               file_mode = O_RDONLY;
+       else
+               usage(argv[0], EXIT_FAILURE);
+
+       fd = open(SYSFS_PATH, file_mode);
+       if (fd == -1)
+               err(EXIT_FAILURE, "%s", SYSFS_PATH);
+
+       if (read_mode)
+               if (read_byte_offset == -1)
+                       dump_ec(fd);
+               else if (read_byte_offset < 0 ||
+                        read_byte_offset >= EC_SPACE_SIZE)
+                       usage(argv[0], EXIT_FAILURE);
+               else
+                       read_ec_val(fd, read_byte_offset);
+       else
+               write_ec_val(fd, write_byte_offset, write_value);
+       close(fd);
+
+       exit(EXIT_SUCCESS);
+}
index cbfec92af32766b2570cc9add2ce4c3290bcd75e..3651db7eda238a91de7c9c6a804516526563c0c4 100644 (file)
@@ -62,7 +62,7 @@ LIB_MAJ=                      0.0.0
 LIB_MIN=                       0
 
 PACKAGE =                      cpupower
-PACKAGE_BUGREPORT =            cpufreq@vger.kernel.org
+PACKAGE_BUGREPORT =            linux-pm@vger.kernel.org
 LANGUAGES =                    de fr it cs pt
 
 
index 0f10b81e3322694df614bf23a0b1824d415b34ce..5224ee5b392d07f06ea963c0a0910f66a6bff263 100644 (file)
@@ -18,7 +18,7 @@
  * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the
  *     TSC-based delay routine on the Linux kernel does not correctly
  *     handle the cpufreq transition. Please report this to
- *     cpufreq@vger.kernel.org
+ *     linux-pm@vger.kernel.org
  */
 
 #include <linux/kernel.h>
index ccd9c84c4e3f2a988a3770278dd8a0242d248fcf..d1dc37425510f73cd168dfc21d809267c7e56412 100644 (file)
 #define R20 r20
 #define R21 r21
 #define R22 r22
+#define R29 r29
+#define R30 r30
+#define R31 r31
 
 #define STACKFRAMESIZE 256
-#define STK_PARAM(i)   (48 + ((i)-3)*8)
 #define STK_REG(i)     (112 + ((i)-14)*8)
 
 #define _GLOBAL(A) FUNC_START(test_ ## A)
+#define _GLOBAL_TOC(A) _GLOBAL(A)
 
 #define PPC_MTOCRF(A, B)       mtocrf A, B
 
index 47b29834a6b61def09f6340013cc9b2927c03cd9..56ff9bebb577df935200aacfc1e8251ae0800bcc 100644 (file)
@@ -548,11 +548,10 @@ static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu,
        u32 val;
        u32 *reg;
 
-       offset >>= 1;
        reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
-                                 vcpu->vcpu_id, offset);
+                                 vcpu->vcpu_id, offset >> 1);
 
-       if (offset & 2)
+       if (offset & 4)
                val = *reg >> 16;
        else
                val = *reg & 0xffff;
@@ -561,13 +560,13 @@ static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu,
        vgic_reg_access(mmio, &val, offset,
                        ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
        if (mmio->is_write) {
-               if (offset < 4) {
+               if (offset < 8) {
                        *reg = ~0U; /* Force PPIs/SGIs to 1 */
                        return false;
                }
 
                val = vgic_cfg_compress(val);
-               if (offset & 2) {
+               if (offset & 4) {
                        *reg &= 0xffff;
                        *reg |= val << 16;
                } else {
@@ -916,6 +915,7 @@ static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg)
        case 0:
                if (!target_cpus)
                        return;
+               break;
 
        case 1:
                target_cpus = ((1 << nrcpus) - 1) & ~(1 << vcpu_id) & 0xff;
@@ -1667,10 +1667,11 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
        if (addr + size < addr)
                return -EINVAL;
 
+       *ioaddr = addr;
        ret = vgic_ioaddr_overlap(kvm);
        if (ret)
-               return ret;
-       *ioaddr = addr;
+               *ioaddr = VGIC_ADDR_UNDEF;
+
        return ret;
 }
 
index 8db43701016f30cebeb37ab7e4d581166606b86f..bf06577fea51c22ab944edb9560e56f01aae2f94 100644 (file)
@@ -395,7 +395,8 @@ static int assigned_device_enable_host_msix(struct kvm *kvm,
        if (dev->entries_nr == 0)
                return r;
 
-       r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
+       r = pci_enable_msix_exact(dev->dev,
+                                 dev->host_msix_entries, dev->entries_nr);
        if (r)
                return r;
 
index 10df100c4514e856d1ca5509f87f118e37726f57..06e6401d6ef45326edcbce4c8ff96e13286d2940 100644 (file)
@@ -101,7 +101,7 @@ static void async_pf_execute(struct work_struct *work)
        if (waitqueue_active(&vcpu->wq))
                wake_up_interruptible(&vcpu->wq);
 
-       mmdrop(mm);
+       mmput(mm);
        kvm_put_kvm(vcpu->kvm);
 }
 
@@ -118,7 +118,7 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
                flush_work(&work->work);
 #else
                if (cancel_work_sync(&work->work)) {
-                       mmdrop(work->mm);
+                       mmput(work->mm);
                        kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
                        kmem_cache_free(async_pf_cache, work);
                }
@@ -183,7 +183,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
        work->addr = hva;
        work->arch = *arch;
        work->mm = current->mm;
-       atomic_inc(&work->mm->mm_count);
+       atomic_inc(&work->mm->mm_users);
        kvm_get_kvm(work->vcpu->kvm);
 
        /* this can't really happen otherwise gfn_to_pfn_async
@@ -201,7 +201,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
        return 1;
 retry_sync:
        kvm_put_kvm(work->vcpu->kvm);
-       mmdrop(work->mm);
+       mmput(work->mm);
        kmem_cache_free(async_pf_cache, work);
        return 0;
 }